diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index abd6190902776ab41154eab057010ff082d94660..6138883c0aea252ee032b5ad6eaf435489dd57d6 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -35,5 +35,5 @@ jobs:
uses: softprops/action-gh-release@v0.1.14
with:
prerelease: ${{ contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }}
- files: app/build/outputs/apk/standard/release/*.apk
+ files: app/build/outputs/apk/ose/release/*.apk
fail_on_unmatched_files: true
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9f2435a4da4a1ca8c30508d0463a2c107f7cb234
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,24 @@
+image: "registry.gitlab.e.foundation/e/os/docker-android-apps-cicd:latest"
+
+stages:
+ - build
+
+before_script:
+ - git submodule sync
+ - git submodule update --init --recursive --force
+ - echo email.key $PEPPER >> local.properties
+ - export GRADLE_USER_HOME=$(pwd)/.gradle
+ - chmod +x ./gradlew
+
+cache:
+ key: ${CI_PROJECT_ID}
+ paths:
+ - .gradle/
+
+build:
+ stage: build
+ script:
+ - ./gradlew build -x test
+ artifacts:
+ paths:
+ - app/build/outputs/apk/ose/
diff --git a/.gitmodules b/.gitmodules
index 6a6b94f2b08376fabf4aa0847f656dafe62879e4..b23c031a137895f2bdabe62599aa62cc69e61547 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,9 +1,14 @@
[submodule "ical4android"]
path = ical4android
- url = https://github.com/bitfireAT/ical4android.git
+ url = https://gitlab.e.foundation/e/os/ical4android.git
+ branch = main
[submodule "vcard4android"]
path = vcard4android
url = https://github.com/bitfireAT/vcard4android.git
[submodule "cert4android"]
path = cert4android
url = https://github.com/bitfireAT/cert4android.git
+[submodule "dav4android"]
+ path = dav4android
+ url = https://gitlab.e.foundation/e/apps/dav4android.git
+ branch = main
diff --git a/AUTHORS b/AUTHORS
index 9c6461d513671d2b33dac50f9123b373191216c8..990d9f6a50eb5d399e06badc9e75fe85d4a306d2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,6 +6,16 @@
Ricki Hirner (bitfire.at)
Bernhard Stockmann (bitfire.at)
-
Sunik Kupfer (bitfire.at)
Patrick Lang (techbee.at)
+
+# This is the list of significant contributors to AccountManager.
+#
+# This does not necessarily list everyone who has contributed work.
+# To see the full list of contributors, see the revision history in
+# source control.
+
+© 2018-2019 - Author: Nihar Thakkar
+© 2018-2022 - Author: Vincent Bourgmayer (murena)
+© 2018-2022 - Author: Romain Hunault (murena)
+© 2021-2022 - Author: Fahim Salam Chowdhury (murena)
diff --git a/README.md b/README.md
index eb83a4164ca26e3eeeafa8b81b83c7f0419c4ffa..af2f68477b798c6a35d1ae1673c5c1f40aba8fec 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,7 @@
+![accountManager logo](app/src/main/res/mipmap-xxxhdpi/ic_launcher.png)
+Account Manager
-[![Website](https://img.shields.io/website?style=flat-square&up_color=%237cb342&url=https%3A%2F%2Fwww.davx5.com)](https://www.davx5.com/)
-[![Twitter](https://img.shields.io/twitter/follow/davx5app?color=%237cb342&label=%40davx5app&style=flat-square)](https://twitter.com/davx5app)
-[![F-Droid](https://img.shields.io/f-droid/v/at.bitfire.davdroid?style=flat-square)](https://f-droid.org/packages/at.bitfire.davdroid/)
-[![License](https://img.shields.io/github/license/bitfireAT/davx5-ose?style=flat-square)](https://github.com/bitfireAT/davx5-ose/blob/main/LICENSE)
-[![Development tests](https://github.com/bitfireAT/davx5-ose/actions/workflows/test-dev.yml/badge.svg)](https://github.com/bitfireAT/davx5-ose/actions/workflows/test-dev.yml)
-
-![DAVx⁵ logo](app/src/main/res/mipmap-xxxhdpi/ic_launcher.png)
-
-
-DAVx⁵
-========
+Account Manager is a fork of DAVx⁵.
Please see the [DAVx⁵ Web site](https://www.davx5.com) for
comprehensive information about DAVx⁵.
diff --git a/app/build.gradle b/app/build.gradle
index b0970d16e7936993d3ad9a76f256b5a1d5f25995..93cd7f8931a42df802b481ee8b7a1d6a687bfbb8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -6,25 +6,31 @@ apply plugin: 'com.android.application'
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 32
buildToolsVersion '32.0.0'
+ aaptOptions {
+ additionalParameters '-I', 'e-ui-sdk.jar'
+ }
+
defaultConfig {
- applicationId "at.bitfire.davdroid"
+ applicationId "foundation.e.accountmanager"
- versionCode 402020000
- versionName '4.2.2'
+ versionCode 402030300
+ versionName '4.2.3.3'
buildConfigField "long", "buildTime", System.currentTimeMillis() + "L"
setProperty "archivesBaseName", "davx5-ose-" + getVersionName()
- minSdkVersion 21 // Android 5
+ minSdkVersion 24 // Android 7.1
targetSdkVersion 32 // Android 12v2
buildConfigField "String", "userAgent", "\"DAVx5\""
+ buildConfigField "String", "EMAIL_KEY", "\"${emailKey()}\""
testInstrumentationRunner "at.bitfire.davdroid.CustomTestRunner"
@@ -53,7 +59,7 @@ android {
flavorDimensions "distribution"
productFlavors {
- standard {
+ ose {
versionNameSuffix "-ose"
}
}
@@ -79,8 +85,6 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules-release.pro'
shrinkResources true
-
- signingConfig signingConfigs.bitfire
}
}
@@ -93,12 +97,21 @@ android {
excludes += ['META-INF/*.md']
}
}
+
+ defaultConfig {
+ manifestPlaceholders = [
+ 'appAuthRedirectScheme': 'net.openid.appauthdemo'
+ ]
+ }
}
dependencies {
+ compileOnly files("../e-ui-sdk.jar")
+
implementation project(':cert4android')
implementation project(':ical4android')
implementation project(':vcard4android')
+ implementation project(':dav4android')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1"
@@ -107,12 +120,12 @@ dependencies {
implementation "com.google.dagger:hilt-android:${versions.hilt}"
kapt "com.google.dagger:hilt-android-compiler:${versions.hilt}"
- implementation 'androidx.appcompat:appcompat:1.4.2'
+ implementation 'androidx.appcompat:appcompat:1.5.0'
implementation 'androidx.browser:browser:1.4.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.core:core-ktx:1.8.0'
- implementation 'androidx.fragment:fragment-ktx:1.5.1'
+ implementation 'androidx.fragment:fragment-ktx:1.5.2'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'androidx.paging:paging-runtime-ktx:3.1.1'
@@ -120,6 +133,7 @@ dependencies {
implementation 'androidx.security:security-crypto:1.1.0-alpha03'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'com.google.android.flexbox:flexbox:3.0.0'
+ implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'com.google.android.material:material:1.6.1'
def room_version = '2.4.3'
@@ -131,14 +145,11 @@ dependencies {
implementation 'com.jaredrummler:colorpicker:1.1.0'
implementation "com.github.AppIntro:AppIntro:${versions.appIntro}"
- implementation("com.github.bitfireAT:dav4jvm:${versions.dav4jvm}") {
- exclude group: 'junit'
- }
implementation "com.mikepenz:aboutlibraries:${versions.aboutLibraries}"
implementation "com.squareup.okhttp3:okhttp:${versions.okhttp}"
implementation "com.squareup.okhttp3:okhttp-brotli:${versions.okhttp}"
implementation "com.squareup.okhttp3:logging-interceptor:${versions.okhttp}"
- implementation 'commons-io:commons-io:2.11.0'
+ implementation 'commons-io:commons-io:2.8.0' // don't update until API level 26 (Android 8) is the minimum API (DAVx5#130)
//noinspection GradleDependency - dnsjava 3+ needs Java 8/Android 7
implementation 'dnsjava:dnsjava:2.1.9'
//noinspection GradleDependency
@@ -147,6 +158,8 @@ dependencies {
implementation "org.apache.commons:commons-lang3:${versions.commonsLang}"
//noinspection GradleDependency
implementation "org.apache.commons:commons-text:${versions.commonsText}"
+ implementation 'net.openid:appauth:0.11.1'
+ implementation 'junit:junit:4.13.2'
// for tests
androidTestImplementation "com.google.dagger:hilt-android-testing:${versions.hilt}"
@@ -158,8 +171,16 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.3'
androidTestImplementation "com.squareup.okhttp3:mockwebserver:${versions.okhttp}"
androidTestImplementation 'io.mockk:mockk-android:1.12.3'
- androidTestImplementation 'junit:junit:4.13.2'
testImplementation "com.squareup.okhttp3:mockwebserver:${versions.okhttp}"
- testImplementation 'junit:junit:4.13.2'
+}
+
+def emailKey() {
+ Properties properties = new Properties()
+ try {
+ properties.load(project.rootProject.file('local.properties').newDataInputStream())
+ } catch (ignored) {
+ // Ignore
+ }
+ return properties.getProperty("email.key", "invalid")
}
diff --git a/app/schemas/at.bitfire.davdroid.db.AppDatabase/11.json b/app/schemas/at.bitfire.davdroid.db.AppDatabase/11.json
index 77f44ee87b79fc3e6b5a9c7baf54f05e14c6e6db..d34f2da1c44141fc6c46af81359ddb541835bf42 100644
--- a/app/schemas/at.bitfire.davdroid.db.AppDatabase/11.json
+++ b/app/schemas/at.bitfire.davdroid.db.AppDatabase/11.json
@@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 11,
- "identityHash": "223aa7f0fd53730921ca212a663585d8",
+ "identityHash": "f9b5aba8e529d0a97714784626add644",
"entities": [
{
"tableName": "service",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `accountName` TEXT NOT NULL, `type` TEXT NOT NULL, `principal` TEXT)",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `accountName` TEXT NOT NULL, `authState` TEXT, `accountType` TEXT, `addressBookAccountType` TEXT, `type` TEXT NOT NULL, `principal` TEXT)",
"fields": [
{
"fieldPath": "id",
@@ -20,6 +20,24 @@
"affinity": "TEXT",
"notNull": true
},
+ {
+ "fieldPath": "authState",
+ "columnName": "authState",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "accountType",
+ "columnName": "accountType",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "addressBookAccountType",
+ "columnName": "addressBookAccountType",
+ "affinity": "TEXT",
+ "notNull": false
+ },
{
"fieldPath": "type",
"columnName": "type",
@@ -47,6 +65,7 @@
"accountName",
"type"
],
+ "orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_service_accountName_type` ON `${TABLE_NAME}` (`accountName`, `type`)"
}
],
@@ -107,6 +126,7 @@
"serviceId",
"url"
],
+ "orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_homeset_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
@@ -251,6 +271,7 @@
"serviceId",
"type"
],
+ "orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_collection_serviceId_type` ON `${TABLE_NAME}` (`serviceId`, `type`)"
},
{
@@ -260,6 +281,7 @@
"homeSetId",
"type"
],
+ "orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_collection_homeSetId_type` ON `${TABLE_NAME}` (`homeSetId`, `type`)"
},
{
@@ -268,6 +290,7 @@
"columnNames": [
"url"
],
+ "orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_collection_url` ON `${TABLE_NAME}` (`url`)"
}
],
@@ -339,6 +362,7 @@
"collectionId",
"authority"
],
+ "orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_syncstats_collectionId_authority` ON `${TABLE_NAME}` (`collectionId`, `authority`)"
}
],
@@ -466,6 +490,7 @@
"parentId",
"name"
],
+ "orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_webdav_document_mountId_parentId_name` ON `${TABLE_NAME}` (`mountId`, `parentId`, `name`)"
}
],
@@ -530,7 +555,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
- "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '223aa7f0fd53730921ca212a663585d8')"
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f9b5aba8e529d0a97714784626add644')"
]
}
}
\ No newline at end of file
diff --git a/app/src/androidTest/java/at/bitfire/davdroid/InitCalendarProviderRule.kt b/app/src/androidTest/java/at/bitfire/davdroid/InitCalendarProviderRule.kt
index bcbe1e1b41fc6de9fd497b2078d21deee0353c7f..89bdc46fee3a7ebd3bf7bf3d24e02853abcdfd1a 100644
--- a/app/src/androidTest/java/at/bitfire/davdroid/InitCalendarProviderRule.kt
+++ b/app/src/androidTest/java/at/bitfire/davdroid/InitCalendarProviderRule.kt
@@ -4,11 +4,15 @@
package at.bitfire.davdroid
+import android.Manifest
import android.accounts.Account
import android.content.ContentUris
import android.content.ContentValues
+import android.os.Build
import android.provider.CalendarContract
+import androidx.annotation.RequiresApi
import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.rule.GrantPermissionRule
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalCalendar
import at.bitfire.davdroid.resource.LocalEvent
@@ -16,60 +20,77 @@ import at.bitfire.ical4android.AndroidCalendar
import at.bitfire.ical4android.Event
import net.fortuna.ical4j.model.property.DtStart
import net.fortuna.ical4j.model.property.RRule
+import org.junit.rules.RuleChain
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
/**
- * JUnit ClassRule which initializes the AOSP CalendarProvider
- * Needed for some "flaky" tests which would otherwise only succeed on second run
+ * JUnit ClassRule which initializes the AOSP CalendarProvider.
+ * Needed for some "flaky" tests which would otherwise only succeed on second run.
+ *
+ * Currently tested on development machine (Ryzen) with Android 12 images (with/without Google Play).
+ * Calendar provider behaves quite randomly, so it may or may not work. If you (the reader
+ * if this comment) can find out on how to initialize the calendar provider so that the
+ * tests are reliably run after `adb shell pm clear com.android.providers.calendar`,
+ * please let us know!
+ *
+ * If you run tests manually, just make sure to ignore the first run after the calendar
+ * provider has been accessed the first time.
*/
-class InitCalendarProviderRule : TestRule {
+class InitCalendarProviderRule private constructor(): TestRule {
companion object {
- private val account = Account("LocalCalendarTest", CalendarContract.ACCOUNT_TYPE_LOCAL)
- private val context = InstrumentationRegistry.getInstrumentation().targetContext
- private val provider = context.contentResolver.acquireContentProviderClient(CalendarContract.AUTHORITY)!!
- private val uri = AndroidCalendar.create(account, provider, ContentValues())
- private val calendar = AndroidCalendar.findByID(account, provider, LocalCalendar.Factory, ContentUris.parseId(uri))
+ fun getInstance() = RuleChain
+ .outerRule(GrantPermissionRule.grant(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR))
+ .around(InitCalendarProviderRule())
}
override fun apply(base: Statement, description: Description): Statement {
- Logger.log.info("Before test: ${description.displayName}")
+ Logger.log.info("Initializing calendar provider before running ${description.displayName}")
+ return InitCalendarProviderStatement(base)
+ }
- Logger.log.info("Initializing CalendarProvider (InitCalendarProviderRule)")
- // single event init
- val normalEvent = Event().apply {
- dtStart = DtStart("20220120T010203Z")
- summary = "Event with 1 instance"
- }
- val normalLocalEvent = LocalEvent(calendar, normalEvent, null, null, null, 0)
- normalLocalEvent.add()
- LocalEvent.numInstances(provider, account, normalLocalEvent.id!!)
+ class InitCalendarProviderStatement(val base: Statement): Statement() {
+
+ override fun evaluate() {
+ if (Build.VERSION.SDK_INT < 31)
+ Logger.log.warning("Calendar provider initialization may or may not work. See InitCalendarProviderRule")
+ initCalendarProvider()
- // recurring event init
- val recurringEvent = Event().apply {
- dtStart = DtStart("20220120T010203Z")
- summary = "Event over 22 years"
- rRules.add(RRule("FREQ=YEARLY;UNTIL=20740119T010203Z")) // year needs to be >2074 (not supported by Android <11 Calendar Storage)
+ base.evaluate()
}
- val localRecurringEvent = LocalEvent(calendar, recurringEvent, null, null, null, 0)
- localRecurringEvent.add()
- LocalEvent.numInstances(provider, account, localRecurringEvent.id!!)
- // Run test
- Logger.log.info("Evaluating test..")
- return try {
- object : Statement() {
- @Throws(Throwable::class)
- override fun evaluate() {
- base.evaluate()
+ private fun initCalendarProvider() {
+ val account = Account("LocalCalendarTest", CalendarContract.ACCOUNT_TYPE_LOCAL)
+ val context = InstrumentationRegistry.getInstrumentation().targetContext
+ val provider = context.contentResolver.acquireContentProviderClient(CalendarContract.AUTHORITY)!!
+ val uri = AndroidCalendar.create(account, provider, ContentValues())
+ val calendar = AndroidCalendar.findByID(account, provider, LocalCalendar.Factory, ContentUris.parseId(uri))
+ try {
+ // single event init
+ val normalEvent = Event().apply {
+ dtStart = DtStart("20220120T010203Z")
+ summary = "Event with 1 instance"
}
+ val normalLocalEvent = LocalEvent(calendar, normalEvent, null, null, null, 0)
+ normalLocalEvent.add()
+ LocalEvent.numInstances(provider, account, normalLocalEvent.id!!)
+
+ // recurring event init
+ val recurringEvent = Event().apply {
+ dtStart = DtStart("20220120T010203Z")
+ summary = "Event over 22 years"
+ rRules.add(RRule("FREQ=YEARLY;UNTIL=20740119T010203Z")) // year needs to be >2074 (not supported by Android <11 Calendar Storage)
+ }
+ val localRecurringEvent = LocalEvent(calendar, recurringEvent, null, null, null, 0)
+ localRecurringEvent.add()
+ LocalEvent.numInstances(provider, account, localRecurringEvent.id!!)
+ } finally {
+ calendar.delete()
}
- } finally {
- Logger.log.info("After test: $description")
- calendar.delete()
}
}
-}
+
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/at/bitfire/davdroid/resource/LocalCalendarTest.kt b/app/src/androidTest/java/at/bitfire/davdroid/resource/LocalCalendarTest.kt
index a92cc256e9a3a69b974671499f3f5d0fe8ca7cb4..945a180da17f8ce4521420cc8c887d276f73a9c3 100644
--- a/app/src/androidTest/java/at/bitfire/davdroid/resource/LocalCalendarTest.kt
+++ b/app/src/androidTest/java/at/bitfire/davdroid/resource/LocalCalendarTest.kt
@@ -31,12 +31,8 @@ class LocalCalendarTest {
companion object {
@JvmField
- @ClassRule(order = 0)
- val permissionRule = GrantPermissionRule.grant(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR)!!
-
- @JvmField
- @ClassRule(order = 1)
- val initCalendarProviderRule: TestRule = InitCalendarProviderRule()
+ @ClassRule
+ val initCalendarProviderRule: TestRule = InitCalendarProviderRule.getInstance()
private lateinit var provider: ContentProviderClient
diff --git a/app/src/androidTest/java/at/bitfire/davdroid/resource/LocalEventTest.kt b/app/src/androidTest/java/at/bitfire/davdroid/resource/LocalEventTest.kt
index e3e43bf44a2adfd47901e01d5d85106389833c0e..b76349ee06869539527b3b87b030af48c810ed55 100644
--- a/app/src/androidTest/java/at/bitfire/davdroid/resource/LocalEventTest.kt
+++ b/app/src/androidTest/java/at/bitfire/davdroid/resource/LocalEventTest.kt
@@ -6,7 +6,9 @@ package at.bitfire.davdroid.resource
import android.Manifest
import android.accounts.Account
-import android.content.*
+import android.content.ContentProviderClient
+import android.content.ContentUris
+import android.content.ContentValues
import android.os.Build
import android.provider.CalendarContract
import android.provider.CalendarContract.ACCOUNT_TYPE_LOCAL
@@ -25,17 +27,15 @@ import net.fortuna.ical4j.model.property.*
import org.junit.*
import org.junit.Assert.*
import org.junit.rules.TestRule
+import java.util.*
class LocalEventTest {
companion object {
- @JvmField
- @ClassRule(order = 0)
- val permissionRule = GrantPermissionRule.grant(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR)!!
@JvmField
- @ClassRule(order = 1)
- val initCalendarProviderRule: TestRule = InitCalendarProviderRule()
+ @ClassRule
+ val initCalendarProviderRule: TestRule = InitCalendarProviderRule.getInstance()
private val account = Account("LocalCalendarTest", ACCOUNT_TYPE_LOCAL)
@@ -107,7 +107,7 @@ class LocalEventTest {
}
@Test
- // Flaky, Needs rec event init of CalendarProvider
+ // flaky, needs InitCalendarProviderRule
fun testNumDirectInstances_Recurring_LateEnd() {
val event = Event().apply {
dtStart = DtStart("20220120T010203Z")
@@ -124,7 +124,7 @@ class LocalEventTest {
}
@Test
- // Flaky, Needs rec event init of CalendarProvider
+ // flaky, needs InitCalendarProviderRule
fun testNumDirectInstances_Recurring_ManyInstances() {
val event = Event().apply {
dtStart = DtStart("20220120T010203Z")
@@ -141,7 +141,7 @@ class LocalEventTest {
}
@Test
- // Flaky, Needs single event init of CalendarProvider
+ // flaky, needs InitCalendarProviderRule
fun testNumDirectInstances_RecurringWithExdate() {
val event = Event().apply {
dtStart = DtStart(Date("20220120T010203Z"))
@@ -180,7 +180,7 @@ class LocalEventTest {
@Test
- // Flaky, Needs single or rec event init of CalendarProvider
+ // flaky, needs InitCalendarProviderRule
fun testNumInstances_SingleInstance() {
val event = Event().apply {
dtStart = DtStart("20220120T010203Z")
@@ -219,7 +219,7 @@ class LocalEventTest {
}
@Test
- // Flaky, Needs rec event init of CalendarProvider
+ // flaky, needs InitCalendarProviderRule
fun testNumInstances_Recurring_LateEnd() {
val event = Event().apply {
dtStart = DtStart("20220120T010203Z")
@@ -236,7 +236,7 @@ class LocalEventTest {
}
@Test
- // Flaky, Needs rec event init of CalendarProvider
+ // flaky, needs InitCalendarProviderRule
fun testNumInstances_Recurring_ManyInstances() {
val event = Event().apply {
dtStart = DtStart("20220120T010203Z")
@@ -306,6 +306,89 @@ class LocalEventTest {
}
+ @Test
+ fun testPrepareForUpload_NoUid() {
+ // create event
+ val event = Event().apply {
+ dtStart = DtStart("20220120T010203Z")
+ summary = "Event without uid"
+ }
+ val localEvent = LocalEvent(calendar, event, null, null, null, 0)
+ localEvent.add() // save it to calendar storage
+
+ // prepare for upload - this should generate a new random uuid, returned as filename
+ val fileNameWithSuffix = localEvent.prepareForUpload()
+ val fileName = fileNameWithSuffix.removeSuffix(".ics")
+
+ // throws an exception if fileName is not an UUID
+ UUID.fromString(fileName)
+
+ // UID in calendar storage should be the same as file name
+ provider.query(
+ ContentUris.withAppendedId(Events.CONTENT_URI, localEvent.id!!).asSyncAdapter(account),
+ arrayOf(Events.UID_2445), null, null, null
+ )!!.use { cursor ->
+ cursor.moveToFirst()
+ assertEquals(fileName, cursor.getString(0))
+ }
+ }
+
+ @Test
+ fun testPrepareForUpload_NormalUid() {
+ // create event
+ val event = Event().apply {
+ dtStart = DtStart("20220120T010203Z")
+ summary = "Event with normal uid"
+ uid = "some-event@hostname.tld" // old UID format, UUID would be new format
+ }
+ val localEvent = LocalEvent(calendar, event, null, null, null, 0)
+ localEvent.add() // save it to calendar storage
+
+ // prepare for upload - this should use the UID for the file name
+ val fileNameWithSuffix = localEvent.prepareForUpload()
+ val fileName = fileNameWithSuffix.removeSuffix(".ics")
+
+ assertEquals(event.uid, fileName)
+
+ // UID in calendar storage should still be set, too
+ provider.query(
+ ContentUris.withAppendedId(Events.CONTENT_URI, localEvent.id!!).asSyncAdapter(account),
+ arrayOf(Events.UID_2445), null, null, null
+ )!!.use { cursor ->
+ cursor.moveToFirst()
+ assertEquals(fileName, cursor.getString(0))
+ }
+ }
+
+ @Test
+ fun testPrepareForUpload_UidHasDangerousChars() {
+ // create event
+ val event = Event().apply {
+ dtStart = DtStart("20220120T010203Z")
+ summary = "Event with funny uid"
+ uid = "https://www.example.com/events/asdfewfe-cxyb-ewrws-sadfrwerxyvser-asdfxye-"
+ }
+ val localEvent = LocalEvent(calendar, event, null, null, null, 0)
+ localEvent.add() // save it to calendar storage
+
+ // prepare for upload - this should generate a new random uuid, returned as filename
+ val fileNameWithSuffix = localEvent.prepareForUpload()
+ val fileName = fileNameWithSuffix.removeSuffix(".ics")
+
+ // throws an exception if fileName is not an UUID
+ UUID.fromString(fileName)
+
+ // UID in calendar storage shouldn't have been changed
+ provider.query(
+ ContentUris.withAppendedId(Events.CONTENT_URI, localEvent.id!!).asSyncAdapter(account),
+ arrayOf(Events.UID_2445), null, null, null
+ )!!.use { cursor ->
+ cursor.moveToFirst()
+ assertEquals(event.uid, cursor.getString(0))
+ }
+ }
+
+
@Test
fun testDeleteDirtyEventsWithoutInstances_NoInstances_Exdate() {
// TODO
@@ -360,7 +443,6 @@ class LocalEventTest {
}
@Test
- // Flaky, Needs single event init OR rec event init of CalendarProvider
fun testDeleteDirtyEventsWithoutInstances_Recurring_Instances() {
val event = Event().apply {
dtStart = DtStart("20220120T010203Z")
diff --git a/app/src/androidTest/java/at/bitfire/davdroid/settings/AccountSettingsTest.kt b/app/src/androidTest/java/at/bitfire/davdroid/settings/AccountSettingsTest.kt
index 612f3899a26df368d32e1e3c91bb911cc29f5dcd..f2060cad3b55ca9cbf02e5b5af18fa62579b2a16 100644
--- a/app/src/androidTest/java/at/bitfire/davdroid/settings/AccountSettingsTest.kt
+++ b/app/src/androidTest/java/at/bitfire/davdroid/settings/AccountSettingsTest.kt
@@ -43,7 +43,7 @@ class AccountSettingsTest {
fun setUp() {
hiltRule.inject()
- assertTrue(AccountUtils.createAccount(context, account, AccountSettings.initialUserData(fakeCredentials)))
+ assertTrue(AccountUtils.createAccount(context, account, AccountSettings.initialUserData(fakeCredentials, null)))
ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 1)
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0)
}
diff --git a/app/src/androidTest/res/drawable-hdpi/ic_launcher.png b/app/src/androidTest/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index 96a442e5b8e9394ccf50bab9988cb2316026245d..0000000000000000000000000000000000000000
Binary files a/app/src/androidTest/res/drawable-hdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/androidTest/res/drawable-ldpi/ic_launcher.png b/app/src/androidTest/res/drawable-ldpi/ic_launcher.png
deleted file mode 100644
index 99238729d8753585237a65b91c7cde426c90baef..0000000000000000000000000000000000000000
Binary files a/app/src/androidTest/res/drawable-ldpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/androidTest/res/drawable-mdpi/ic_launcher.png b/app/src/androidTest/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 359047dfa4ed206e41e2354f9c6b307e713efe32..0000000000000000000000000000000000000000
Binary files a/app/src/androidTest/res/drawable-mdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/androidTest/res/drawable-xhdpi/ic_launcher.png b/app/src/androidTest/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 71c6d760f05183ef8a47c614d8d13380c8528499..0000000000000000000000000000000000000000
Binary files a/app/src/androidTest/res/drawable-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/androidTestStandard/java/at/bitfire/davdroid/OkhttpClientTest.kt b/app/src/androidTestOse/java/at/bitfire/davdroid/OkhttpClientTest.kt
similarity index 100%
rename from app/src/androidTestStandard/java/at/bitfire/davdroid/OkhttpClientTest.kt
rename to app/src/androidTestOse/java/at/bitfire/davdroid/OkhttpClientTest.kt
diff --git a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/AccountUtilsTest.kt b/app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/AccountUtilsTest.kt
similarity index 100%
rename from app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/AccountUtilsTest.kt
rename to app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/AccountUtilsTest.kt
diff --git a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/LocalTestCollection.kt b/app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/LocalTestCollection.kt
similarity index 100%
rename from app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/LocalTestCollection.kt
rename to app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/LocalTestCollection.kt
diff --git a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/LocalTestResource.kt b/app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/LocalTestResource.kt
similarity index 100%
rename from app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/LocalTestResource.kt
rename to app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/LocalTestResource.kt
diff --git a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncAdapterServiceTest.kt b/app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/SyncAdapterServiceTest.kt
similarity index 100%
rename from app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncAdapterServiceTest.kt
rename to app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/SyncAdapterServiceTest.kt
diff --git a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncAdapterTest.kt b/app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/SyncAdapterTest.kt
similarity index 100%
rename from app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncAdapterTest.kt
rename to app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/SyncAdapterTest.kt
diff --git a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncManagerTest.kt b/app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/SyncManagerTest.kt
similarity index 99%
rename from app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncManagerTest.kt
rename to app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/SyncManagerTest.kt
index b494110cdee3725e5ca180be7c3839a47982021b..963665489d1d06dc02bed6a4c6d5040945758106 100644
--- a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/SyncManagerTest.kt
+++ b/app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/SyncManagerTest.kt
@@ -53,7 +53,7 @@ class SyncManagerTest {
@BeforeClass
@JvmStatic
fun createAccount() {
- assertTrue(AccountManager.get(context).addAccountExplicitly(account, "test", AccountSettings.initialUserData(Credentials("test", "test"))))
+ assertTrue(AccountManager.get(context).addAccountExplicitly(account, "test", AccountSettings.initialUserData(Credentials("test", "test"), null)))
}
@AfterClass
diff --git a/app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/TestSyncManager.kt b/app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/TestSyncManager.kt
similarity index 100%
rename from app/src/androidTestStandard/java/at/bitfire/davdroid/syncadapter/TestSyncManager.kt
rename to app/src/androidTestOse/java/at/bitfire/davdroid/syncadapter/TestSyncManager.kt
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 957d808596442ee0805a85ab42faad734f3f211a..ae49a5f558c00b6b850dbadbc48dc653ef566844 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -53,7 +53,18 @@
-
+
+
+
+
+
+
+
+
-
+
@@ -104,6 +115,7 @@
android:name=".ui.setup.LoginActivity"
android:label="@string/login_title"
android:parentActivityName=".ui.AccountsActivity"
+ android:excludeFromRecents="true"
android:exported="true">
@@ -259,8 +271,284 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png
index 4cc81409080c7754124235d4d31c11ce7a8434f0..cafde5df9d1e89e1bdc0c9800cacbdabf7bd084a 100644
Binary files a/app/src/main/ic_launcher-web.png and b/app/src/main/ic_launcher-web.png differ
diff --git a/app/src/main/java/at/bitfire/davdroid/Constants.kt b/app/src/main/java/at/bitfire/davdroid/Constants.kt
index 8e6c59bc981c5ef5bdb768df26f0ad1c1c40751b..ef5d0960dd99d5f447e64a5efa74c4ee180822f8 100644
--- a/app/src/main/java/at/bitfire/davdroid/Constants.kt
+++ b/app/src/main/java/at/bitfire/davdroid/Constants.kt
@@ -10,6 +10,10 @@ object Constants {
// gplay billing
const val BILLINGCLIENT_CONNECTION_MAX_RETRIES = 4
+ // NOTE: Android 7 and up don't allow 2 min sync frequencies unless system frameworks are modified
+ const val DEFAULT_CALENDAR_SYNC_INTERVAL = 2 * 60L // 2 minutes
+ const val DEFAULT_CONTACTS_SYNC_INTERVAL = 15 * 60L // 15 minutes
+
/**
* Context label for [org.apache.commons.lang3.exception.ContextedException].
* Context value is the [at.bitfire.davdroid.resource.LocalResource]
@@ -24,4 +28,8 @@ object Constants {
*/
const val EXCEPTION_CONTEXT_REMOTE_RESOURCE = "remoteResource"
+ const val AUTH_TOKEN_TYPE = "oauth2-access-token"
+
+ const val EELO_SYNC_HOST = "ecloud.global"
+ const val E_SYNC_URL = "e.email"
}
diff --git a/app/src/main/java/at/bitfire/davdroid/DavService.kt b/app/src/main/java/at/bitfire/davdroid/DavService.kt
index eefa5c484e8e5bcb9bdfe117a48f8bc92f5b6d9b..50dac87f333eb664a54a4198851e1892b5073f86 100644
--- a/app/src/main/java/at/bitfire/davdroid/DavService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/DavService.kt
@@ -29,6 +29,7 @@ import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.DebugInfoActivity
import at.bitfire.davdroid.ui.NotificationUtils
import dagger.hilt.android.AndroidEntryPoint
+import net.openid.appauth.AuthState
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import java.lang.ref.WeakReference
@@ -171,7 +172,7 @@ class DavService: IntentService("DavService") {
val collectionDao = db.collectionDao()
val service = db.serviceDao().get(serviceId) ?: throw IllegalArgumentException("Service not found")
- val account = Account(service.accountName, getString(R.string.account_type))
+ val account = Account(service.accountName, service.accountType)
val homeSets = homeSetDao.getByService(serviceId).associateBy { it.url }.toMutableMap()
val collections = collectionDao.getByService(serviceId).associateBy { it.url }.toMutableMap()
@@ -190,7 +191,7 @@ class DavService: IntentService("DavService") {
* @throws HttpException
* @throws at.bitfire.dav4jvm.exception.DavException
*/
- fun queryHomeSets(client: OkHttpClient, url: HttpUrl, personal: Boolean = true) {
+ fun queryHomeSets(client: OkHttpClient, url: HttpUrl, accessToken: String?, personal: Boolean = true) {
val related = mutableSetOf()
fun findRelated(root: HttpUrl, dav: Response) {
@@ -223,7 +224,7 @@ class DavService: IntentService("DavService") {
}
}
- val dav = DavResource(client, url)
+ val dav = DavResource(client, url, accessToken)
when (service.type) {
Service.TYPE_CARDDAV ->
try {
@@ -270,7 +271,8 @@ class DavService: IntentService("DavService") {
// query related homesets (those that do not belong to the current-user-principal)
for (resource in related)
- queryHomeSets(client, resource, false)
+ queryHomeSets(client, resource, accessToken, false)
+
}
fun saveHomesets() {
@@ -303,91 +305,145 @@ class DavService: IntentService("DavService") {
HttpClient.Builder(this, AccountSettings(this, account))
.setForeground(true)
.build().use { client ->
- val httpClient = client.okHttpClient
-
- // refresh home set list (from principal)
- service.principal?.let { principalUrl ->
- Logger.log.fine("Querying principal $principalUrl for home sets")
- queryHomeSets(httpClient, principalUrl)
- }
-
- // now refresh homesets and their member collections
- val itHomeSets = homeSets.iterator()
- while (itHomeSets.hasNext()) {
- val (homeSetUrl, homeSet) = itHomeSets.next()
- Logger.log.fine("Listing home set $homeSetUrl")
-
- try {
- DavResource(httpClient, homeSetUrl).propfind(1, *DAV_COLLECTION_PROPERTIES) { response, relation ->
- if (!response.isSuccess())
- return@propfind
-
- if (relation == Response.HrefRelation.SELF) {
- // this response is about the homeset itself
- homeSet.displayName = response[DisplayName::class.java]?.displayName
- homeSet.privBind = response[CurrentUserPrivilegeSet::class.java]?.mayBind ?: true
- }
-
- // in any case, check whether the response is about a useable collection
- val info = Collection.fromDavResponse(response) ?: return@propfind
- info.serviceId = serviceId
- info.refHomeSet = homeSet
- info.confirmed = true
+ val httpClient = client.okHttpClient
- // whether new collections are selected for synchronization by default (controlled by managed setting)
- info.sync = syncAllCollections
-
- info.owner = response[Owner::class.java]?.href?.let { response.href.resolve(it) }
- Logger.log.log(Level.FINE, "Found collection", info)
+ var accessToken : String? = null
+ service.authState?.let {
+ accessToken = AuthState.jsonDeserialize(it).accessToken
+ }
- // remember usable collections
- if ((service.type == Service.TYPE_CARDDAV && info.type == Collection.TYPE_ADDRESSBOOK) ||
- (service.type == Service.TYPE_CALDAV && arrayOf(Collection.TYPE_CALENDAR, Collection.TYPE_WEBCAL).contains(info.type)))
- collections[response.href] = info
- }
- } catch(e: HttpException) {
- if (e.code in arrayOf(403, 404, 410))
- // delete home set only if it was not accessible (40x)
- itHomeSets.remove()
+ // refresh home set list (from principal)
+ service.principal?.let { principalUrl ->
+ Logger.log.fine("Querying principal $principalUrl for home sets")
+ queryHomeSets(httpClient, principalUrl, accessToken)
}
- }
- // check/refresh unconfirmed collections
- val collectionsIter = collections.entries.iterator()
- while (collectionsIter.hasNext()) {
- val currentCollection = collectionsIter.next()
- val (url, info) = currentCollection
- if (!info.confirmed)
- try {
- // this collection doesn't belong to a homeset anymore, otherwise it would have been confirmed
- info.homeSetId = null
+// now refresh homesets and their member collections
+ val itHomeSets = homeSets.iterator()
+ while (itHomeSets.hasNext()) {
+ val homeSet = itHomeSets.next()
+ Logger.log.fine("Listing home set ${homeSet.key}")
- DavResource(httpClient, url).propfind(0, *DAV_COLLECTION_PROPERTIES) { response, _ ->
+ try {
+ DavResource(httpClient, homeSet.key, accessToken).propfind(
+ 1,
+ *DAV_COLLECTION_PROPERTIES
+ ) { response, relation ->
if (!response.isSuccess())
return@propfind
- val collection = Collection.fromDavResponse(response) ?: return@propfind
- collection.serviceId = info.serviceId // use same service ID as previous entry
- collection.confirmed = true
+ if (relation == Response.HrefRelation.SELF) {
+ // this response is about the homeset itself
+ homeSet.value.displayName =
+ response[DisplayName::class.java]?.displayName
+ homeSet.value.privBind =
+ response[CurrentUserPrivilegeSet::class.java]?.mayBind
+ ?: true
+ }
+
+ // in any case, check whether the response is about a useable collection
+ val info = Collection.fromDavResponse(response) ?: return@propfind
+ info.serviceId = serviceId
+ info.confirmed = true
+ Logger.log.log(Level.FINE, "Found collection", info)
+
+ // remember usable collections
+ if ((service.type == Service.TYPE_CARDDAV && info.type == Collection.TYPE_ADDRESSBOOK) ||
+ (service.type == Service.TYPE_CALDAV && arrayOf(Collection.TYPE_CALENDAR, Collection.TYPE_WEBCAL).contains(info.type))) {
+ // Ignore "recently contacted" accounts since it is buggy and causes error 501
+ if (!info.url.toString().contains(AccountSettings.CONTACTS_APP_INTERACTION)) {
+ collections[response.href] = info
+ }
+ }
+ }
+ } catch (e: HttpException) {
+ if (e.code in arrayOf(403, 404, 410))
+ // delete home set only if it was not accessible (40x)
+ itHomeSets.remove()
+ }
+ }
- // remove unusable collections
- if ((service.type == Service.TYPE_CARDDAV && collection.type != Collection.TYPE_ADDRESSBOOK) ||
- (service.type == Service.TYPE_CALDAV && !arrayOf(Collection.TYPE_CALENDAR, Collection.TYPE_WEBCAL).contains(collection.type)) ||
- (collection.type == Collection.TYPE_WEBCAL && collection.source == null))
+ // check/refresh unconfirmed collections
+ val collectionsIter = collections.entries.iterator()
+ while (collectionsIter.hasNext()) {
+ val currentCollection = collectionsIter.next()
+ val (url, info) = currentCollection
+ if (!info.confirmed)
+ try {
+ // this collection doesn't belong to a homeset anymore, otherwise it would have been confirmed
+ info.homeSetId = null
+
+ DavResource(httpClient, url).propfind(
+ 0,
+ *DAV_COLLECTION_PROPERTIES
+ ) { response, _ ->
+ if (!response.isSuccess())
+ return@propfind
+
+ val collection =
+ Collection.fromDavResponse(response) ?: return@propfind
+ collection.serviceId =
+ info.serviceId // use same service ID as previous entry
+ collection.confirmed = true
+
+ // remove unusable collections
+ if ((service.type == Service.TYPE_CARDDAV && collection.type != Collection.TYPE_ADDRESSBOOK) ||
+ (service.type == Service.TYPE_CALDAV && !arrayOf(
+ Collection.TYPE_CALENDAR,
+ Collection.TYPE_WEBCAL
+ ).contains(collection.type)) ||
+ (collection.type == Collection.TYPE_WEBCAL && collection.source == null)
+ )
+ collectionsIter.remove()
+ else
+ // update this collection in list
+ currentCollection.setValue(collection)
+ }
+ } catch (e: HttpException) {
+ if (e.code in arrayOf(403, 404, 410))
+ // delete collection only if it was not accessible (40x)
collectionsIter.remove()
else
- // update this collection in list
- currentCollection.setValue(collection)
+ throw e
}
- } catch(e: HttpException) {
- if (e.code in arrayOf(403, 404, 410))
+ }
+
+ // check/refresh unconfirmed collections
+ val itCollections = collections.entries.iterator()
+ while (itCollections.hasNext()) {
+ val (url, info) = itCollections.next()
+ if (!info.confirmed)
+ try {
+ DavResource(httpClient, url, accessToken).propfind(
+ 0,
+ *DAV_COLLECTION_PROPERTIES
+ ) { response, _ ->
+ if (!response.isSuccess())
+ return@propfind
+
+ val collection =
+ Collection.fromDavResponse(response) ?: return@propfind
+ collection.confirmed = true
+
+ // remove unusable collections
+ if ((service.type == Service.TYPE_CARDDAV && collection.type != Collection.TYPE_ADDRESSBOOK) ||
+ (service.type == Service.TYPE_CALDAV && !arrayOf(
+ Collection.TYPE_CALENDAR,
+ Collection.TYPE_WEBCAL
+ ).contains(collection.type)) ||
+ (collection.type == Collection.TYPE_WEBCAL && collection.source == null)
+ )
+ itCollections.remove()
+ }
+ } catch (e: HttpException) {
+ if (e.code in arrayOf(403, 404, 410))
// delete collection only if it was not accessible (40x)
- collectionsIter.remove()
- else
- throw e
- }
+ itCollections.remove()
+ else
+ throw e
+ }
+ }
}
- }
db.runInTransaction {
saveHomesets()
diff --git a/app/src/main/java/at/bitfire/davdroid/ECloudAccountHelper.kt b/app/src/main/java/at/bitfire/davdroid/ECloudAccountHelper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2e07362eb6919cfac5e2e8a062856b8a1c079187
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/ECloudAccountHelper.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid
+
+import android.accounts.AccountManager
+import android.app.Activity
+import android.content.Context
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+
+object ECloudAccountHelper {
+
+ fun alreadyHasECloudAccount(context: Context) : Boolean {
+ val accountManager = AccountManager.get(context)
+ val eCloudAccounts = accountManager.getAccountsByType(context.getString(R.string.eelo_account_type))
+ return eCloudAccounts.isNotEmpty()
+ }
+
+ fun showMultipleECloudAccountNotAcceptedDialog(activity: Activity) {
+ MaterialAlertDialogBuilder(activity, R.style.CustomAlertDialogStyle)
+ .setIcon(R.drawable.ic_error)
+ .setMessage(R.string.multiple_ecloud_account_not_permitted_message)
+ .setCancelable(false)
+ .setPositiveButton(android.R.string.ok) { _, _ ->
+ activity.finish()
+ }
+ .show()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/at/bitfire/davdroid/MailAccountSyncHelper.kt b/app/src/main/java/at/bitfire/davdroid/MailAccountSyncHelper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..42e78eb37803682661ca464ef550c3439c62e194
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/MailAccountSyncHelper.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+
+object MailAccountSyncHelper {
+
+ private const val MAIL_PACKAGE = "foundation.e.mail"
+ private const val MAIL_RECEIVER_CLASS = "com.fsck.k9.account.AccountSyncReceiver"
+ private const val ACTION_PREFIX = "foundation.e.accountmanager.account."
+
+ fun accountLoggedIn(applicationContext : Context?) {
+ val intent = getIntent()
+ intent.action = ACTION_PREFIX + "create"
+ applicationContext?.sendBroadcast(intent)
+ }
+
+ fun accountLoggedOut(applicationContext: Context?, email: String?) {
+ email?.let {
+ if (!it.contains("@")) {
+ return@let
+ }
+ val intent = getIntent()
+ intent.action = ACTION_PREFIX + "remove"
+ intent.putExtra("account", it)
+ applicationContext?.sendBroadcast(intent)
+ }
+ }
+
+ private fun getIntent() : Intent {
+ val intent = Intent()
+ intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
+ intent.component = ComponentName(MAIL_PACKAGE, MAIL_RECEIVER_CLASS)
+ return intent
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/at/bitfire/davdroid/authorization/IdentityProvider.java b/app/src/main/java/at/bitfire/davdroid/authorization/IdentityProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..7277d3bdfca1ad5a021cf04b23502a6ee72bed70
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/authorization/IdentityProvider.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.authorization;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.Uri;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+
+import net.openid.appauth.AuthorizationServiceConfiguration;
+import net.openid.appauth.AuthorizationServiceConfiguration.RetrieveConfigurationCallback;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import at.bitfire.davdroid.R;
+
+/**
+ * An abstraction of identity providers, containing all necessary info for the demo app.
+ */
+public class IdentityProvider {
+
+ /**
+ * Value used to indicate that a configured property is not specified or required.
+ */
+ public static final int NOT_SPECIFIED = -1;
+
+ public static final IdentityProvider GOOGLE = new IdentityProvider(
+ "Google",
+ R.string.google_discovery_uri,
+ NOT_SPECIFIED, // auth endpoint is discovered
+ NOT_SPECIFIED, // token endpoint is discovered
+ R.string.google_client_id,
+ NOT_SPECIFIED, // client secret is not required for Google
+ R.string.google_auth_redirect_uri,
+ R.string.google_scope_string,
+ R.string.google_name);
+
+ public static final List PROVIDERS = Arrays.asList(
+ GOOGLE);
+
+ public static List getEnabledProviders(Context context) {
+ ArrayList providers = new ArrayList<>();
+ for (IdentityProvider provider : PROVIDERS) {
+ provider.readConfiguration(context);
+ providers.add(provider);
+ }
+ return providers;
+ }
+
+ @NonNull
+ public final String name;
+
+ @StringRes
+ public final int buttonContentDescriptionRes;
+
+ @StringRes
+ private final int mDiscoveryEndpointRes;
+
+ @StringRes
+ private final int mAuthEndpointRes;
+
+ @StringRes
+ private final int mTokenEndpointRes;
+
+ @StringRes
+ private final int mClientIdRes;
+
+ @StringRes
+ private final int mClientSecretRes;
+
+ @StringRes
+ private final int mRedirectUriRes;
+
+ @StringRes
+ private final int mScopeRes;
+
+ private boolean mConfigurationRead = false;
+ private Uri mDiscoveryEndpoint;
+ private Uri mAuthEndpoint;
+ private Uri mTokenEndpoint;
+ private String mClientId;
+ private String mClientSecret;
+ private Uri mRedirectUri;
+ private String mScope;
+
+ IdentityProvider(
+ @NonNull String name,
+ @StringRes int discoveryEndpointRes,
+ @StringRes int authEndpointRes,
+ @StringRes int tokenEndpointRes,
+ @StringRes int clientIdRes,
+ @StringRes int clientSecretRes,
+ @StringRes int redirectUriRes,
+ @StringRes int scopeRes,
+ @StringRes int buttonContentDescriptionRes) {
+ if (!isSpecified(discoveryEndpointRes)
+ && !isSpecified(authEndpointRes)
+ && !isSpecified(tokenEndpointRes)) {
+ throw new IllegalArgumentException(
+ "the discovery endpoint or the auth and token endpoints must be specified");
+ }
+
+ this.name = name;
+ this.mDiscoveryEndpointRes = discoveryEndpointRes;
+ this.mAuthEndpointRes = authEndpointRes;
+ this.mTokenEndpointRes = tokenEndpointRes;
+ this.mClientIdRes = checkSpecified(clientIdRes, "clientIdRes");
+ this.mClientSecretRes = clientSecretRes;
+ this.mRedirectUriRes = checkSpecified(redirectUriRes, "redirectUriRes");
+ this.mScopeRes = checkSpecified(scopeRes, "scopeRes");
+ this.buttonContentDescriptionRes =
+ checkSpecified(buttonContentDescriptionRes, "buttonContentDescriptionRes");
+ }
+
+ /**
+ * This must be called before any of the getters will function.
+ */
+ public void readConfiguration(Context context) {
+ if (mConfigurationRead) {
+ return;
+ }
+
+ Resources res = context.getResources();
+
+ mDiscoveryEndpoint = isSpecified(mDiscoveryEndpointRes)
+ ? getUriResource(res, mDiscoveryEndpointRes, "discoveryEndpointRes")
+ : null;
+ mAuthEndpoint = isSpecified(mAuthEndpointRes)
+ ? getUriResource(res, mAuthEndpointRes, "authEndpointRes")
+ : null;
+ mTokenEndpoint = isSpecified(mTokenEndpointRes)
+ ? getUriResource(res, mTokenEndpointRes, "tokenEndpointRes")
+ : null;
+ mClientId = res.getString(mClientIdRes);
+ mClientSecret = isSpecified(mClientSecretRes) ? res.getString(mClientSecretRes) : null;
+ mRedirectUri = getUriResource(res, mRedirectUriRes, "mRedirectUriRes");
+ mScope = res.getString(mScopeRes);
+
+ mConfigurationRead = true;
+ }
+
+ private void checkConfigurationRead() {
+ if (!mConfigurationRead) {
+ throw new IllegalStateException("Configuration not read");
+ }
+ }
+
+ @Nullable
+ public Uri getDiscoveryEndpoint() {
+ checkConfigurationRead();
+ return mDiscoveryEndpoint;
+ }
+
+ @Nullable
+ public Uri getAuthEndpoint() {
+ checkConfigurationRead();
+ return mAuthEndpoint;
+ }
+
+ @Nullable
+ public Uri getTokenEndpoint() {
+ checkConfigurationRead();
+ return mTokenEndpoint;
+ }
+
+ @NonNull
+ public String getClientId() {
+ checkConfigurationRead();
+ return mClientId;
+ }
+
+ @Nullable
+ public String getClientSecret() {
+ checkConfigurationRead();
+ return mClientSecret;
+ }
+
+ @NonNull
+ public Uri getRedirectUri() {
+ checkConfigurationRead();
+ return mRedirectUri;
+ }
+
+ @NonNull
+ public String getScope() {
+ checkConfigurationRead();
+ return mScope;
+ }
+
+ public void retrieveConfig(Context context,
+ RetrieveConfigurationCallback callback) {
+ readConfiguration(context);
+ if (getDiscoveryEndpoint() != null) {
+ AuthorizationServiceConfiguration.fetchFromUrl(mDiscoveryEndpoint, callback);
+ } else {
+ AuthorizationServiceConfiguration config =
+ new AuthorizationServiceConfiguration(mAuthEndpoint, mTokenEndpoint, null);
+ callback.onFetchConfigurationCompleted(config, null);
+ }
+ }
+
+ private static boolean isSpecified(int value) {
+ return value != NOT_SPECIFIED;
+ }
+
+ private static int checkSpecified(int value, String valueName) {
+ if (value == NOT_SPECIFIED) {
+ throw new IllegalArgumentException(valueName + " must be specified");
+ }
+ return value;
+ }
+
+ private static Uri getUriResource(Resources res, @StringRes int resId, String resName) {
+ return Uri.parse(res.getString(resId));
+ }
+}
+
diff --git a/app/src/main/java/at/bitfire/davdroid/db/AppDatabase.kt b/app/src/main/java/at/bitfire/davdroid/db/AppDatabase.kt
index fc56d4c69a723ddb8ba94a2a0291ac4b5359230b..4e3e9480c86b405321538101756a3400c28e0edb 100644
--- a/app/src/main/java/at/bitfire/davdroid/db/AppDatabase.kt
+++ b/app/src/main/java/at/bitfire/davdroid/db/AppDatabase.kt
@@ -37,8 +37,7 @@ import javax.inject.Singleton
WebDavDocument::class,
WebDavMount::class
], exportSchema = true, version = 11, autoMigrations = [
- AutoMigration(from = 9, to = 10),
- AutoMigration(from = 10, to = 11)
+ AutoMigration(from = 9, to = 10)
])
@TypeConverters(Converters::class)
abstract class AppDatabase: RoomDatabase() {
@@ -80,6 +79,13 @@ abstract class AppDatabase: RoomDatabase() {
// migrations
val migrations: Array = arrayOf(
+ object : Migration(10, 11) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.execSQL("CREATE TABLE IF NOT EXISTS `webdav_document` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `mountId` INTEGER NOT NULL, `parentId` INTEGER, `name` TEXT NOT NULL, `isDirectory` INTEGER NOT NULL, `displayName` TEXT, `mimeType` TEXT, `eTag` TEXT, `lastModified` INTEGER, `size` INTEGER, `mayBind` INTEGER, `mayUnbind` INTEGER, `mayWriteContent` INTEGER, `quotaAvailable` INTEGER, `quotaUsed` INTEGER, FOREIGN KEY(`mountId`) REFERENCES `webdav_mount`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`parentId`) REFERENCES `webdav_document`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
+ database.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_webdav_document_mountId_parentId_name` ON `webdav_document` (`mountId`, `parentId`, `name`)")
+ }
+ },
+
object : Migration(8, 9) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("CREATE TABLE syncstats (" +
@@ -116,11 +122,14 @@ abstract class AppDatabase: RoomDatabase() {
"CREATE TABLE service(" +
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," +
"accountName TEXT NOT NULL," +
+ "authState TEXT," +
+ "accountType TEXT," +
+ "addressBookAccountType TEXT," +
"type TEXT NOT NULL," +
"principal TEXT DEFAULT NULL" +
")",
"CREATE UNIQUE INDEX index_service_accountName_type ON service(accountName, type)",
- "INSERT INTO service(id, accountName, type, principal) SELECT _id, accountName, service, principal FROM services",
+ "INSERT INTO service(id, accountName, authState, accountType, addressBookAccountType, type, principal) SELECT _id, accountName, authState, accountType, addressBookAccountType, service, principal FROM services",
"DROP TABLE services",
// migrate "homesets" to "homeset": rename columns, make id NOT NULL
diff --git a/app/src/main/java/at/bitfire/davdroid/db/Collection.kt b/app/src/main/java/at/bitfire/davdroid/db/Collection.kt
index eee29ed14a87e531c9e0a466a21250aa5c7f0019..213f54849a32e9d9da506d21ea8c16892497d296 100644
--- a/app/src/main/java/at/bitfire/davdroid/db/Collection.kt
+++ b/app/src/main/java/at/bitfire/davdroid/db/Collection.kt
@@ -61,7 +61,7 @@ data class Collection(
var source: HttpUrl? = null,
/** whether this collection has been selected for synchronization */
- var sync: Boolean = false
+ var sync: Boolean = true
): IdEntity {
@@ -171,4 +171,4 @@ data class Collection(
fun title() = displayName ?: DavUtils.lastSegmentOfUrl(url)
fun readOnly() = forceReadOnly || !privWriteContent
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/db/Credentials.kt b/app/src/main/java/at/bitfire/davdroid/db/Credentials.kt
index f2f4758b1185a3000dd4896e43b2c498ec182ad8..45af127502199a0b2b481a617f134c592f3e8c61 100644
--- a/app/src/main/java/at/bitfire/davdroid/db/Credentials.kt
+++ b/app/src/main/java/at/bitfire/davdroid/db/Credentials.kt
@@ -4,10 +4,15 @@
package at.bitfire.davdroid.db
+import net.openid.appauth.AuthState
+import java.net.URI
+
data class Credentials(
val userName: String? = null,
val password: String? = null,
- val certificateAlias: String? = null
+ val authState: AuthState? = null,
+ val certificateAlias: String? = null,
+ val serverUri: URI? = null
) {
override fun toString(): String {
diff --git a/app/src/main/java/at/bitfire/davdroid/db/Service.kt b/app/src/main/java/at/bitfire/davdroid/db/Service.kt
index 0287f6c215042fa5ceaf7b45194ee2ac4b68af70..1e757519a41ae48e23c4acaf27328429ca9a7ceb 100644
--- a/app/src/main/java/at/bitfire/davdroid/db/Service.kt
+++ b/app/src/main/java/at/bitfire/davdroid/db/Service.kt
@@ -19,6 +19,11 @@ data class Service(
override var id: Long,
var accountName: String,
+
+ var authState: String?,
+ var accountType: String?,
+ var addressBookAccountType: String?,
+
var type: String,
var principal: HttpUrl?
diff --git a/app/src/main/java/at/bitfire/davdroid/db/ServiceDao.kt b/app/src/main/java/at/bitfire/davdroid/db/ServiceDao.kt
index 62ed226c9f3e28c9214aea99d34e7824bb2bf90e..d45bb779dc6348fa86a9795f08ffd75f3f117f4c 100644
--- a/app/src/main/java/at/bitfire/davdroid/db/ServiceDao.kt
+++ b/app/src/main/java/at/bitfire/davdroid/db/ServiceDao.kt
@@ -22,6 +22,10 @@ interface ServiceDao {
@Query("SELECT * FROM service WHERE id=:id")
fun get(id: Long): Service?
+
+ @Query("SELECT * FROM service WHERE accountName=:accountName")
+ fun getByAccountName(accountName: String): Service?
+
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertOrReplace(service: Service): Long
diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt b/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt
index eba09f8173e75611d57a8ad2907bacd10a069307..98076add8106154013d729f71b3a44848bcdacca 100644
--- a/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt
+++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt
@@ -8,6 +8,8 @@ import android.accounts.AccountManager
import android.content.*
import android.os.Build
import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
import android.os.RemoteException
import android.provider.ContactsContract
import android.provider.ContactsContract.CommonDataKinds.GroupMembership
@@ -16,6 +18,7 @@ import android.provider.ContactsContract.RawContacts
import android.util.Base64
import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.R
+import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.SyncState
import at.bitfire.davdroid.log.Logger
@@ -23,6 +26,8 @@ import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.syncadapter.AccountUtils
import at.bitfire.davdroid.syncadapter.SyncUtils
import at.bitfire.vcard4android.*
+import at.bitfire.davdroid.MailAccountSyncHelper
+
import java.io.ByteArrayOutputStream
import java.util.*
import java.util.logging.Level
@@ -46,8 +51,10 @@ open class LocalAddressBook(
const val USER_DATA_URL = "url"
const val USER_DATA_READ_ONLY = "read_only"
- fun create(context: Context, provider: ContentProviderClient, mainAccount: Account, info: Collection): LocalAddressBook {
- val account = Account(accountName(mainAccount, info), context.getString(R.string.account_type_address_book))
+ fun create(context: Context, db: AppDatabase, provider: ContentProviderClient, mainAccount: Account, info: Collection): LocalAddressBook {
+ val service = db.serviceDao().getByAccountName(mainAccount.name) ?: throw IllegalArgumentException("Service not found")
+ val account = Account(accountName(mainAccount, info), service.addressBookAccountType)
+
val userData = initialUserData(mainAccount, info.url.toString())
Logger.log.log(Level.INFO, "Creating local address book $account", userData)
if (!AccountUtils.createAccount(context, account, userData))
@@ -65,18 +72,18 @@ open class LocalAddressBook(
return addressBook
}
+
+ fun findAll(context: Context, provider: ContentProviderClient?, mainAccount: Account?): List {
+ val accountManager = AccountManager.get(context)
+ val accounts = ArrayList()
+ accountManager.getAccountsByType(context.getString(R.string.account_type_eelo_address_book)).forEach { accounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type_google_address_book)).forEach { accounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type_address_book)).forEach { accounts.add(it) }
- fun findAll(context: Context, provider: ContentProviderClient?, mainAccount: Account) = AccountManager.get(context)
- .getAccountsByType(context.getString(R.string.account_type_address_book))
- .map { LocalAddressBook(context, it, provider) }
- .filter {
- try {
- it.mainAccount == mainAccount
- } catch(e: IllegalStateException) {
- false
- }
- }
+ return accounts.toTypedArray().map { LocalAddressBook(context, it, provider) }
+ .filter { mainAccount == null || it.mainAccount == mainAccount }
.toList()
+ }
fun accountName(mainAccount: Account, info: Collection): String {
val baos = ByteArrayOutputStream()
@@ -102,7 +109,10 @@ open class LocalAddressBook(
}
fun mainAccount(context: Context, account: Account): Account =
- if (account.type == context.getString(R.string.account_type_address_book)) {
+ if (account.type == context.getString(R.string.account_type_address_book) ||
+ account.type == context.getString(R.string.account_type_eelo_address_book) ||
+ account.type == context.getString(R.string.account_type_google_address_book)) {
+
val manager = AccountManager.get(context)
val accountName = manager.getUserData(account, USER_DATA_MAIN_ACCOUNT_NAME)
val accountType = manager.getUserData(account, USER_DATA_MAIN_ACCOUNT_TYPE)
@@ -233,11 +243,43 @@ open class LocalAddressBook(
fun delete() {
val accountManager = AccountManager.get(context)
+ val email = accountManager.getUserData(account, AccountSettings.KEY_EMAIL_ADDRESS)
+
@Suppress("DEPRECATION")
- if (Build.VERSION.SDK_INT >= 22)
- accountManager.removeAccount(account, null, null, null)
- else
- accountManager.removeAccount(account, null, null)
+ if (Build.VERSION.SDK_INT >= 22) {
+ removeAccount(accountManager, email)
+ }
+ else {
+ removeAccountForOlderSdk(accountManager, email)
+ }
+ }
+
+ private fun removeAccountForOlderSdk(accountManager: AccountManager, email: String?) {
+ accountManager.removeAccount(account, {
+ try {
+ if (it.result) {
+ Handler(Looper.getMainLooper()).post {
+ MailAccountSyncHelper.accountLoggedOut(context.applicationContext, email)
+ }
+ }
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't remove account", e)
+ }
+ }, null)
+ }
+
+ private fun removeAccount(accountManager: AccountManager, email: String?) {
+ accountManager.removeAccount(account, null, {
+ try {
+ if (it.result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
+ Handler(Looper.getMainLooper()).post {
+ MailAccountSyncHelper.accountLoggedOut(context.applicationContext, email)
+ }
+ }
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't remove account", e)
+ }
+ }, null)
}
@@ -369,6 +411,7 @@ open class LocalAddressBook(
* @return id of the group with given title
* @throws RemoteException on content provider errors
*/
+ @Synchronized
fun findOrCreateGroup(title: String): Long {
provider!!.query(syncAdapterURI(Groups.CONTENT_URI), arrayOf(Groups._ID),
"${Groups.TITLE}=?", arrayOf(title), null)?.use { cursor ->
diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.kt b/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.kt
index 90240734470d4b724ae8e1dbe8a2d98c091368d5..bb6e29b5395821b5f53563abb3feacd142463be8 100644
--- a/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.kt
+++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.kt
@@ -19,8 +19,8 @@ import at.bitfire.davdroid.log.Logger
import at.bitfire.ical4android.AndroidCalendar
import at.bitfire.ical4android.AndroidCalendarFactory
import at.bitfire.ical4android.BatchOperation
-import at.bitfire.ical4android.DateUtils
-import at.bitfire.ical4android.MiscUtils.UriHelper.asSyncAdapter
+import at.bitfire.ical4android.util.DateUtils
+import at.bitfire.ical4android.util.MiscUtils.UriHelper.asSyncAdapter
import java.util.*
import java.util.logging.Level
diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalEvent.kt b/app/src/main/java/at/bitfire/davdroid/resource/LocalEvent.kt
index e5a64e0265308926bfb8c769abd9f951448bf51a..495e7d42f8ff916fc7d0fb08476ee6cda89f2706 100644
--- a/app/src/main/java/at/bitfire/davdroid/resource/LocalEvent.kt
+++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalEvent.kt
@@ -12,7 +12,7 @@ import android.provider.CalendarContract
import android.provider.CalendarContract.Events
import at.bitfire.davdroid.BuildConfig
import at.bitfire.ical4android.*
-import at.bitfire.ical4android.MiscUtils.UriHelper.asSyncAdapter
+import at.bitfire.ical4android.util.MiscUtils.UriHelper.asSyncAdapter
import net.fortuna.ical4j.model.property.ProdId
import org.apache.commons.lang3.StringUtils
import java.util.*
@@ -193,27 +193,50 @@ class LocalEvent: AndroidEvent, LocalResource {
}
+ /**
+ * Creates and sets a new UID in the calendar provider, if no UID is already set.
+ * It also returns the desired file name for the event for further processing in the sync algorithm.
+ *
+ * @return file name to use at upload
+ */
override fun prepareForUpload(): String {
- var uid: String? = null
+ // fetch UID_2445 from calendar provider
+ var dbUid: String? = null
calendar.provider.query(eventSyncURI(), arrayOf(Events.UID_2445), null, null, null)?.use { cursor ->
if (cursor.moveToNext())
- uid = StringUtils.trimToNull(cursor.getString(0))
+ dbUid = StringUtils.trimToNull(cursor.getString(0))
}
- if (uid == null) {
+ // make sure that UID is set
+ val uid: String = dbUid ?: {
// generate new UID
- uid = UUID.randomUUID().toString()
+ val newUid = UUID.randomUUID().toString()
+ // update in calendar provider
val values = ContentValues(1)
- values.put(Events.UID_2445, uid)
+ values.put(Events.UID_2445, newUid)
calendar.provider.update(eventSyncURI(), values, null, null)
- event!!.uid = uid
- }
+ // Update this event
+ event?.uid = newUid
+
+ newUid
+ }()
- return "$uid.ics"
+ val uidIsGoodFilename = uid.all { char ->
+ // see RFC 2396 2.2
+ char.isLetterOrDigit() || arrayOf( // allow letters and digits
+ ';',':','@','&','=','+','$',',', // allow reserved characters except '/' and '?'
+ '-','_','.','!','~','*','\'','(',')' // allow unreserved characters
+ ).contains(char)
+ }
+ return if (uidIsGoodFilename)
+ "$uid.ics" // use UID as file name
+ else
+ "${UUID.randomUUID()}.ics" // UID would be dangerous as file name, use random UUID instead
}
+
override fun clearDirty(fileName: String?, eTag: String?, scheduleTag: String?) {
val values = ContentValues(5)
if (fileName != null)
diff --git a/app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt b/app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt
index 8d414c121ab07cd9c17585c76b5b4fa6f05ef8c1..120b9523b60751e25826fff1f03481550506329f 100644
--- a/app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt
+++ b/app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt
@@ -21,6 +21,7 @@ import android.util.Base64
import androidx.annotation.WorkerThread
import androidx.core.content.ContextCompat
import androidx.preference.PreferenceManager
+import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.R
import at.bitfire.davdroid.closeCompat
@@ -47,6 +48,7 @@ import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.components.SingletonComponent
import net.fortuna.ical4j.model.Property
import net.fortuna.ical4j.model.property.Url
+import net.openid.appauth.AuthState
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.apache.commons.lang3.StringUtils
import org.dmfs.tasks.contract.TaskContract
@@ -89,6 +91,8 @@ class AccountSettings(
const val KEY_SYNC_INTERVAL_TASKS = "sync_interval_tasks"
const val KEY_USERNAME = "user_name"
+ const val KEY_EMAIL_ADDRESS = "email_address"
+ const val KEY_AUTH_STATE = "auth_state"
const val KEY_CERTIFICATE_ALIAS = "certificate_alias"
const val KEY_WIFI_ONLY = "wifi_only" // sync on WiFi only (default: false)
@@ -133,16 +137,27 @@ class AccountSettings(
const val SYNC_INTERVAL_MANUALLY = -1L
+ const val CONTACTS_APP_INTERACTION = "z-app-generated--contactsinteraction--recent/"
- fun initialUserData(credentials: Credentials?): Bundle {
+ fun initialUserData(credentials: Credentials?, baseURL: String?): Bundle {
val bundle = Bundle(2)
bundle.putString(KEY_SETTINGS_VERSION, CURRENT_VERSION.toString())
if (credentials != null) {
- if (credentials.userName != null)
+ if (credentials.userName != null) {
bundle.putString(KEY_USERNAME, credentials.userName)
- if (credentials.certificateAlias != null)
+ bundle.putString(KEY_EMAIL_ADDRESS, credentials.userName)
+ }
+ if (credentials.certificateAlias != null) {
bundle.putString(KEY_CERTIFICATE_ALIAS, credentials.certificateAlias)
+ }
+ if (credentials.authState != null) {
+ bundle.putString(KEY_AUTH_STATE, credentials.authState.jsonSerializeString())
+ }
+ }
+
+ if (!baseURL.isNullOrEmpty()) {
+ bundle.putString("oc_base_url", baseURL)
}
return bundle
@@ -200,12 +215,12 @@ class AccountSettings(
init {
when (argAccount.type) {
- context.getString(R.string.account_type_address_book) -> {
+ context.getString(R.string.account_type_address_book), context.getString(R.string.account_type_eelo_address_book), context.getString(R.string.account_type_google_address_book) -> {
/* argAccount is an address book account, which is not a main account. However settings are
stored in the main account, so resolve and use the main account instead. */
account = LocalAddressBook.mainAccount(context, argAccount)
}
- context.getString(R.string.account_type) ->
+ context.getString(R.string.account_type), context.getString(R.string.google_account_type), context.getString(R.string.eelo_account_type) ->
account = argAccount
else ->
throw IllegalArgumentException("Account type not supported")
@@ -229,16 +244,37 @@ class AccountSettings(
// authentication settings
- fun credentials() = Credentials(
- accountManager.getUserData(account, KEY_USERNAME),
- accountManager.getPassword(account),
- accountManager.getUserData(account, KEY_CERTIFICATE_ALIAS)
- )
+ fun credentials(): Credentials {
+ return if (accountManager.getUserData(account, KEY_AUTH_STATE).isNullOrEmpty()) {
+ Credentials(
+ accountManager.getUserData(account, KEY_USERNAME),
+ accountManager.getPassword(account),
+ null,
+ accountManager.getUserData(account, KEY_CERTIFICATE_ALIAS)
+ )
+ } else {
+ Credentials(
+ accountManager.getUserData(account, KEY_USERNAME),
+ accountManager.getPassword(account),
+ AuthState.jsonDeserialize(accountManager.getUserData(account, KEY_AUTH_STATE)),
+ accountManager.getUserData(account, KEY_CERTIFICATE_ALIAS)
+ )
+ }
+ }
fun credentials(credentials: Credentials) {
- accountManager.setUserData(account, KEY_USERNAME, credentials.userName)
- accountManager.setPassword(account, credentials.password)
- accountManager.setUserData(account, KEY_CERTIFICATE_ALIAS, credentials.certificateAlias)
+ if (credentials.authState == null) {
+ accountManager.setUserData(account, KEY_USERNAME, credentials.userName)
+ accountManager.setPassword(account, credentials.password)
+ accountManager.setUserData(account, KEY_CERTIFICATE_ALIAS, credentials.certificateAlias)
+ }
+ else {
+ accountManager.setUserData(account, KEY_USERNAME, credentials.userName)
+ accountManager.setPassword(account, credentials.password)
+ accountManager.setUserData(account, KEY_AUTH_STATE, credentials.authState.jsonSerializeString())
+ accountManager.setUserData(account, KEY_CERTIFICATE_ALIAS, credentials.certificateAlias)
+ }
+
}
@@ -498,6 +534,16 @@ class AccountSettings(
edit.remove(overrideProxyPort)
}
edit.apply()
+
+ setGroupMethod(GroupMethod.CATEGORIES)
+ val service = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CARDDAV)
+ if (service != null) {
+ for (collection in db.collectionDao().getByServiceAndSync(service.id)) {
+ if(collection.url.toString().contains(CONTACTS_APP_INTERACTION)) {
+ db.collectionDao().delete(collection)
+ }
+ }
+ }
}
@@ -730,7 +776,7 @@ class AccountSettings(
// request sync of new address book account
ContentResolver.setIsSyncable(account, context.getString(R.string.address_books_authority), 1)
- setSyncInterval(context.getString(R.string.address_books_authority), 4*3600)
+ setSyncInterval(context.getString(R.string.address_books_authority), Constants.DEFAULT_CONTACTS_SYNC_INTERVAL)
}
/* Android 7.1.1 OpenTasks fix */
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountsUpdatedListener.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountsUpdatedListener.kt
index 68804cb70514023f6077a67993f5f5217890d17b..d38040f6061e0a8737072dab576651d5c7b339cc 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountsUpdatedListener.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountsUpdatedListener.kt
@@ -68,34 +68,41 @@ class AccountsUpdatedListener private constructor(
@Synchronized
private fun cleanupAccounts(context: Context, accounts: Array) {
- Logger.log.log(Level.INFO, "Cleaning up accounts. Current accounts:", accounts)
+ Logger.log.log(Level.INFO, "Cleaning up accounts. Current accounts")
- val mainAccountType = context.getString(R.string.account_type)
- val mainAccountNames = accounts
- .filter { account -> account.type == mainAccountType }
- .map { it.name }
+ val accountManager = AccountManager.get(context)
+ val accountNames = HashSet()
+ val accountFromManager = ArrayList()
- val addressBookAccountType = context.getString(R.string.account_type_address_book)
- val addressBooks = accounts
- .filter { account -> account.type == addressBookAccountType }
- .map { addressBookAccount -> LocalAddressBook(context, addressBookAccount, null) }
- for (addressBook in addressBooks) {
- try {
- if (!mainAccountNames.contains(addressBook.mainAccount.name))
- // the main account for this address book doesn't exist anymore
- addressBook.delete()
- } catch(e: Exception) {
- Logger.log.log(Level.SEVERE, "Couldn't delete address book account", e)
- }
+ accountManager.getAccountsByType(context.getString(R.string.eelo_account_type)).forEach { accountFromManager.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.google_account_type)).forEach { accountFromManager.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type)).forEach { accountFromManager.add(it) }
+
+ for (account in accountFromManager.toTypedArray()) {
+ accountNames += account.name
}
+ // delete orphaned address book accounts
+ val addressBookAccounts = ArrayList()
+ accountManager.getAccountsByType(context.getString(R.string.account_type_eelo_address_book)).forEach { addressBookAccounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type_google_address_book)).forEach { addressBookAccounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type_address_book)).forEach { addressBookAccounts.add(it) }
+ addressBookAccounts.map { LocalAddressBook(context, it, null) }
+ .forEach {
+ try {
+ if (!accountNames.contains(it.mainAccount.name))
+ it.delete()
+ } catch(e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't delete address book account", e)
+ }
+ }
+
// delete orphaned services in DB
val db = EntryPointAccessors.fromApplication(context, AccountsUpdatedListenerEntryPoint::class.java).appDatabase()
val serviceDao = db.serviceDao()
- if (mainAccountNames.isEmpty())
+ if (accountNames.isEmpty())
serviceDao.deleteAll()
else
- serviceDao.deleteExceptAccounts(mainAccountNames.toTypedArray())
+ serviceDao.deleteExceptAccounts(accountNames.toTypedArray())
}
-
}
\ No newline at end of file
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt
index 275ab782ca025bb86f85d394a3972075227f485b..3996eb2e4c5c6863e044a73a91346b050d0b8b56 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt
@@ -108,7 +108,7 @@ class AddressBooksSyncAdapterService : SyncAdapterService() {
// create new local address books
for ((_, info) in remoteAddressBooks) {
Logger.log.log(Level.INFO, "Adding local address book", info)
- LocalAddressBook.create(context, contactsProvider, account, info)
+ LocalAddressBook.create(context, db, contactsProvider, account, info)
}
} finally {
contactsProvider?.closeCompat()
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.kt
index c384005515b7185b0ab41549d1408bd1074452b2..30839b784176d7deff67f7c27501dc64f526c7eb 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.kt
@@ -22,7 +22,7 @@ import at.bitfire.davdroid.resource.LocalCalendar
import at.bitfire.davdroid.resource.LocalEvent
import at.bitfire.davdroid.resource.LocalResource
import at.bitfire.davdroid.settings.AccountSettings
-import at.bitfire.ical4android.DateUtils
+import at.bitfire.ical4android.util.DateUtils
import at.bitfire.ical4android.Event
import at.bitfire.ical4android.InvalidCalendarException
import net.fortuna.ical4j.model.Component
@@ -55,7 +55,7 @@ class CalendarSyncManager(
override fun prepare(): Boolean {
collectionURL = (localCollection.name ?: return false).toHttpUrlOrNull() ?: return false
- davCollection = DavCalendar(httpClient.okHttpClient, collectionURL)
+ davCollection = DavCalendar(httpClient.okHttpClient, collectionURL, accountSettings.credentials().authState?.accessToken)
// if there are dirty exceptions for events, mark their master events as dirty, too
localCollection.processDirtyExceptions()
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.kt
index 83633b5ba525045d54c2c6b7f2813b317da9b906..67b16cb8c3f84384744610828acd0af97f93153e 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.kt
@@ -9,15 +9,18 @@ import android.content.ContentResolver
import android.content.Context
import android.content.SyncResult
import android.os.Bundle
+import android.os.AsyncTask
import android.provider.CalendarContract
import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
+import at.bitfire.davdroid.db.Credentials
import at.bitfire.davdroid.db.Service
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalCalendar
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.ical4android.AndroidCalendar
+import net.openid.appauth.AuthorizationService
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import java.util.logging.Level
@@ -60,7 +63,42 @@ class CalendarsSyncAdapterService: SyncAdapterService() {
for (calendar in calendars) {
Logger.log.info("Synchronizing calendar #${calendar.id}, URL: ${calendar.name}")
CalendarSyncManager(context, account, accountSettings, extras, httpClient.value, authority, syncResult, calendar).let {
- it.performSync()
+ val authState = accountSettings.credentials().authState
+ if (authState != null) {
+ if (authState.needsTokenRefresh) {
+ val tokenRequest = authState.createTokenRefreshRequest()
+
+ AuthorizationService(context).performTokenRequest(tokenRequest) { tokenResponse, ex ->
+ authState.update(tokenResponse, ex)
+ accountSettings.credentials(
+ Credentials(
+ account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ it.accountSettings.credentials(
+ Credentials(
+ it.account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ object : AsyncTask() {
+ override fun doInBackground(vararg params: Void): Void? {
+ it.performSync()
+ return null
+ }
+ }.execute()
+ }
+ } else {
+ it.performSync()
+ }
+ } else {
+ it.performSync()
+ }
}
}
} catch(e: Exception) {
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.kt
index 454d06535ea4f0420dfb2bb12aa49d5b6435bf87..5de00c3d1cd273fabea671266d7d4afe80ab7c8b 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncAdapterService.kt
@@ -9,13 +9,16 @@ import android.content.ContentProviderClient
import android.content.ContentResolver
import android.content.Context
import android.content.SyncResult
+import android.os.AsyncTask
import android.os.Bundle
import android.provider.ContactsContract
import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.db.Credentials
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.settings.AccountSettings
+import net.openid.appauth.AuthorizationService
import java.util.logging.Level
class ContactsSyncAdapterService: SyncAdapterService() {
@@ -64,7 +67,42 @@ class ContactsSyncAdapterService: SyncAdapterService() {
Logger.log.info("Taking settings from: ${addressBook.mainAccount}")
ContactsSyncManager(context, account, accountSettings, httpClient.value, extras, authority, syncResult, provider, addressBook).let {
- it.performSync()
+ val authState = accountSettings.credentials().authState
+ if (authState != null) {
+ if (authState.needsTokenRefresh) {
+ val tokenRequest = authState.createTokenRefreshRequest()
+
+ AuthorizationService(context).performTokenRequest(tokenRequest) { tokenResponse, ex ->
+ authState.update(tokenResponse, ex)
+ accountSettings.credentials(
+ Credentials(
+ account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ it.accountSettings.credentials(
+ Credentials(
+ it.account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ object : AsyncTask() {
+ override fun doInBackground(vararg params: Void): Void? {
+ it.performSync()
+ return null
+ }
+ }.execute()
+ }
+ } else {
+ it.performSync()
+ }
+ } else {
+ it.performSync()
+ }
}
} catch(e: Exception) {
Logger.log.log(Level.SEVERE, "Couldn't sync contacts", e)
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.kt
index 2401a0a0d7adaf4141f13d94c961eee80d669f32..85b04623085f63e540019b25db07ac206787aa98 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.kt
@@ -95,6 +95,7 @@ class ContactsSyncManager(
}
private val readOnly = localAddressBook.readOnly
+ private val accessToken: String? = accountSettings.credentials().authState?.accessToken
private var hasVCard4 = false
private var hasJCard = false
@@ -121,7 +122,7 @@ class ContactsSyncManager(
}
collectionURL = localCollection.url.toHttpUrlOrNull() ?: return false
- davCollection = DavAddressBook(httpClient.okHttpClient, collectionURL)
+ davCollection = DavAddressBook(httpClient.okHttpClient, collectionURL, accountSettings.credentials().authState?.accessToken)
resourceDownloader = ResourceDownloader(davCollection.location)
@@ -377,10 +378,17 @@ class ContactsSyncManager(
.build()
try {
- val response = client.okHttpClient.newCall(Request.Builder()
- .get()
- .url(httpUrl)
- .build()).execute()
+ val requestBuilder = Request.Builder()
+ .get()
+ .url(httpUrl)
+
+ if (!accessToken.isNullOrEmpty()) {
+ requestBuilder.header("Authorization", "Bearer $accessToken")
+ }
+
+ val response = client.okHttpClient.newCall(requestBuilder
+ .build())
+ .execute()
if (response.isSuccessful)
return response.body?.bytes()
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloAccountAuthenticatorService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloAccountAuthenticatorService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f9d71fd4c53dd04db278e12c502b011ae76784f1
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloAccountAuthenticatorService.kt
@@ -0,0 +1,195 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.*
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import at.bitfire.davdroid.R
+import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.log.Logger
+import at.bitfire.davdroid.resource.LocalAddressBook
+import at.bitfire.davdroid.ui.setup.LoginActivity
+import dagger.hilt.android.EntryPointAccessors
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import java.util.logging.Level
+
+/**
+ * Account authenticator for the eelo account type.
+ *
+ * Gets started when an eelo account is removed, too, so it also watches for account removals
+ * and contains the corresponding cleanup code.
+ */
+
+class EeloAccountAuthenticatorService : Service(), OnAccountsUpdateListener {
+
+ companion object {
+
+ fun cleanupAccounts(context: Context, db: AppDatabase) {
+ Logger.log.info("Cleaning up orphaned accounts")
+
+ val accountManager = AccountManager.get(context)
+
+ val accountNames = HashSet()
+
+ val accounts = ArrayList()
+ accountManager.getAccountsByType(context.getString(R.string.eelo_account_type))
+ .forEach { accounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.google_account_type))
+ .forEach { accounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type))
+ .forEach { accounts.add(it) }
+
+ for (account in accounts.toTypedArray()) {
+ accountNames += account.name
+ }
+
+ // delete orphaned address book accounts
+ val addressBookAccounts = ArrayList()
+ accountManager.getAccountsByType(context.getString(R.string.account_type_eelo_address_book))
+ .forEach { addressBookAccounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type_google_address_book))
+ .forEach { addressBookAccounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type_address_book))
+ .forEach { addressBookAccounts.add(it) }
+ addressBookAccounts.map { LocalAddressBook(context, it, null) }
+ .forEach {
+ try {
+ if (!accountNames.contains(it.mainAccount.name))
+ it.delete()
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't delete address book account", e)
+ }
+ }
+
+ // delete orphaned services in DB
+ val serviceDao = db.serviceDao()
+ if (accountNames.isEmpty())
+ serviceDao.deleteAll()
+ else
+ serviceDao.deleteExceptAccounts(accountNames.toTypedArray())
+ }
+
+ }
+
+ private lateinit var accountManager: AccountManager
+ private lateinit var accountAuthenticator: AccountAuthenticator
+
+ override fun onCreate() {
+ accountManager = AccountManager.get(this)
+ accountManager.addOnAccountsUpdatedListener(this, null, true)
+
+ accountAuthenticator = AccountAuthenticator(this)
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ accountManager.removeOnAccountsUpdatedListener(this)
+ }
+
+ override fun onBind(intent: Intent?) =
+ accountAuthenticator.iBinder.takeIf { intent?.action == AccountManager.ACTION_AUTHENTICATOR_INTENT }
+
+ override fun onAccountsUpdated(accounts: Array?) {
+ /* onAccountsUpdated may be called from the main thread, but cleanupAccounts
+ requires disk (database) access. So we launch it in a separate thread. */
+ CoroutineScope(Dispatchers.Default).launch {
+ val db = EntryPointAccessors.fromApplication(
+ applicationContext,
+ AccountsUpdatedListener.AccountsUpdatedListenerEntryPoint::class.java
+ ).appDatabase()
+
+ cleanupAccounts(applicationContext, db)
+
+ val eeloAccounts = ArrayList(accounts?.asList() ?: emptyList())
+ eeloAccounts.removeIf { it.type != getString(R.string.eelo_account_type) }
+ eeloAccounts.removeAll(
+ accountManager.getAccountsByType(
+ getString(
+ R.string.eelo_account_type
+ )
+ ).toSet()
+ )
+
+ for (removedAccount in eeloAccounts) {
+ val intent = Intent("drive.services.ResetService")
+ intent.setPackage(getString(R.string.e_drive_package_name))
+ intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, removedAccount.name)
+ intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, removedAccount.type)
+ startService(intent)
+ }
+ }
+ }
+
+ private class AccountAuthenticator(
+ val context: Context
+ ) : AbstractAccountAuthenticator(context) {
+
+ override fun addAccount(
+ response: AccountAuthenticatorResponse?,
+ accountType: String?,
+ authTokenType: String?,
+ requiredFeatures: Array?,
+ options: Bundle?
+ ): Bundle {
+ val intent = Intent(context, LoginActivity::class.java)
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response)
+ intent.putExtra(
+ LoginActivity.SETUP_ACCOUNT_PROVIDER_TYPE,
+ LoginActivity.ACCOUNT_PROVIDER_EELO
+ )
+ val bundle = Bundle(1)
+ bundle.putParcelable(AccountManager.KEY_INTENT, intent)
+ return bundle
+ }
+
+ override fun editProperties(response: AccountAuthenticatorResponse?, accountType: String?) =
+ null
+
+ override fun getAuthTokenLabel(p0: String?) = null
+
+ override fun confirmCredentials(
+ p0: AccountAuthenticatorResponse?,
+ p1: Account?,
+ p2: Bundle?
+ ) = null
+
+ override fun updateCredentials(
+ p0: AccountAuthenticatorResponse?,
+ p1: Account?,
+ p2: String?,
+ p3: Bundle?
+ ) = null
+
+ override fun getAuthToken(
+ response: AccountAuthenticatorResponse?,
+ account: Account?,
+ authTokenType: String?,
+ options: Bundle?
+ ) = null
+
+ override fun hasFeatures(
+ p0: AccountAuthenticatorResponse?,
+ p1: Account?,
+ p2: Array?
+ ) = null
+ }
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloAddressBooksSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloAddressBooksSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..cac6e633c9a7e3c9d67f998de784e52118741c05
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloAddressBooksSyncAdapterService.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.Manifest
+import android.accounts.Account
+import android.content.*
+import android.content.pm.PackageManager
+import android.os.Bundle
+import android.provider.ContactsContract
+import androidx.core.content.ContextCompat
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.PermissionUtils
+import at.bitfire.davdroid.closeCompat
+import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.db.Collection
+import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
+import at.bitfire.davdroid.resource.LocalAddressBook
+import at.bitfire.davdroid.settings.AccountSettings
+import at.bitfire.davdroid.ui.account.AccountActivity
+import okhttp3.HttpUrl
+import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
+import java.util.logging.Level
+
+class EeloAddressBooksSyncAdapterService : SyncAdapterService() {
+
+ override fun syncAdapter() = AddressBooksSyncAdapter(this, appDatabase)
+
+ class AddressBooksSyncAdapter(
+ context: Context,
+ db: AppDatabase
+ ) : SyncAdapter(context, db) {
+
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ try {
+ val accountSettings = AccountSettings(context, account)
+
+ /* don't run sync if
+ - sync conditions (e.g. "sync only in WiFi") are not met AND
+ - this is is an automatic sync (i.e. manual syncs are run regardless of sync conditions)
+ */
+ if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(
+ accountSettings
+ )
+ )
+ return
+
+ if (updateLocalAddressBooks(account, syncResult))
+ for (addressBookAccount in LocalAddressBook.findAll(context, null, account)
+ .map { it.account }) {
+ Logger.log.log(
+ Level.INFO,
+ "Running sync for address book",
+ addressBookAccount
+ )
+ val syncExtras = Bundle(extras)
+ syncExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true)
+ syncExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true)
+ ContentResolver.requestSync(
+ addressBookAccount,
+ ContactsContract.AUTHORITY,
+ syncExtras
+ )
+ }
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't sync address books", e)
+ }
+
+ Logger.log.info("Address book sync complete")
+ }
+
+ private fun updateLocalAddressBooks(account: Account, syncResult: SyncResult): Boolean {
+ val service = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CARDDAV)
+
+ val remoteAddressBooks = mutableMapOf()
+ if (service != null)
+ for (collection in db.collectionDao().getByServiceAndSync(service.id)) {
+ if(collection.url.toString().contains(AccountSettings.CONTACTS_APP_INTERACTION)) {
+ db.collectionDao().delete(collection)
+ }
+ remoteAddressBooks[collection.url] = collection
+ }
+
+ if (ContextCompat.checkSelfPermission(
+ context,
+ Manifest.permission.WRITE_CONTACTS
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ if (remoteAddressBooks.isEmpty())
+ Logger.log.info("No contacts permission, but no address book selected for synchronization")
+ else {
+ // no contacts permission, but address books should be synchronized -> show notification
+ val intent = Intent(context, AccountActivity::class.java)
+ intent.putExtra(AccountActivity.EXTRA_ACCOUNT, account)
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ PermissionUtils.notifyPermissions(context, intent)
+ }
+ return false
+ }
+
+ val contactsProvider =
+ context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY)
+ try {
+ if (contactsProvider == null) {
+ Logger.log.severe("Couldn't access contacts provider")
+ syncResult.databaseError = true
+ return false
+ }
+
+ // delete/update local address books
+ for (addressBook in LocalAddressBook.findAll(context, contactsProvider, account)) {
+ val url = addressBook.url.toHttpUrlOrNull()!!
+ val info = remoteAddressBooks[url]
+ if (info == null) {
+ Logger.log.log(Level.INFO, "Deleting obsolete local address book", url)
+ addressBook.delete()
+ } else {
+ // remote CollectionInfo found for this local collection, update data
+ try {
+ Logger.log.log(Level.FINE, "Updating local address book $url", info)
+ addressBook.update(info)
+ } catch (e: Exception) {
+ Logger.log.log(Level.WARNING, "Couldn't rename address book account", e)
+ }
+ // we already have a local address book for this remote collection, don't take into consideration anymore
+ remoteAddressBooks -= url
+ }
+ }
+
+ // create new local address books
+ for ((_, info) in remoteAddressBooks) {
+ Logger.log.log(Level.INFO, "Adding local address book", info)
+ LocalAddressBook.create(context, db, contactsProvider, account, info)
+ }
+ } finally {
+ contactsProvider?.closeCompat()
+ }
+
+ return true
+ }
+
+ }
+
+}
+
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloAppDataSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloAppDataSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0136139b65addfdae6732526315177e4e2513b1f
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloAppDataSyncAdapterService.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.content.*
+import android.os.Bundle
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.db.AppDatabase
+
+class EeloAppDataSyncAdapterService : SyncAdapterService() {
+
+ override fun syncAdapter() = EeloAppDataSyncAdapter(this, appDatabase)
+
+ class EeloAppDataSyncAdapter(
+ context: Context,
+ db: AppDatabase
+ ): SyncAdapter(context, db) {
+
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ // Unused
+ }
+ }
+}
+
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloCalendarsSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloCalendarsSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..26e1a9f044d7aefc59884abc74068eabf0e48498
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloCalendarsSyncAdapterService.kt
@@ -0,0 +1,192 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.content.ContentProviderClient
+import android.content.ContentResolver
+import android.content.Context
+import android.content.SyncResult
+import android.os.AsyncTask
+import android.os.Bundle
+import android.provider.CalendarContract
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.db.Collection
+import at.bitfire.davdroid.db.Credentials
+import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
+import at.bitfire.davdroid.resource.LocalCalendar
+import at.bitfire.davdroid.settings.AccountSettings
+import at.bitfire.ical4android.AndroidCalendar
+import net.openid.appauth.AuthorizationService
+import okhttp3.HttpUrl
+import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
+import java.util.logging.Level
+
+class EeloCalendarsSyncAdapterService : SyncAdapterService() {
+
+ override fun syncAdapter() = CalendarsSyncAdapter(this, appDatabase)
+
+ class CalendarsSyncAdapter(
+ context: Context,
+ appDatabase: AppDatabase
+ ) : SyncAdapter(context, appDatabase) {
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ try {
+ val accountSettings = AccountSettings(context, account)
+
+ /* don't run sync if
+ - sync conditions (e.g. "sync only in WiFi") are not met AND
+ - this is is an automatic sync (i.e. manual syncs are run regardless of sync conditions)
+ */
+ if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(
+ accountSettings
+ )
+ )
+ return
+
+ if (accountSettings.getEventColors())
+ AndroidCalendar.insertColors(provider, account)
+ else
+ AndroidCalendar.removeColors(provider, account)
+
+ updateLocalCalendars(provider, account, accountSettings)
+
+ val priorityCalendars = priorityCollections(extras)
+ val calendars = AndroidCalendar
+ .find(
+ account,
+ provider,
+ LocalCalendar.Factory,
+ "${CalendarContract.Calendars.SYNC_EVENTS}!=0",
+ null
+ )
+ .sortedByDescending { priorityCalendars.contains(it.id) }
+ for (calendar in calendars) {
+ Logger.log.info("Synchronizing calendar #${calendar.id}, URL: ${calendar.name}")
+ CalendarSyncManager(
+ context,
+ account,
+ accountSettings,
+ extras,
+ httpClient.value,
+ authority,
+ syncResult,
+ calendar
+ ).let {
+ val authState = accountSettings.credentials().authState
+ if (authState != null) {
+ if (authState.needsTokenRefresh) {
+ val tokenRequest = authState.createTokenRefreshRequest()
+
+ AuthorizationService(context).performTokenRequest(tokenRequest) { tokenResponse, ex ->
+ authState.update(tokenResponse, ex)
+ accountSettings.credentials(
+ Credentials(
+ account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ it.accountSettings.credentials(
+ Credentials(
+ it.account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ object : AsyncTask() {
+ override fun doInBackground(vararg params: Void): Void? {
+ it.performSync()
+ return null
+ }
+ }.execute()
+ }
+ } else {
+ it.performSync()
+ }
+ } else {
+ it.performSync()
+ }
+ }
+ }
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't sync calendars", e)
+ }
+ Logger.log.info("Calendar sync complete")
+ }
+
+ private fun updateLocalCalendars(
+ provider: ContentProviderClient,
+ account: Account,
+ settings: AccountSettings
+ ) {
+ val service = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CALDAV)
+
+ val remoteCalendars = mutableMapOf()
+
+ if (service != null) {
+ for (collection in db.collectionDao().getSyncCalendars(service.id)) {
+ remoteCalendars[collection.url] = collection
+ }
+ }
+
+ // delete/update local calendars
+ val updateColors = settings.getManageCalendarColors()
+ for (calendar in AndroidCalendar.find(
+ account,
+ provider,
+ LocalCalendar.Factory,
+ null,
+ null
+ ))
+ calendar.name?.let {
+ val url = it.toHttpUrlOrNull()!!
+ val info = remoteCalendars[url]
+
+ if (info == null) {
+ Logger.log.log(Level.INFO, "Deleting obsolete local calendar", url)
+ calendar.delete()
+ } else {
+ // remote CollectionInfo found for this local collection, update data
+ Logger.log.log(Level.FINE, "Updating local calendar $url", info)
+ calendar.update(info, updateColors)
+ // we already have a local calendar for this remote collection, don't take into consideration anymore
+ remoteCalendars -= url
+ }
+ }
+
+ // create new local calendars
+ for ((_, info) in remoteCalendars) {
+ Logger.log.log(Level.INFO, "Adding local calendar", info)
+ LocalCalendar.create(account, provider, info)
+ }
+ }
+
+ }
+}
+
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloContactsSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloContactsSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b5c0419d8984679be71d63cfc670c859806696cb
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloContactsSyncAdapterService.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.content.ContentProviderClient
+import android.content.ContentResolver
+import android.content.Context
+import android.content.SyncResult
+import android.os.Bundle
+import android.provider.ContactsContract
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.log.Logger
+import at.bitfire.davdroid.resource.LocalAddressBook
+import at.bitfire.davdroid.settings.AccountSettings
+import java.util.logging.Level
+
+class EeloContactsSyncAdapterService: SyncAdapterService() {
+
+ companion object {
+ const val PREVIOUS_GROUP_METHOD = "previous_group_method"
+ }
+
+ override fun syncAdapter() = ContactsSyncAdapter(this, appDatabase)
+
+
+ class ContactsSyncAdapter(
+ context: Context,
+ db: AppDatabase
+ ): SyncAdapter(context, db) {
+
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ try {
+ val addressBook = LocalAddressBook(context, account, provider)
+ val accountSettings = AccountSettings(context, addressBook.mainAccount)
+
+ // handle group method change
+ val groupMethod = accountSettings.getGroupMethod().name
+ accountSettings.accountManager.getUserData(account, PREVIOUS_GROUP_METHOD)?.let { previousGroupMethod ->
+ if (previousGroupMethod != groupMethod) {
+ Logger.log.info("Group method changed, deleting all local contacts/groups")
+
+ // delete all local contacts and groups so that they will be downloaded again
+ provider.delete(addressBook.syncAdapterURI(ContactsContract.RawContacts.CONTENT_URI), null, null)
+ provider.delete(addressBook.syncAdapterURI(ContactsContract.Groups.CONTENT_URI), null, null)
+
+ // reset sync state
+ addressBook.syncState = null
+ }
+ }
+ accountSettings.accountManager.setUserData(account, PREVIOUS_GROUP_METHOD, groupMethod)
+
+ /* don't run sync if
+ - sync conditions (e.g. "sync only in WiFi") are not met AND
+ - this is is an automatic sync (i.e. manual syncs are run regardless of sync conditions)
+ */
+ if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(accountSettings))
+ return
+
+ Logger.log.info("Synchronizing address book: ${addressBook.url}")
+ Logger.log.info("Taking settings from: ${addressBook.mainAccount}")
+
+ ContactsSyncManager(context, account, accountSettings, httpClient.value, extras, authority, syncResult, provider, addressBook).let {
+ it.performSync()
+ }
+ } catch(e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't sync contacts", e)
+ }
+ Logger.log.info("Contacts sync complete")
+ }
+ }
+}
+
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloEmailSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloEmailSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ea1319c3b25595563a6d920e4f40fe01ce9fee02
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloEmailSyncAdapterService.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.content.*
+import android.os.Bundle
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.db.AppDatabase
+
+class EeloEmailSyncAdapterService : SyncAdapterService() {
+
+ override fun syncAdapter() = EeloEmailSyncAdapter(this, appDatabase)
+
+
+ class EeloEmailSyncAdapter(
+ context: Context,
+ db: AppDatabase
+ ): SyncAdapter(context, db) {
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ // Unused
+ }
+ }
+}
+
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloMediaSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloMediaSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..e7af69c3e668e5d58d0887e06d4896ecbba4bdcd
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloMediaSyncAdapterService.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.content.*
+import android.os.Bundle
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.db.AppDatabase
+
+class EeloMediaSyncAdapterService : SyncAdapterService() {
+
+ override fun syncAdapter() = EeloMediaSyncAdapter(this, appDatabase)
+
+
+ class EeloMediaSyncAdapter(
+ context: Context,
+ db: AppDatabase
+ ): SyncAdapter(context, db) {
+
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ // Unused
+ }
+ }
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloMeteredEdriveSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloMeteredEdriveSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2702a7a4c42b6e2579a078c638456d0b2e073608
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloMeteredEdriveSyncAdapterService.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.content.ContentProviderClient
+import android.content.Context
+import android.content.SyncResult
+import android.os.Bundle
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.db.AppDatabase
+
+class EeloMeteredEdriveSyncAdapterService : SyncAdapterService() {
+
+ override fun syncAdapter() = EeloMeteredEdriveSyncAdapter(this, appDatabase)
+
+ class EeloMeteredEdriveSyncAdapter(
+ context: Context,
+ db: AppDatabase
+ ): SyncAdapter(context, db) {
+
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ // Unused
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloNotesSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloNotesSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..86a1daa897f51c01d0184e166f1fab6600d8d405
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloNotesSyncAdapterService.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.content.*
+import android.os.Bundle
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.db.AppDatabase
+
+class EeloNotesSyncAdapterService : SyncAdapterService() {
+
+ override fun syncAdapter() = EeloNotesSyncAdapter(this, appDatabase)
+
+ class EeloNotesSyncAdapter(
+ context: Context,
+ db: AppDatabase
+ ): SyncAdapter(context, db) {
+
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ // Unused
+ }
+ }
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloNullAuthenticatorService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloNullAuthenticatorService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..58367a45a433170ebd315a53beb14c7c5042e0e7
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloNullAuthenticatorService.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.AbstractAccountAuthenticator
+import android.accounts.Account
+import android.accounts.AccountAuthenticatorResponse
+import android.accounts.AccountManager
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import at.bitfire.davdroid.ui.AccountsActivity
+
+class EeloNullAuthenticatorService: Service() {
+
+ private lateinit var accountAuthenticator: AccountAuthenticator
+
+ override fun onCreate() {
+ accountAuthenticator = AccountAuthenticator(this)
+ }
+
+ override fun onBind(intent: Intent?) =
+ accountAuthenticator.iBinder.takeIf { intent?.action == AccountManager.ACTION_AUTHENTICATOR_INTENT }
+
+
+ private class AccountAuthenticator(
+ val context: Context
+ ): AbstractAccountAuthenticator(context) {
+
+ override fun addAccount(response: AccountAuthenticatorResponse?, accountType: String?, authTokenType: String?, requiredFeatures: Array?, options: Bundle?): Bundle {
+ val intent = Intent(context, AccountsActivity::class.java)
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response)
+ val bundle = Bundle(1)
+ bundle.putParcelable(AccountManager.KEY_INTENT, intent)
+ return bundle
+ }
+
+ override fun editProperties(response: AccountAuthenticatorResponse?, accountType: String?) = null
+ override fun getAuthTokenLabel(p0: String?) = null
+ override fun confirmCredentials(p0: AccountAuthenticatorResponse?, p1: Account?, p2: Bundle?) = null
+ override fun updateCredentials(p0: AccountAuthenticatorResponse?, p1: Account?, p2: String?, p3: Bundle?) = null
+ override fun getAuthToken(p0: AccountAuthenticatorResponse?, p1: Account?, p2: String?, p3: Bundle?) = null
+ override fun hasFeatures(p0: AccountAuthenticatorResponse?, p1: Account?, p2: Array?) = null
+ }
+}
+
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloTasksSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloTasksSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2dbbd4c8016eb7b36723a8b63b8fbf88ac89b946
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/EeloTasksSyncAdapterService.kt
@@ -0,0 +1,203 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.accounts.AccountManager
+import android.content.ContentProviderClient
+import android.content.ContentResolver
+import android.content.Context
+import android.content.SyncResult
+import android.os.AsyncTask
+import android.os.Build
+import android.os.Bundle
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.db.Collection
+import at.bitfire.davdroid.db.Credentials
+import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
+import at.bitfire.davdroid.resource.LocalTaskList
+import at.bitfire.davdroid.settings.AccountSettings
+import at.bitfire.ical4android.AndroidTaskList
+import at.bitfire.ical4android.TaskProvider
+import net.openid.appauth.AuthorizationService
+import okhttp3.HttpUrl
+import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
+import org.dmfs.tasks.contract.TaskContract
+import java.util.logging.Level
+
+
+/**
+ * Synchronization manager for CalDAV collections; handles tasks ({@code VTODO}).
+ */
+class EeloTasksSyncAdapterService : SyncAdapterService() {
+
+ override fun syncAdapter() = TasksSyncAdapter(this, appDatabase)
+
+
+ class TasksSyncAdapter(
+ context: Context,
+ appDatabase: AppDatabase
+ ) : SyncAdapter(context, appDatabase) {
+
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ try {
+ val providerName = TaskProvider.ProviderName.fromAuthority(authority)
+ val taskProvider = TaskProvider.fromProviderClient(context, providerName, provider)
+
+ // make sure account can be seen by OpenTasks
+ if (Build.VERSION.SDK_INT >= 26)
+ AccountManager.get(context).setAccountVisibility(
+ account,
+ taskProvider.name.packageName,
+ AccountManager.VISIBILITY_VISIBLE
+ )
+
+ val accountSettings = AccountSettings(context, account)
+ /* don't run sync if
+ - sync conditions (e.g. "sync only in WiFi") are not met AND
+ - this is is an automatic sync (i.e. manual syncs are run regardless of sync conditions)
+ */
+ if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(
+ accountSettings
+ )
+ )
+ return
+
+ updateLocalTaskLists(taskProvider, account, accountSettings)
+
+ val priorityTaskLists = priorityCollections(extras)
+ val taskLists = AndroidTaskList
+ .find(
+ account,
+ taskProvider,
+ LocalTaskList.Factory,
+ "${TaskContract.TaskLists.SYNC_ENABLED}!=0",
+ null
+ )
+ .sortedByDescending { priorityTaskLists.contains(it.id) }
+ for (taskList in taskLists) {
+ Logger.log.info("Synchronizing task list #${taskList.id} [${taskList.syncId}]")
+ TasksSyncManager(
+ context,
+ account,
+ accountSettings,
+ httpClient.value,
+ extras,
+ authority,
+ syncResult,
+ taskList
+ ).let {
+ val authState = accountSettings.credentials().authState
+ if (authState != null) {
+ if (authState.needsTokenRefresh) {
+ val tokenRequest = authState.createTokenRefreshRequest()
+
+ AuthorizationService(context).performTokenRequest(tokenRequest,
+ AuthorizationService.TokenResponseCallback { tokenResponse, ex ->
+ authState.update(tokenResponse, ex)
+ accountSettings.credentials(
+ Credentials(
+ account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ it.accountSettings.credentials(
+ Credentials(
+ it.account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ object : AsyncTask() {
+ override fun doInBackground(vararg params: Void): Void? {
+ it.performSync()
+ return null
+ }
+ }.execute()
+ })
+ } else {
+ it.performSync()
+ }
+ } else {
+ it.performSync()
+ }
+ }
+ }
+ } catch (e: TaskProvider.ProviderTooOldException) {
+ SyncUtils.notifyProviderTooOld(context, e)
+ syncResult.databaseError = true
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't sync task lists", e)
+ syncResult.databaseError = true
+ }
+
+ Logger.log.info("Task sync complete")
+ }
+
+ private fun updateLocalTaskLists(
+ provider: TaskProvider,
+ account: Account,
+ settings: AccountSettings
+ ) {
+ val service = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CALDAV)
+
+ val remoteTaskLists = mutableMapOf()
+ if (service != null)
+ for (collection in db.collectionDao().getSyncTaskLists(service.id)) {
+ remoteTaskLists[collection.url] = collection
+ }
+
+ // delete/update local task lists
+ val updateColors = settings.getManageCalendarColors()
+
+ for (list in AndroidTaskList.find(account, provider, LocalTaskList.Factory, null, null))
+ list.syncId?.let {
+ val url = it.toHttpUrlOrNull()!!
+ val info = remoteTaskLists[url]
+ if (info == null) {
+ Logger.log.fine("Deleting obsolete local task list $url")
+ list.delete()
+ } else {
+ // remote CollectionInfo found for this local collection, update data
+ Logger.log.log(Level.FINE, "Updating local task list $url", info)
+ list.update(info, updateColors)
+ // we already have a local task list for this remote collection, don't take into consideration anymore
+ remoteTaskLists -= url
+ }
+ }
+
+ // create new local task lists
+ for ((_, info) in remoteTaskLists) {
+ Logger.log.log(Level.INFO, "Adding local task list", info)
+ LocalTaskList.create(account, provider, info)
+ }
+ }
+
+ }
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleAccountAuthenticatorService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleAccountAuthenticatorService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..82fe2de0f648ed0e9eacd48272a44dc03b6d9f7f
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleAccountAuthenticatorService.kt
@@ -0,0 +1,218 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.*
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import at.bitfire.davdroid.R
+import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.log.Logger
+import at.bitfire.davdroid.resource.LocalAddressBook
+import at.bitfire.davdroid.settings.AccountSettings
+import at.bitfire.davdroid.ui.setup.LoginActivity
+import dagger.hilt.android.EntryPointAccessors
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import net.openid.appauth.AuthState
+import net.openid.appauth.AuthorizationService
+import java.util.logging.Level
+
+/**
+ * Account authenticator for the Google account type.
+ *
+ * Gets started when a Google account is removed, too, so it also watches for account removals
+ * and contains the corresponding cleanup code.
+ */
+
+class GoogleAccountAuthenticatorService : Service(), OnAccountsUpdateListener {
+
+ companion object {
+ fun cleanupAccounts(context: Context, db: AppDatabase) {
+ Logger.log.info("Cleaning up orphaned accounts")
+
+ val accountManager = AccountManager.get(context)
+
+ val accountNames = HashSet()
+ val accounts = ArrayList()
+ accountManager.getAccountsByType(context.getString(R.string.eelo_account_type))
+ .forEach { accounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.google_account_type))
+ .forEach { accounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type))
+ .forEach { accounts.add(it) }
+
+ for (account in accounts.toTypedArray()) {
+ accountNames += account.name
+ }
+
+ // delete orphaned address book accounts
+ val addressBookAccounts = ArrayList()
+ accountManager.getAccountsByType(context.getString(R.string.account_type_eelo_address_book))
+ .forEach { addressBookAccounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type_google_address_book))
+ .forEach { addressBookAccounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type_address_book))
+ .forEach { addressBookAccounts.add(it) }
+ addressBookAccounts.map { LocalAddressBook(context, it, null) }
+ .forEach {
+ try {
+ if (!accountNames.contains(it.mainAccount.name))
+ it.delete()
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't delete address book account", e)
+ }
+ }
+
+ // delete orphaned services in DB
+ val serviceDao = db.serviceDao()
+ if (accountNames.isEmpty())
+ serviceDao.deleteAll()
+ else
+ serviceDao.deleteExceptAccounts(accountNames.toTypedArray())
+ }
+
+ }
+
+ private lateinit var accountManager: AccountManager
+ private lateinit var accountAuthenticator: AccountAuthenticator
+
+ override fun onCreate() {
+ accountManager = AccountManager.get(this)
+ accountManager.addOnAccountsUpdatedListener(this, null, true)
+
+ accountAuthenticator = AccountAuthenticator(this)
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ accountManager.removeOnAccountsUpdatedListener(this)
+ }
+
+ override fun onBind(intent: Intent?) =
+ accountAuthenticator.iBinder.takeIf { intent?.action == AccountManager.ACTION_AUTHENTICATOR_INTENT }
+
+ override fun onAccountsUpdated(accounts: Array?) {
+ /* onAccountsUpdated may be called from the main thread, but cleanupAccounts
+ requires disk (database) access. So we launch it in a separate thread. */
+ CoroutineScope(Dispatchers.Default).launch {
+ val db = EntryPointAccessors.fromApplication(
+ applicationContext,
+ AccountsUpdatedListener.AccountsUpdatedListenerEntryPoint::class.java
+ ).appDatabase()
+
+ cleanupAccounts(applicationContext, db)
+ }
+ }
+
+ private class AccountAuthenticator(
+ val context: Context
+ ) : AbstractAccountAuthenticator(context) {
+
+ override fun addAccount(
+ response: AccountAuthenticatorResponse?,
+ accountType: String?,
+ authTokenType: String?,
+ requiredFeatures: Array?,
+ options: Bundle?
+ ): Bundle {
+ val intent = Intent(context, LoginActivity::class.java)
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response)
+ intent.putExtra(
+ LoginActivity.SETUP_ACCOUNT_PROVIDER_TYPE,
+ LoginActivity.ACCOUNT_PROVIDER_GOOGLE
+ )
+ val bundle = Bundle(1)
+ bundle.putParcelable(AccountManager.KEY_INTENT, intent)
+ return bundle
+ }
+
+ override fun editProperties(response: AccountAuthenticatorResponse?, accountType: String?) = null
+
+ override fun getAuthTokenLabel(p0: String?) = null
+
+ override fun confirmCredentials(
+ p0: AccountAuthenticatorResponse?,
+ p1: Account?,
+ p2: Bundle?
+ ) = null
+
+ override fun updateCredentials(
+ p0: AccountAuthenticatorResponse?,
+ p1: Account?,
+ p2: String?,
+ p3: Bundle?
+ ) = null
+
+ override fun getAuthToken(
+ response: AccountAuthenticatorResponse?,
+ account: Account?,
+ authTokenType: String?,
+ options: Bundle?
+ ): Bundle {
+ val accountManager = AccountManager.get(context)
+ val authState = AuthState.jsonDeserialize(
+ accountManager.getUserData(
+ account,
+ AccountSettings.KEY_AUTH_STATE
+ )
+ )
+
+ if (authState != null) {
+ if (authState.needsTokenRefresh) {
+ val tokenRequest = authState.createTokenRefreshRequest()
+
+ AuthorizationService(context).performTokenRequest(tokenRequest) { tokenResponse, ex ->
+ authState.update(tokenResponse, ex)
+ accountManager.setUserData(
+ account,
+ AccountSettings.KEY_AUTH_STATE,
+ authState.jsonSerializeString()
+ )
+ val result = Bundle()
+ result.putString(AccountManager.KEY_ACCOUNT_NAME, account!!.name)
+ result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type)
+ result.putString(AccountManager.KEY_AUTHTOKEN, authState.accessToken)
+ response?.onResult(result)
+ }
+ } else {
+ val result = Bundle()
+ result.putString(AccountManager.KEY_ACCOUNT_NAME, account!!.name)
+ result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type)
+ result.putString(AccountManager.KEY_AUTHTOKEN, authState.accessToken)
+ return result
+ }
+ }
+
+ val result = Bundle()
+ result.putInt(
+ AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
+ AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION
+ )
+ return result
+ }
+
+ override fun hasFeatures(
+ p0: AccountAuthenticatorResponse?,
+ p1: Account?,
+ p2: Array?
+ ) = null
+ }
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleAddressBooksSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleAddressBooksSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..128a26f660b8caca68d34833a07c71721b4aa2d9
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleAddressBooksSyncAdapterService.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.Manifest
+import android.accounts.Account
+import android.content.*
+import android.content.pm.PackageManager
+import android.os.Bundle
+import android.provider.ContactsContract
+import androidx.core.content.ContextCompat
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.PermissionUtils
+import at.bitfire.davdroid.closeCompat
+import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.db.Collection
+import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
+import at.bitfire.davdroid.resource.LocalAddressBook
+import at.bitfire.davdroid.settings.AccountSettings
+import at.bitfire.davdroid.ui.account.AccountActivity
+import okhttp3.HttpUrl
+import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
+import java.util.logging.Level
+
+class GoogleAddressBooksSyncAdapterService : SyncAdapterService() {
+
+ override fun syncAdapter() = AddressBooksSyncAdapter(this, appDatabase)
+
+ class AddressBooksSyncAdapter(
+ context: Context,
+ db: AppDatabase
+ ) : SyncAdapter(context, db) {
+
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ try {
+ val accountSettings = AccountSettings(context, account)
+
+ /* don't run sync if
+ - sync conditions (e.g. "sync only in WiFi") are not met AND
+ - this is is an automatic sync (i.e. manual syncs are run regardless of sync conditions)
+ */
+ if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(
+ accountSettings
+ )
+ )
+ return
+
+ if (updateLocalAddressBooks(account, syncResult))
+ for (addressBookAccount in LocalAddressBook.findAll(context, null, account)
+ .map { it.account }) {
+ Logger.log.log(
+ Level.INFO,
+ "Running sync for address book",
+ addressBookAccount
+ )
+ val syncExtras = Bundle(extras)
+ syncExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true)
+ syncExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true)
+ ContentResolver.requestSync(
+ addressBookAccount,
+ ContactsContract.AUTHORITY,
+ syncExtras
+ )
+ }
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't sync address books", e)
+ }
+
+ Logger.log.info("Address book sync complete")
+ }
+
+ private fun updateLocalAddressBooks(account: Account, syncResult: SyncResult): Boolean {
+ val service = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CARDDAV)
+
+ val remoteAddressBooks = mutableMapOf()
+ if (service != null)
+ for (collection in db.collectionDao().getByServiceAndSync(service.id))
+ remoteAddressBooks[collection.url] = collection
+
+ if (ContextCompat.checkSelfPermission(
+ context,
+ Manifest.permission.WRITE_CONTACTS
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ if (remoteAddressBooks.isEmpty())
+ Logger.log.info("No contacts permission, but no address book selected for synchronization")
+ else {
+ // no contacts permission, but address books should be synchronized -> show notification
+ val intent = Intent(context, AccountActivity::class.java)
+ intent.putExtra(AccountActivity.EXTRA_ACCOUNT, account)
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+ PermissionUtils.notifyPermissions(context, intent)
+ }
+ return false
+ }
+
+ val contactsProvider =
+ context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY)
+ try {
+ if (contactsProvider == null) {
+ Logger.log.severe("Couldn't access contacts provider")
+ syncResult.databaseError = true
+ return false
+ }
+
+ // delete/update local address books
+ for (addressBook in LocalAddressBook.findAll(context, contactsProvider, account)) {
+ val url = addressBook.url.toHttpUrlOrNull()!!
+ val info = remoteAddressBooks[url]
+ if (info == null) {
+ Logger.log.log(Level.INFO, "Deleting obsolete local address book", url)
+ addressBook.delete()
+ } else {
+ // remote CollectionInfo found for this local collection, update data
+ try {
+ Logger.log.log(Level.FINE, "Updating local address book $url", info)
+ addressBook.update(info)
+ } catch (e: Exception) {
+ Logger.log.log(Level.WARNING, "Couldn't rename address book account", e)
+ }
+ // we already have a local address book for this remote collection, don't take into consideration anymore
+ remoteAddressBooks -= url
+ }
+ }
+
+ // create new local address books
+ for ((_, info) in remoteAddressBooks) {
+ Logger.log.log(Level.INFO, "Adding local address book", info)
+ LocalAddressBook.create(context, db, contactsProvider, account, info)
+ }
+ } finally {
+ contactsProvider?.closeCompat()
+ }
+
+ return true
+ }
+
+ }
+
+}
+
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleCalendarsSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleCalendarsSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..643a649cd1ce7f9ab229cbaa717085658f14aef0
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleCalendarsSyncAdapterService.kt
@@ -0,0 +1,190 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.content.ContentProviderClient
+import android.content.ContentResolver
+import android.content.Context
+import android.content.SyncResult
+import android.os.AsyncTask
+import android.os.Bundle
+import android.provider.CalendarContract
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.db.Collection
+import at.bitfire.davdroid.db.Credentials
+import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
+import at.bitfire.davdroid.resource.LocalCalendar
+import at.bitfire.davdroid.settings.AccountSettings
+import at.bitfire.ical4android.AndroidCalendar
+import net.openid.appauth.AuthorizationService
+import okhttp3.HttpUrl
+import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
+import java.util.logging.Level
+
+class GoogleCalendarsSyncAdapterService : SyncAdapterService() {
+
+ override fun syncAdapter() = CalendarsSyncAdapter(this, appDatabase)
+
+
+ class CalendarsSyncAdapter(
+ context: Context,
+ db: AppDatabase
+ ) : SyncAdapter(context, db) {
+
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ try {
+ val accountSettings = AccountSettings(context, account)
+
+ /* don't run sync if
+ - sync conditions (e.g. "sync only in WiFi") are not met AND
+ - this is is an automatic sync (i.e. manual syncs are run regardless of sync conditions)
+ */
+ if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(
+ accountSettings
+ )
+ )
+ return
+
+ if (accountSettings.getEventColors())
+ AndroidCalendar.insertColors(provider, account)
+ else
+ AndroidCalendar.removeColors(provider, account)
+
+ updateLocalCalendars(provider, account, accountSettings)
+
+ val priorityCalendars = priorityCollections(extras)
+ val calendars = AndroidCalendar
+ .find(
+ account,
+ provider,
+ LocalCalendar.Factory,
+ "${CalendarContract.Calendars.SYNC_EVENTS}!=0",
+ null
+ )
+ .sortedByDescending { priorityCalendars.contains(it.id) }
+ for (calendar in calendars) {
+ Logger.log.info("Synchronizing calendar #${calendar.id}, URL: ${calendar.name}")
+ CalendarSyncManager(
+ context,
+ account,
+ accountSettings,
+ extras,
+ httpClient.value,
+ authority,
+ syncResult,
+ calendar
+ ).let {
+ val authState = accountSettings.credentials().authState
+ if (authState != null) {
+ if (authState.needsTokenRefresh) {
+ val tokenRequest = authState.createTokenRefreshRequest()
+
+ AuthorizationService(context).performTokenRequest(tokenRequest,
+ AuthorizationService.TokenResponseCallback { tokenResponse, ex ->
+ authState.update(tokenResponse, ex)
+ accountSettings.credentials(
+ Credentials(
+ account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ it.accountSettings.credentials(
+ Credentials(
+ it.account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ object : AsyncTask() {
+ override fun doInBackground(vararg params: Void): Void? {
+ it.performSync()
+ return null
+ }
+ }.execute()
+ })
+ } else {
+ it.performSync()
+ }
+ } else {
+ it.performSync()
+ }
+ }
+ }
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't sync calendars", e)
+ }
+ Logger.log.info("Calendar sync complete")
+ }
+
+ private fun updateLocalCalendars(
+ provider: ContentProviderClient,
+ account: Account,
+ settings: AccountSettings
+ ) {
+ val service = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CALDAV)
+
+ val remoteCalendars = mutableMapOf()
+ if (service != null)
+ for (collection in db.collectionDao().getSyncCalendars(service.id)) {
+ remoteCalendars[collection.url] = collection
+ }
+
+ // delete/update local calendars
+ val updateColors = settings.getManageCalendarColors()
+ for (calendar in AndroidCalendar.find(
+ account,
+ provider,
+ LocalCalendar.Factory,
+ null,
+ null
+ ))
+ calendar.name?.let {
+ val url = it.toHttpUrlOrNull()!!
+ val info = remoteCalendars[url]
+ if (info == null) {
+ Logger.log.log(Level.INFO, "Deleting obsolete local calendar", url)
+ calendar.delete()
+ } else {
+ // remote CollectionInfo found for this local collection, update data
+ Logger.log.log(Level.FINE, "Updating local calendar $url", info)
+ calendar.update(info, updateColors)
+ // we already have a local calendar for this remote collection, don't take into consideration anymore
+ remoteCalendars -= url
+ }
+ }
+
+ // create new local calendars
+ for ((_, info) in remoteCalendars) {
+ Logger.log.log(Level.INFO, "Adding local calendar", info)
+ LocalCalendar.create(account, provider, info)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleContactsSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleContactsSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..fd8c3ade1460f4d99a9914f5fb868f402044a205
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleContactsSyncAdapterService.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.content.ContentProviderClient
+import android.content.ContentResolver
+import android.content.Context
+import android.content.SyncResult
+import android.os.Bundle
+import android.provider.ContactsContract
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.log.Logger
+import at.bitfire.davdroid.resource.LocalAddressBook
+import at.bitfire.davdroid.settings.AccountSettings
+import java.util.logging.Level
+
+class GoogleContactsSyncAdapterService : SyncAdapterService() {
+
+ companion object {
+ const val PREVIOUS_GROUP_METHOD = "previous_group_method"
+ }
+
+ override fun syncAdapter() = ContactsSyncAdapter(this, appDatabase)
+
+ class ContactsSyncAdapter(
+ context: Context,
+ db: AppDatabase
+ ) : SyncAdapter(context, db) {
+
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ try {
+ val addressBook = LocalAddressBook(context, account, provider)
+ val accountSettings = AccountSettings(context, addressBook.mainAccount)
+
+ // handle group method change
+ val groupMethod = accountSettings.getGroupMethod().name
+ accountSettings.accountManager.getUserData(account, PREVIOUS_GROUP_METHOD)
+ ?.let { previousGroupMethod ->
+ if (previousGroupMethod != groupMethod) {
+ Logger.log.info("Group method changed, deleting all local contacts/groups")
+
+ // delete all local contacts and groups so that they will be downloaded again
+ provider.delete(
+ addressBook.syncAdapterURI(ContactsContract.RawContacts.CONTENT_URI),
+ null,
+ null
+ )
+ provider.delete(
+ addressBook.syncAdapterURI(ContactsContract.Groups.CONTENT_URI),
+ null,
+ null
+ )
+
+ // reset sync state
+ addressBook.syncState = null
+ }
+ }
+ accountSettings.accountManager.setUserData(
+ account,
+ PREVIOUS_GROUP_METHOD,
+ groupMethod
+ )
+
+ /* don't run sync if
+ - sync conditions (e.g. "sync only in WiFi") are not met AND
+ - this is is an automatic sync (i.e. manual syncs are run regardless of sync conditions)
+ */
+ if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(
+ accountSettings
+ )
+ )
+ return
+
+ Logger.log.info("Synchronizing address book: ${addressBook.url}")
+ Logger.log.info("Taking settings from: ${addressBook.mainAccount}")
+
+ ContactsSyncManager(
+ context,
+ account,
+ accountSettings,
+ httpClient.value,
+ extras,
+ authority,
+ syncResult,
+ provider,
+ addressBook
+ ).performSync()
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't sync contacts", e)
+ }
+ Logger.log.info("Contacts sync complete")
+ }
+ }
+}
+
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleEmailSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleEmailSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..458237d98fd1ed239721092801cf95b187cc7b6a
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleEmailSyncAdapterService.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.content.*
+import android.os.Bundle
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.db.AppDatabase
+
+class GoogleEmailSyncAdapterService : SyncAdapterService() {
+
+ override fun syncAdapter() = GoogleEmailSyncAdapter(this, appDatabase)
+
+ class GoogleEmailSyncAdapter(
+ context: Context,
+ db: AppDatabase
+ ): SyncAdapter(context, db) {
+
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ // Unused
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleNullAuthenticatorService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleNullAuthenticatorService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0485928f26e3a4c4b0219d528064ca7e8262a8f5
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleNullAuthenticatorService.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.AbstractAccountAuthenticator
+import android.accounts.Account
+import android.accounts.AccountAuthenticatorResponse
+import android.accounts.AccountManager
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import at.bitfire.davdroid.ui.AccountsActivity
+
+class GoogleNullAuthenticatorService: Service() {
+
+ private lateinit var accountAuthenticator: AccountAuthenticator
+
+ override fun onCreate() {
+ accountAuthenticator = AccountAuthenticator(this)
+ }
+
+ override fun onBind(intent: Intent?) =
+ accountAuthenticator.iBinder.takeIf { intent?.action == AccountManager.ACTION_AUTHENTICATOR_INTENT }
+
+
+ private class AccountAuthenticator(
+ val context: Context
+ ): AbstractAccountAuthenticator(context) {
+
+ override fun addAccount(response: AccountAuthenticatorResponse?, accountType: String?, authTokenType: String?, requiredFeatures: Array?, options: Bundle?): Bundle {
+ val intent = Intent(context, AccountsActivity::class.java)
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response)
+ val bundle = Bundle(1)
+ bundle.putParcelable(AccountManager.KEY_INTENT, intent)
+ return bundle
+ }
+
+ override fun editProperties(response: AccountAuthenticatorResponse?, accountType: String?) = null
+ override fun getAuthTokenLabel(p0: String?) = null
+ override fun confirmCredentials(p0: AccountAuthenticatorResponse?, p1: Account?, p2: Bundle?) = null
+ override fun updateCredentials(p0: AccountAuthenticatorResponse?, p1: Account?, p2: String?, p3: Bundle?) = null
+ override fun getAuthToken(p0: AccountAuthenticatorResponse?, p1: Account?, p2: String?, p3: Bundle?) = null
+ override fun hasFeatures(p0: AccountAuthenticatorResponse?, p1: Account?, p2: Array?) = null
+ }
+}
+
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleTasksSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleTasksSyncAdapterService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8a3d0713f4a217f2dcce91aee947fbbe824ab282
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/GoogleTasksSyncAdapterService.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.syncadapter
+
+import android.accounts.Account
+import android.accounts.AccountManager
+import android.content.ContentProviderClient
+import android.content.ContentResolver
+import android.content.Context
+import android.content.SyncResult
+import android.os.AsyncTask
+import android.os.Build
+import android.os.Bundle
+import at.bitfire.davdroid.HttpClient
+import at.bitfire.davdroid.db.AppDatabase
+import at.bitfire.davdroid.db.Collection
+import at.bitfire.davdroid.db.Credentials
+import at.bitfire.davdroid.db.Service
+import at.bitfire.davdroid.log.Logger
+import at.bitfire.davdroid.resource.LocalTaskList
+import at.bitfire.davdroid.settings.AccountSettings
+import at.bitfire.ical4android.AndroidTaskList
+import at.bitfire.ical4android.TaskProvider
+import net.openid.appauth.AuthorizationService
+import okhttp3.HttpUrl
+import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
+import org.dmfs.tasks.contract.TaskContract
+import java.util.logging.Level
+
+/**
+ * Synchronization manager for CalDAV collections; handles tasks ({@code VTODO}).
+ */
+class GoogleTasksSyncAdapterService : SyncAdapterService() {
+
+ override fun syncAdapter() = TasksSyncAdapter(this, appDatabase)
+
+
+ class TasksSyncAdapter(
+ context: Context,
+ db: AppDatabase
+ ) : SyncAdapter(context, db) {
+
+ override fun sync(
+ account: Account,
+ extras: Bundle,
+ authority: String,
+ httpClient: Lazy,
+ provider: ContentProviderClient,
+ syncResult: SyncResult
+ ) {
+ try {
+ val providerName = TaskProvider.ProviderName.fromAuthority(authority)
+ val taskProvider = TaskProvider.fromProviderClient(context, providerName, provider)
+
+ // make sure account can be seen by OpenTasks
+ if (Build.VERSION.SDK_INT >= 26)
+ AccountManager.get(context).setAccountVisibility(
+ account,
+ taskProvider.name.packageName,
+ AccountManager.VISIBILITY_VISIBLE
+ )
+
+ val accountSettings = AccountSettings(context, account)
+ /* don't run sync if
+ - sync conditions (e.g. "sync only in WiFi") are not met AND
+ - this is is an automatic sync (i.e. manual syncs are run regardless of sync conditions)
+ */
+ if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(
+ accountSettings
+ )
+ )
+ return
+
+ updateLocalTaskLists(taskProvider, account, accountSettings)
+
+ val priorityTaskLists = priorityCollections(extras)
+ val taskLists = AndroidTaskList
+ .find(
+ account,
+ taskProvider,
+ LocalTaskList.Factory,
+ "${TaskContract.TaskLists.SYNC_ENABLED}!=0",
+ null
+ )
+ .sortedByDescending { priorityTaskLists.contains(it.id) }
+ for (taskList in taskLists) {
+ Logger.log.info("Synchronizing task list #${taskList.id} [${taskList.syncId}]")
+ TasksSyncManager(
+ context,
+ account,
+ accountSettings,
+ httpClient.value,
+ extras,
+ authority,
+ syncResult,
+ taskList
+ ).let {
+ val authState = accountSettings.credentials().authState
+ if (authState != null) {
+ if (authState.needsTokenRefresh) {
+ val tokenRequest = authState.createTokenRefreshRequest()
+
+ AuthorizationService(context).performTokenRequest(tokenRequest,
+ AuthorizationService.TokenResponseCallback { tokenResponse, ex ->
+ authState.update(tokenResponse, ex)
+ accountSettings.credentials(
+ Credentials(
+ account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ it.accountSettings.credentials(
+ Credentials(
+ it.account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ object : AsyncTask() {
+ override fun doInBackground(vararg params: Void): Void? {
+ it.performSync()
+ return null
+ }
+ }.execute()
+ })
+ } else {
+ it.performSync()
+ }
+ } else {
+ it.performSync()
+ }
+ }
+ }
+ } catch (e: TaskProvider.ProviderTooOldException) {
+ SyncUtils.notifyProviderTooOld(context, e)
+ syncResult.databaseError = true
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't sync task lists", e)
+ syncResult.databaseError = true
+ }
+
+ Logger.log.info("Task sync complete")
+ }
+
+ private fun updateLocalTaskLists(
+ provider: TaskProvider,
+ account: Account,
+ settings: AccountSettings
+ ) {
+ val service = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CALDAV)
+
+ val remoteTaskLists = mutableMapOf()
+ if (service != null)
+ for (collection in db.collectionDao().getSyncTaskLists(service.id)) {
+ remoteTaskLists[collection.url] = collection
+ }
+
+ // delete/update local task lists
+ val updateColors = settings.getManageCalendarColors()
+
+ for (list in AndroidTaskList.find(account, provider, LocalTaskList.Factory, null, null))
+ list.syncId?.let {
+ val url = it.toHttpUrlOrNull()!!
+ val info = remoteTaskLists[url]
+ if (info == null) {
+ Logger.log.fine("Deleting obsolete local task list $url")
+ list.delete()
+ } else {
+ // remote CollectionInfo found for this local collection, update data
+ Logger.log.log(Level.FINE, "Updating local task list $url", info)
+ list.update(info, updateColors)
+ // we already have a local task list for this remote collection, don't take into consideration anymore
+ remoteTaskLists -= url
+ }
+ }
+
+ // create new local task lists
+ for ((_, info) in remoteTaskLists) {
+ Logger.log.log(Level.INFO, "Adding local task list", info)
+ LocalTaskList.create(account, provider, info)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncManager.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncManager.kt
index 5ecdc496a49c0f24181cb7b5beb2cc315d36ed1d..e33b0e2941f63edcd6a396447a5f4690b570e04d 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/JtxSyncManager.kt
@@ -47,7 +47,7 @@ class JtxSyncManager(
override fun prepare(): Boolean {
collectionURL = (localCollection.url ?: return false).toHttpUrlOrNull() ?: return false
- davCollection = DavCalendar(httpClient.okHttpClient, collectionURL)
+ davCollection = DavCalendar(httpClient.okHttpClient, collectionURL, accountSettings.credentials().authState?.accessToken)
return true
}
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.kt
index 443f75ba77ea0a2bd5a289839c93fbf4687500ce..34b4f47104b36e6410b4ee7cd2342ce1d4786985 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncManager.kt
@@ -323,7 +323,7 @@ abstract class SyncManager, out CollectionType: L
val lastETag = if (lastScheduleTag == null) local.eTag else null
Logger.log.info("$fileName has been deleted locally -> deleting from server (ETag $lastETag / schedule-tag $lastScheduleTag)")
- remoteExceptionContext(DavResource(httpClient.okHttpClient, collectionURL.newBuilder().addPathSegment(fileName).build())) { remote ->
+ remoteExceptionContext(DavResource(httpClient.okHttpClient, collectionURL.newBuilder().addPathSegment(fileName).build(), accountSettings.credentials().authState?.accessToken)) { remote ->
try {
remote.delete(ifETag = lastETag, ifScheduleTag = lastScheduleTag) {}
numDeleted++
@@ -712,6 +712,13 @@ abstract class SyncManager, out CollectionType: L
Logger.log.log(Level.SEVERE, "Not authorized anymore", e)
message = context.getString(R.string.sync_error_authentication_failed)
syncResult.stats.numAuthExceptions++
+ if (account.type.toLowerCase(Locale.getDefault()).contains("google")) {
+ /* TODO Investigate deeper why this exception sometimes happens
+ * https://gitlab.e.foundation/e/backlog/-/issues/3430
+ */
+ Logger.log.log(Level.WARNING, "Authorization error. Do not notify the user")
+ return
+ }
}
is HttpException, is DavException -> {
Logger.log.log(Level.SEVERE, "HTTP/DAV exception", e)
@@ -732,7 +739,10 @@ abstract class SyncManager, out CollectionType: L
val contentIntent: Intent
var viewItemAction: NotificationCompat.Action? = null
- if (e is UnauthorizedException) {
+ if ((account.type == context.getString(R.string.account_type) ||
+ account.type == context.getString(R.string.eelo_account_type) ||
+ account.type == context.getString(R.string.google_account_type)) &&
+ (e is UnauthorizedException || e is NotFoundException)) {
contentIntent = Intent(context, SettingsActivity::class.java)
contentIntent.putExtra(SettingsActivity.EXTRA_ACCOUNT,
if (authority == ContactsContract.AUTHORITY)
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncUtils.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncUtils.kt
index a808dd905906e5d30aac8588a635d8c946eba3a2..c9e9bc5abb6fa76389898738f8ecefab7ed86278 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncUtils.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/SyncUtils.kt
@@ -17,6 +17,7 @@ import android.os.Build
import androidx.annotation.WorkerThread
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
+import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.PermissionUtils
import at.bitfire.davdroid.R
@@ -104,7 +105,7 @@ object SyncUtils {
// check all accounts and (de)activate task provider(s) if a CalDAV service is defined
val db = EntryPointAccessors.fromApplication(context, SyncUtilsEntryPoint::class.java).appDatabase()
val accountManager = AccountManager.get(context)
- for (account in accountManager.getAccountsByType(context.getString(R.string.account_type))) {
+ for (account in accountManager.accounts) {
val hasCalDAV = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CALDAV) != null
for (providerName in TaskProvider.ProviderName.values()) {
val isSyncable = ContentResolver.getIsSyncable(account, providerName.authority) // may be -1 (unknown state)
@@ -133,7 +134,7 @@ object SyncUtils {
ContentResolver.setIsSyncable(account, authority, 1)
try {
val settings = AccountSettings(context, account)
- val interval = settings.getSavedTasksSyncInterval() ?: settingsManager.getLong(Settings.DEFAULT_SYNC_INTERVAL)
+ val interval = settings.getSavedTasksSyncInterval() ?: Constants.DEFAULT_CALENDAR_SYNC_INTERVAL
settings.setSyncInterval(authority, interval)
} catch (e: InvalidAccountException) {
// account has already been removed
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.kt
index 8b03e8035134f0e7908a924e6cf90494ff373ee6..c61070f8d14bd2384561d7280faf4d26cb6d1651 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.kt
@@ -20,6 +20,11 @@ import at.bitfire.davdroid.resource.LocalTaskList
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.ical4android.AndroidTaskList
import at.bitfire.ical4android.TaskProvider
+import android.os.AsyncTask
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import at.bitfire.davdroid.db.Credentials
+import net.openid.appauth.AuthorizationService
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import org.dmfs.tasks.contract.TaskContract
@@ -70,7 +75,42 @@ open class TasksSyncAdapterService: SyncAdapterService() {
for (taskList in taskLists) {
Logger.log.info("Synchronizing task list #${taskList.id} [${taskList.syncId}]")
TasksSyncManager(context, account, accountSettings, httpClient.value, extras, authority, syncResult, taskList).let {
- it.performSync()
+ val authState = accountSettings.credentials().authState
+ if (authState != null) {
+ if (authState.needsTokenRefresh) {
+ val tokenRequest = authState.createTokenRefreshRequest()
+
+ AuthorizationService(context).performTokenRequest(tokenRequest) { tokenResponse, ex ->
+ authState.update(tokenResponse, ex)
+ accountSettings.credentials(
+ Credentials(
+ account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ it.accountSettings.credentials(
+ Credentials(
+ it.account.name,
+ null,
+ authState,
+ null
+ )
+ )
+ object : AsyncTask() {
+ override fun doInBackground(vararg params: Void): Void? {
+ it.performSync()
+ return null
+ }
+ }.execute()
+ }
+ } else {
+ it.performSync()
+ }
+ } else {
+ it.performSync()
+ }
}
}
} catch (e: TaskProvider.ProviderTooOldException) {
diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.kt
index d1dbc363ea5d613e9374c1626853dc007a00564e..bb02ce57ff013a87331796736aaf749a6f3a78dc 100644
--- a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.kt
+++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.kt
@@ -50,7 +50,7 @@ class TasksSyncManager(
override fun prepare(): Boolean {
collectionURL = (localCollection.syncId ?: return false).toHttpUrlOrNull() ?: return false
- davCollection = DavCalendar(httpClient.okHttpClient, collectionURL)
+ davCollection = DavCalendar(httpClient.okHttpClient, collectionURL, accountSettings.credentials().authState?.accessToken)
return true
}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt
index a1fe1f1aeeb4b5afe55de2ee8e0546cc4d64f1cb..253ac1944e12e761372c24ee1e389765cda1debe 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt
@@ -255,9 +255,14 @@ class AccountListFragment: Fragment() {
val context = getApplication()
val collator = Collator.getInstance()
- val sortedAccounts = accountManager
- .getAccountsByType(context.getString(R.string.account_type))
- .sortedArrayWith { a, b ->
+ val accountsFromManager = ArrayList()
+ val accountManager = AccountManager.get(context)
+ accountManager.getAccountsByType(context.getString(R.string.eelo_account_type)).forEach { accountsFromManager.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.google_account_type)).forEach { accountsFromManager.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type)).forEach { accountsFromManager.add(it) }
+
+ val sortedAccounts = accountsFromManager
+ .sortedWith { a, b ->
collator.compare(a.name, b.name)
}
val accountsWithInfo = sortedAccounts.map { account ->
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/BaseAccountsDrawerHandler.kt b/app/src/main/java/at/bitfire/davdroid/ui/BaseAccountsDrawerHandler.kt
index fb8bb50f4dc7d12610b179d2696eb6d83120fd84..151453809893ada9c7fdbc9dcd7a3f4cae1b9dd1 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/BaseAccountsDrawerHandler.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/BaseAccountsDrawerHandler.kt
@@ -7,12 +7,9 @@ package at.bitfire.davdroid.ui
import android.app.Activity
import android.content.Context
import android.content.Intent
-import android.net.Uri
import android.view.Menu
import android.view.MenuItem
-import android.widget.Toast
import androidx.annotation.CallSuper
-import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.R
/**
@@ -20,15 +17,9 @@ import at.bitfire.davdroid.R
*/
abstract class BaseAccountsDrawerHandler: AccountsDrawerHandler {
- companion object {
- private const val BETA_FEEDBACK_URI = "mailto:play@bitfire.at?subject=${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} feedback (${BuildConfig.VERSION_CODE})"
- }
-
-
@CallSuper
override fun initMenu(context: Context, menu: Menu) {
- if (BuildConfig.VERSION_NAME.contains("-alpha") || BuildConfig.VERSION_NAME.contains("-beta") || BuildConfig.VERSION_NAME.contains("-rc"))
- menu.findItem(R.id.nav_beta_feedback).isVisible = true
+ // TODO Provide option for beta feedback
}
@CallSuper
@@ -36,15 +27,6 @@ abstract class BaseAccountsDrawerHandler: AccountsDrawerHandler {
when (item.itemId) {
R.id.nav_about ->
activity.startActivity(Intent(activity, AboutActivity::class.java))
- R.id.nav_beta_feedback ->
- if (!UiUtils.launchUri(
- activity,
- Uri.parse(BETA_FEEDBACK_URI),
- Intent.ACTION_SENDTO,
- false
- )
- )
- Toast.makeText(activity, R.string.install_email_client, Toast.LENGTH_LONG).show()
R.id.nav_app_settings ->
activity.startActivity(Intent(activity, AppSettingsActivity::class.java))
}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.kt
index 8573047d7edc12db163756be1c6c951cb835583d..a8c63ad873a21176377ad95715f625e8c90b2a77 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/DebugInfoActivity.kt
@@ -43,8 +43,8 @@ import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.settings.SettingsManager
-import at.bitfire.ical4android.MiscUtils.ContentProviderClientHelper.closeCompat
import at.bitfire.ical4android.TaskProvider.ProviderName
+import at.bitfire.ical4android.util.MiscUtils.ContentProviderClientHelper.closeCompat
import at.techbee.jtx.JtxContract
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -65,6 +65,7 @@ import java.util.logging.Level
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import javax.inject.Inject
+import kotlin.collections.ArrayList
@AndroidEntryPoint
class DebugInfoActivity: AppCompatActivity() {
@@ -449,10 +450,11 @@ class DebugInfoActivity: AppCompatActivity() {
writer.append('\n')
writer.append("\nACCOUNTS\n\n")
- // main accounts
+
val accountManager = AccountManager.get(context)
- val mainAccounts = accountManager.getAccountsByType(context.getString(R.string.account_type))
- val addressBookAccounts = accountManager.getAccountsByType(context.getString(R.string.account_type_address_book)).toMutableList()
+ val mainAccounts = getMainAccounts(accountManager)
+ val addressBookAccounts = getAddressBookAccounts(accountManager)
+
for (account in mainAccounts) {
dumpMainAccount(account, writer)
@@ -489,6 +491,28 @@ class DebugInfoActivity: AppCompatActivity() {
debugInfo.postValue(debugInfoFile)
}
+ private fun getMainAccounts(accountManager: AccountManager): ArrayList {
+ val mainAccounts = ArrayList()
+ accountManager.getAccountsByType(context.getString(R.string.eelo_account_type))
+ .forEach { mainAccounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.google_account_type))
+ .forEach { mainAccounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type))
+ .forEach { mainAccounts.add(it) }
+ return mainAccounts
+ }
+
+ private fun getAddressBookAccounts(accountManager: AccountManager): ArrayList {
+ val addressBookAccounts = ArrayList()
+ accountManager.getAccountsByType(context.getString(R.string.account_type_eelo_address_book))
+ .forEach { addressBookAccounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type_google_address_book))
+ .forEach { addressBookAccounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type_address_book))
+ .forEach { addressBookAccounts.add(it) }
+ return addressBookAccounts
+ }
+
fun generateZip(onSuccess: (File) -> Unit) {
viewModelScope.launch(Dispatchers.IO) {
try {
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/ExceptionInfoFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/ExceptionInfoFragment.kt
index 05df1bcf3c90743b6a7022de0689016eb8aa3a3c..81307123be919dcf332e245652aacb1a71628005 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/ExceptionInfoFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/ExceptionInfoFragment.kt
@@ -40,7 +40,7 @@ class ExceptionInfoFragment: DialogFragment() {
else -> R.string.exception
}
- val dialog = MaterialAlertDialogBuilder(requireActivity())
+ val dialog = MaterialAlertDialogBuilder(requireActivity(), R.style.CustomAlertDialogStyle)
.setIcon(R.drawable.ic_error)
.setTitle(title)
.setMessage(exception::class.java.name + "\n" + exception.localizedMessage)
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/OseAccountsDrawerHandler.kt b/app/src/main/java/at/bitfire/davdroid/ui/OseAccountsDrawerHandler.kt
index dd15c7bfc62ee167b288765b5ac430caf65d753f..368908788b720e6cd4cbdf2b8f210cb68aee979b 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/OseAccountsDrawerHandler.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/OseAccountsDrawerHandler.kt
@@ -6,9 +6,7 @@ package at.bitfire.davdroid.ui
import android.app.Activity
import android.content.Intent
-import android.net.Uri
import android.view.MenuItem
-import at.bitfire.davdroid.App
import at.bitfire.davdroid.R
import at.bitfire.davdroid.ui.webdav.WebdavMountsActivity
import javax.inject.Inject
@@ -18,50 +16,10 @@ import javax.inject.Inject
*/
class OseAccountsDrawerHandler @Inject constructor(): BaseAccountsDrawerHandler() {
- companion object {
- const val COMMUNITY_URL = "https://github.com/bitfireAT/davx5-ose/discussions"
- }
-
override fun onNavigationItemSelected(activity: Activity, item: MenuItem) {
when (item.itemId) {
-
- R.id.nav_twitter ->
- UiUtils.launchUri(
- activity,
- Uri.parse("https://twitter.com/" + activity.getString(R.string.twitter_handle))
- )
-
R.id.nav_webdav_mounts ->
activity.startActivity(Intent(activity, WebdavMountsActivity::class.java))
-
- R.id.nav_website ->
- UiUtils.launchUri(
- activity,
- App.homepageUrl(activity)
- )
- R.id.nav_manual ->
- UiUtils.launchUri(
- activity,
- App.homepageUrl(activity).buildUpon().appendPath("manual").build()
- )
- R.id.nav_faq ->
- UiUtils.launchUri(
- activity,
- App.homepageUrl(activity).buildUpon().appendPath("faq").build()
- )
- R.id.nav_community ->
- UiUtils.launchUri(activity, Uri.parse(COMMUNITY_URL))
- R.id.nav_donate ->
- UiUtils.launchUri(
- activity,
- App.homepageUrl(activity).buildUpon().appendPath("donate").build()
- )
- R.id.nav_privacy ->
- UiUtils.launchUri(
- activity,
- App.homepageUrl(activity).buildUpon().appendPath("privacy").build()
- )
-
else ->
super.onNavigationItemSelected(activity, item)
}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt
index 607f25afdc35e1c4a5ae4bde201203910110c3a9..91ef9620d9d8c6d93dbf887db25b42a90f3e7fab 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt
@@ -38,6 +38,8 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
+import at.bitfire.davdroid.MailAccountSyncHelper
+
import java.util.logging.Level
import javax.inject.Inject
@@ -112,7 +114,7 @@ class AccountActivity: AppCompatActivity() {
}
fun deleteAccount(menuItem: MenuItem) {
- MaterialAlertDialogBuilder(this)
+ MaterialAlertDialogBuilder(this, R.style.CustomAlertDialogStyle)
.setIcon(R.drawable.ic_error)
.setTitle(R.string.account_delete_confirmation_title)
.setMessage(R.string.account_delete_confirmation_text)
@@ -125,29 +127,40 @@ class AccountActivity: AppCompatActivity() {
private fun deleteAccount() {
val accountManager = AccountManager.get(this)
+ val email = accountManager.getUserData(model.account, AccountSettings.KEY_EMAIL_ADDRESS)
if (Build.VERSION.SDK_INT >= 22)
- accountManager.removeAccount(model.account, this, { future ->
- try {
- if (future.result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT))
- Handler(Looper.getMainLooper()).post {
- finish()
- }
- } catch(e: Exception) {
- Logger.log.log(Level.SEVERE, "Couldn't remove account", e)
- }
- }, null)
+ removeAccount(accountManager, email)
else
- accountManager.removeAccount(model.account, { future ->
- try {
- if (future.result)
- Handler(Looper.getMainLooper()).post {
- finish()
- }
- } catch (e: Exception) {
- Logger.log.log(Level.SEVERE, "Couldn't remove account", e)
- }
- }, null)
+ removeAccountForOlderSdk(accountManager, email)
+ }
+
+ private fun removeAccountForOlderSdk(accountManager: AccountManager, email: String?) {
+ accountManager.removeAccount(model.account, { future ->
+ try {
+ if (future.result)
+ Handler(Looper.getMainLooper()).post {
+ MailAccountSyncHelper.accountLoggedOut(applicationContext, email)
+ finish()
+ }
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't remove account", e)
+ }
+ }, null)
+ }
+
+ private fun removeAccount(accountManager: AccountManager, email: String?) {
+ accountManager.removeAccount(model.account, this, { future ->
+ try {
+ if (future.result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT))
+ Handler(Looper.getMainLooper()).post {
+ MailAccountSyncHelper.accountLoggedOut(applicationContext, email)
+ finish()
+ }
+ } catch (e: Exception) {
+ Logger.log.log(Level.SEVERE, "Couldn't remove account", e)
+ }
+ }, null)
}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt
index f4e197b46f34eea0d292f8fdf53a360b74a46e5b..4e195262cd07d009fe5f6ea8f44594d8828c74bb 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt
@@ -12,6 +12,7 @@ import android.provider.ContactsContract
import android.view.*
import android.widget.PopupMenu
import androidx.annotation.AnyThread
+import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.activityViewModels
@@ -126,7 +127,7 @@ abstract class CollectionsFragment: Fragment(), SwipeRefreshLayout.OnRefreshList
lifecycleScope.launch {
val colors = data.flow.map { pagingData ->
pagingData.map { collection ->
- collection.color ?: Constants.DAVDROID_GREEN_RGBA
+ collection.color ?: ContextCompat.getColor(requireContext(), R.color.accentColor)
}
}
data.flow.collectLatest { pagingData ->
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/CreateCalendarActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/CreateCalendarActivity.kt
index 830368e85d8e13e37e1cdb778d04632e64426af4..453e64beb5b4e39daedaab43e1f68a5baa946a1d 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/CreateCalendarActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/CreateCalendarActivity.kt
@@ -28,7 +28,7 @@ import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.HomeSet
import at.bitfire.davdroid.db.Service
import at.bitfire.davdroid.ui.HomeSetAdapter
-import at.bitfire.ical4android.DateUtils
+import at.bitfire.ical4android.util.DateUtils
import com.jaredrummler.android.colorpicker.ColorPickerDialog
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import dagger.assisted.Assisted
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/RenameAccountFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/RenameAccountFragment.kt
index ca8c3985979f8108a8ca5dea728df3726810dd22..b216edc913d480955c17197e06954df507ff909a 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/RenameAccountFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/RenameAccountFragment.kt
@@ -84,7 +84,7 @@ class RenameAccountFragment: DialogFragment() {
this@RenameAccountFragment.requireActivity().finish()
})
- return MaterialAlertDialogBuilder(requireActivity())
+ return MaterialAlertDialogBuilder(requireActivity(), R.style.CustomAlertDialogStyle)
.setTitle(R.string.account_rename)
.setMessage(R.string.account_rename_new_name)
.setView(layout)
@@ -141,6 +141,17 @@ class RenameAccountFragment: DialogFragment() {
}
}
+ private fun getAddressBookAccounts(accountManager: AccountManager): ArrayList {
+ val addressBookAccounts = ArrayList()
+ accountManager.getAccountsByType(context.getString(R.string.account_type_eelo_address_book))
+ .forEach { addressBookAccounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type_google_address_book))
+ .forEach { addressBookAccounts.add(it) }
+ accountManager.getAccountsByType(context.getString(R.string.account_type_address_book))
+ .forEach { addressBookAccounts.add(it) }
+ return addressBookAccounts
+ }
+
@SuppressLint("Recycle")
@WorkerThread
fun onAccountRenamed(accountManager: AccountManager, oldAccount: Account, newName: String, syncIntervals: List>) {
@@ -149,7 +160,8 @@ class RenameAccountFragment: DialogFragment() {
// cancel maybe running synchronization
ContentResolver.cancelSync(oldAccount, null)
- for (addrBookAccount in accountManager.getAccountsByType(context.getString(R.string.account_type_address_book)))
+
+ for (addrBookAccount in getAddressBookAccounts(accountManager))
ContentResolver.cancelSync(addrBookAccount, null)
// update account name references in database
@@ -166,7 +178,7 @@ class RenameAccountFragment: DialogFragment() {
try {
context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY)?.let { provider ->
try {
- for (addrBookAccount in accountManager.getAccountsByType(context.getString(R.string.account_type_address_book))) {
+ for (addrBookAccount in getAddressBookAccounts(accountManager)) {
val addressBook = LocalAddressBook(context, addrBookAccount, provider)
if (oldAccount == addressBook.mainAccount)
addressBook.mainAccount = Account(newName, oldAccount.type)
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/SettingsActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/SettingsActivity.kt
index b4a58e02fe022d9eadafdacfefc434cbdc519986..ddf18e5c716f5e48beed103ac93726a983088d33 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/account/SettingsActivity.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/account/SettingsActivity.kt
@@ -5,6 +5,7 @@
package at.bitfire.davdroid.ui.account
import android.accounts.Account
+import android.accounts.AccountManager
import android.annotation.SuppressLint
import android.content.ContentResolver
import android.content.Context
@@ -119,6 +120,13 @@ class SettingsActivity: AppCompatActivity() {
checkWifiPermissions()
}
+ private fun launchSetup(): Boolean {
+ AccountManager.get(context).addAccount(getString(R.string.google_account_type),
+ null, null, null, activity, null,
+ null)
+ return true
+ }
+
private fun initSettings() {
// preference group: sync
findPreference(getString(R.string.settings_sync_interval_contacts_key))!!.let {
@@ -219,6 +227,7 @@ class SettingsActivity: AppCompatActivity() {
}
// preference group: authentication
+ val prefCredentials = findPreference("credentials")!!
val prefUserName = findPreference("username")!!
val prefPassword = findPreference("password")!!
val prefCertAlias = findPreference("certificate_alias")!!
@@ -226,23 +235,39 @@ class SettingsActivity: AppCompatActivity() {
prefUserName.summary = credentials.userName
prefUserName.text = credentials.userName
prefUserName.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newUserName ->
- model.updateCredentials(Credentials(newUserName as String, credentials.password, credentials.certificateAlias))
+ model.updateCredentials(Credentials(newUserName as String, credentials.password, credentials.authState, credentials.certificateAlias))
false
}
if (credentials.userName != null) {
- prefPassword.isVisible = true
- prefPassword.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newPassword ->
- model.updateCredentials(Credentials(credentials.userName, newPassword as String, credentials.certificateAlias))
- false
+ if (credentials.authState != null) {
+ prefPassword.isVisible = false
+ prefCredentials.isVisible = true
+ prefCredentials.setOnPreferenceClickListener{launchSetup()}
+ } else {
+ prefPassword.isVisible = true
+ prefCredentials.isVisible = false
+ prefPassword.onPreferenceChangeListener =
+ Preference.OnPreferenceChangeListener { _, newPassword ->
+ model.updateCredentials(
+ Credentials(
+ credentials.userName,
+ newPassword as String,
+ credentials.authState,
+ credentials.certificateAlias
+ )
+ )
+ false
+ }
}
} else
prefPassword.isVisible = false
+ prefCredentials.isVisible = false
prefCertAlias.summary = credentials.certificateAlias ?: getString(R.string.settings_certificate_alias_empty)
prefCertAlias.setOnPreferenceClickListener {
KeyChain.choosePrivateKeyAlias(requireActivity(), { newAlias ->
- model.updateCredentials(Credentials(credentials.userName, credentials.password, newAlias))
+ model.updateCredentials(Credentials(credentials.userName, credentials.password, credentials.authState, newAlias))
}, null, null, null, -1, credentials.certificateAlias)
true
}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt
index 074aabd3d99834b23b6109fe522527e1c95ae308..35248273dd7012ac7dfe1643180d33c6e285f399 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt
@@ -5,7 +5,9 @@
package at.bitfire.davdroid.ui.setup
import android.accounts.Account
+import android.accounts.AccountAuthenticatorResponse
import android.accounts.AccountManager
+import android.app.Activity
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
@@ -16,12 +18,15 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
+import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.*
+import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.DavService
import at.bitfire.davdroid.InvalidAccountException
+import at.bitfire.davdroid.MailAccountSyncHelper
import at.bitfire.davdroid.R
import at.bitfire.davdroid.databinding.LoginAccountDetailsBinding
import at.bitfire.davdroid.db.AppDatabase
@@ -31,7 +36,6 @@ import at.bitfire.davdroid.db.Service
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.TaskUtils
import at.bitfire.davdroid.settings.AccountSettings
-import at.bitfire.davdroid.settings.Settings
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.syncadapter.AccountUtils
import at.bitfire.davdroid.ui.account.AccountActivity
@@ -64,8 +68,8 @@ class AccountDetailsFragment : Fragment() {
// default account name
model.name.value =
- config.calDAV?.emails?.firstOrNull()
- ?: loginModel.credentials?.userName
+ loginModel.credentials?.userName
+ ?: config.calDAV?.emails?.firstOrNull()
?: loginModel.credentials?.certificateAlias
?: loginModel.baseURI?.host
@@ -74,6 +78,8 @@ class AccountDetailsFragment : Fragment() {
if (settings.containsKey(AccountSettings.KEY_CONTACT_GROUP_METHOD))
v.contactGroupMethod.isEnabled = false
+ v.contactGroupMethod.setSelection(1)
+
// CalDAV-specific
config.calDAV?.let {
val accountNameAdapter = ArrayAdapter(requireActivity(), android.R.layout.simple_list_item_1, it.emails)
@@ -99,6 +105,7 @@ class AccountDetailsFragment : Fragment() {
v.createAccount.visibility = View.GONE
model.createAccount(
+ requireActivity(),
name,
loginModel.credentials,
config,
@@ -107,11 +114,6 @@ class AccountDetailsFragment : Fragment() {
if (success) {
// close Create account activity
requireActivity().finish()
- // open Account activity for created account
- val intent = Intent(requireActivity(), AccountActivity::class.java)
- val account = Account(name, getString(R.string.account_type))
- intent.putExtra(AccountActivity.EXTRA_ACCOUNT, account)
- startActivity(intent)
} else {
Snackbar.make(requireActivity().findViewById(android.R.id.content), R.string.login_account_not_created, Snackbar.LENGTH_LONG).show()
@@ -134,6 +136,49 @@ class AccountDetailsFragment : Fragment() {
} else
v.contactGroupMethod.isEnabled = true
+ if (requireActivity().intent.getStringExtra(LoginActivity.SETUP_ACCOUNT_PROVIDER_TYPE) == LoginActivity.ACCOUNT_PROVIDER_EELO ||
+ requireActivity().intent.getStringExtra(LoginActivity.SETUP_ACCOUNT_PROVIDER_TYPE) == LoginActivity.ACCOUNT_PROVIDER_GOOGLE) {
+ val name = model.name.value
+ if (name.isNullOrBlank())
+ model.nameError.value = getString(R.string.login_account_name_required)
+ else {
+ val idx = v.contactGroupMethod.selectedItemPosition
+ val groupMethodName = resources.getStringArray(R.array.settings_contact_group_method_values)[idx]
+
+ model.createAccount(
+ requireActivity(),
+ name,
+ loginModel.credentials!!,
+ config,
+ GroupMethod.valueOf(groupMethodName)
+ ).observe(viewLifecycleOwner, Observer { success ->
+ if (success) {
+ Toast.makeText(context, R.string.message_account_added_successfully, Toast.LENGTH_LONG).show()
+ MailAccountSyncHelper.accountLoggedIn(context?.applicationContext)
+ requireActivity().setResult(Activity.RESULT_OK)
+ requireActivity().finish()
+
+ if (requireActivity().intent.hasExtra(AccountManager
+ .KEY_ACCOUNT_AUTHENTICATOR_RESPONSE) && requireActivity().intent
+ .getParcelableExtra(AccountManager
+ .KEY_ACCOUNT_AUTHENTICATOR_RESPONSE) != null) {
+ requireActivity().intent
+ .getParcelableExtra(AccountManager
+ .KEY_ACCOUNT_AUTHENTICATOR_RESPONSE)?.onResult(null)
+ }
+
+ if (requireActivity().intent.getStringExtra(LoginActivity.SETUP_ACCOUNT_PROVIDER_TYPE) == LoginActivity.ACCOUNT_PROVIDER_EELO) {
+ val intent = Intent("drive.services.InitializerService")
+ intent.setPackage(getString(R.string.e_drive_package_name))
+ intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, name)
+ intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, getString(R.string.eelo_account_type))
+ requireActivity().startService(intent)
+ }
+ }
+ })
+ }
+ }
+
return v.root
}
@@ -154,25 +199,73 @@ class AccountDetailsFragment : Fragment() {
nameError.value = null
}
- fun createAccount(name: String, credentials: Credentials?, config: DavResourceFinder.Configuration, groupMethod: GroupMethod): LiveData {
+ fun createAccount(activity: Activity, name: String, credentials: Credentials?, config: DavResourceFinder.Configuration, groupMethod: GroupMethod): LiveData {
val result = MutableLiveData()
viewModelScope.launch(Dispatchers.Default + NonCancellable) {
- val account = Account(name, context.getString(R.string.account_type))
+ var accountType = context.getString(R.string.account_type)
+ var addressBookAccountType = context.getString(R.string.account_type_address_book)
+
+ var baseURL : String? = null
+ if (config.calDAV != null) {
+ baseURL = config.calDAV.principal.toString()
+ }
+
+ when (activity.intent.getStringExtra(LoginActivity.SETUP_ACCOUNT_PROVIDER_TYPE)) {
+ LoginActivity.ACCOUNT_PROVIDER_EELO -> {
+ accountType = context.getString(R.string.eelo_account_type)
+ addressBookAccountType = context.getString(R.string.account_type_eelo_address_book)
+ baseURL = credentials?.serverUri.toString()
+ }
+ LoginActivity.ACCOUNT_PROVIDER_GOOGLE -> {
+ accountType = context.getString(R.string.google_account_type)
+ addressBookAccountType = context.getString(R.string.account_type_google_address_book)
+ baseURL = null
+ }
+ }
+
+ val account = Account(credentials?.userName, accountType)
// create Android account
- val userData = AccountSettings.initialUserData(credentials)
+ val userData = AccountSettings.initialUserData(credentials, baseURL)
Logger.log.log(Level.INFO, "Creating Android account with initial config", arrayOf(account, userData))
+ val accountManager = AccountManager.get(context)
+
if (!AccountUtils.createAccount(context, account, userData, credentials?.password)) {
- result.postValue(false)
- return@launch
+ if (accountType == context.getString(R.string.google_account_type)) {
+ for (googleAccount in accountManager.getAccountsByType(context.getString(
+ R.string.google_account_type))) {
+ if (userData.get(AccountSettings.KEY_EMAIL_ADDRESS) == accountManager
+ .getUserData(account, AccountSettings.KEY_EMAIL_ADDRESS)) {
+ accountManager.setUserData(googleAccount, AccountSettings.KEY_AUTH_STATE,
+ userData.getString(AccountSettings.KEY_AUTH_STATE))
+ }
+ }
+ } else {
+ result.postValue(false)
+ return@launch
+ }
}
+ if (!credentials?.authState?.accessToken.isNullOrEmpty()) {
+ accountManager.setAuthToken(account, Constants.AUTH_TOKEN_TYPE, credentials?.authState?.accessToken)
+ }
+
+ if (!credentials?.password.isNullOrEmpty()) {
+ accountManager.setPassword(account, credentials?.password)
+ }
+
+ ContentResolver.setSyncAutomatically(account, context.getString(R.string.notes_authority), true)
+ ContentResolver.setSyncAutomatically(account, context.getString(R.string.email_authority), true)
+ ContentResolver.setSyncAutomatically(account, context.getString(R.string.media_authority), true)
+ ContentResolver.setSyncAutomatically(account, context.getString(R.string.app_data_authority), true)
+ ContentResolver.setSyncAutomatically(account, context.getString(R.string.metered_edrive_authority), true)
+
// add entries for account to service DB
Logger.log.log(Level.INFO, "Writing account configuration to database", config)
try {
val accountSettings = AccountSettings(context, account)
- val defaultSyncInterval = settingsManager.getLong(Settings.DEFAULT_SYNC_INTERVAL)
+ val defaultSyncInterval = Constants.DEFAULT_CALENDAR_SYNC_INTERVAL
val refreshIntent = Intent(context, DavService::class.java)
refreshIntent.action = DavService.ACTION_REFRESH_COLLECTIONS
@@ -180,7 +273,14 @@ class AccountDetailsFragment : Fragment() {
val addrBookAuthority = context.getString(R.string.address_books_authority)
if (config.cardDAV != null) {
// insert CardDAV service
- val id = insertService(name, Service.TYPE_CARDDAV, config.cardDAV)
+ val id = insertService(
+ credentials?.userName ?: "",
+ credentials?.authState?.jsonSerializeString(),
+ accountType,
+ addressBookAccountType,
+ Service.TYPE_CARDDAV,
+ config.cardDAV
+ )
// initial CardDAV account settings
accountSettings.setGroupMethod(groupMethod)
@@ -197,7 +297,14 @@ class AccountDetailsFragment : Fragment() {
if (config.calDAV != null) {
// insert CalDAV service
- val id = insertService(name, Service.TYPE_CALDAV, config.calDAV)
+ val id = insertService(
+ credentials?.userName ?: "",
+ credentials?.authState?.jsonSerializeString(),
+ accountType,
+ addressBookAccountType,
+ Service.TYPE_CALDAV,
+ config.calDAV
+ )
// start CalDAV service detection (refresh collections)
refreshIntent.putExtra(DavService.EXTRA_DAV_SERVICE_ID, id)
@@ -226,9 +333,16 @@ class AccountDetailsFragment : Fragment() {
return result
}
- private fun insertService(accountName: String, type: String, info: DavResourceFinder.Configuration.ServiceInfo): Long {
+ private fun insertService(
+ accountName: String,
+ authState: String?,
+ accountType: String,
+ addressBookAccountType: String,
+ type: String,
+ info: DavResourceFinder.Configuration.ServiceInfo
+ ): Long {
// insert service
- val service = Service(0, accountName, type, info.principal)
+ val service = Service(0, accountName, authState, accountType, addressBookAccountType, type, info.principal)
val serviceId = db.serviceDao().insertOrReplace(service)
// insert home sets
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/CreateAccountActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/CreateAccountActivity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4eeb391fbc01e4ff879531f4ea12656988c2b479
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/CreateAccountActivity.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright © ECORP SAS 2022.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Public License v3.0
+ * which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+package at.bitfire.davdroid.ui.setup
+
+import android.os.Bundle
+import android.view.MenuItem
+import androidx.appcompat.app.AppCompatActivity
+import at.bitfire.davdroid.R
+
+class CreateAccountActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_create_account)
+
+ supportFragmentManager.beginTransaction().apply {
+ replace(R.id.content, SendInviteFragment())
+ commit()
+ }
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ if (item.itemId == android.R.id.home) {
+ finish()
+ return true
+ }
+ return false
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.kt
index f4f4b7bc01d5422af27ff5f49d2c516e0c34b494..a86b7697e820460bcc82d29ff2fa030f791eb7b3 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/DavResourceFinder.kt
@@ -163,7 +163,7 @@ class DavResourceFinder(
private fun checkUserGivenURL(baseURL: HttpUrl, service: Service, config: Configuration.ServiceInfo) {
log.info("Checking user-given URL: $baseURL")
- val davBase = DavResource(httpClient.okHttpClient, baseURL, log)
+ val davBase = DavResource(httpClient.okHttpClient, baseURL, loginModel.credentials?.authState?.accessToken, log)
try {
when (service) {
Service.CARDDAV -> {
@@ -176,7 +176,7 @@ class DavResourceFinder(
}
}
Service.CALDAV -> {
- davBase.propfind(0,
+ davBase.propfind(1,
ResourceType.NAME, DisplayName.NAME, CalendarColor.NAME, CalendarDescription.NAME, CalendarTimezone.NAME, CurrentUserPrivilegeSet.NAME, SupportedCalendarComponentSet.NAME,
CalendarHomeSet.NAME,
CurrentUserPrincipal.NAME
@@ -199,13 +199,15 @@ class DavResourceFinder(
fun queryEmailAddress(principal: HttpUrl): List {
val mailboxes = LinkedList()
try {
- DavResource(httpClient.okHttpClient, principal, log).propfind(0, CalendarUserAddressSet.NAME) { response, _ ->
+ DavResource(httpClient.okHttpClient, principal, null, log).propfind(0, CalendarUserAddressSet.NAME) { response, _ ->
response[CalendarUserAddressSet::class.java]?.let { addressSet ->
for (href in addressSet.hrefs)
try {
val uri = URI(href)
- if (uri.scheme.equals("mailto", true))
+ if (uri.scheme.equals("mailto", true)) {
+ log.info("myenail: ${uri.schemeSpecificPart}")
mailboxes.add(uri.schemeSpecificPart)
+ }
} catch(e: URISyntaxException) {
log.log(Level.WARNING, "Couldn't parse user address", e)
}
@@ -313,7 +315,7 @@ class DavResourceFinder(
fun providesService(url: HttpUrl, service: Service): Boolean {
var provided = false
try {
- DavResource(httpClient.okHttpClient, url, log).options { capabilities, _ ->
+ DavResource(httpClient.okHttpClient, url, loginModel.credentials?.authState?.accessToken, log).options { capabilities, _ ->
if ((service == Service.CARDDAV && capabilities.contains("addressbook")) ||
(service == Service.CALDAV && capabilities.contains("calendar-access")))
provided = true
@@ -401,7 +403,7 @@ class DavResourceFinder(
@Throws(IOException::class, HttpException::class, DavException::class)
fun getCurrentUserPrincipal(url: HttpUrl, service: Service?): HttpUrl? {
var principal: HttpUrl? = null
- DavResource(httpClient.okHttpClient, url, log).propfind(0, CurrentUserPrincipal.NAME) { response, _ ->
+ DavResource(httpClient.okHttpClient, url, loginModel.credentials?.authState?.accessToken, log).propfind(0, CurrentUserPrincipal.NAME) { response, _ ->
response[CurrentUserPrincipal::class.java]?.href?.let { href ->
response.requestedUrl.resolve(href)?.let {
log.info("Found current-user-principal: $it")
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/DefaultLoginCredentialsFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/DefaultLoginCredentialsFragment.kt
index 445079025c282ff85b97e9a500042ca53e3c18fa..24f939cf89bd6a9865d958f60ad7d6ad6d70e64a 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/setup/DefaultLoginCredentialsFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/DefaultLoginCredentialsFragment.kt
@@ -179,7 +179,7 @@ class DefaultLoginCredentialsFragment : Fragment() {
loginModel.credentials = when {
// username/password and client certificate
model.loginUseUsernamePassword.value == true && model.loginUseClientCertificate.value == true ->
- Credentials(username, password, alias)
+ Credentials(username, password, null, alias)
// user/name password only
model.loginUseUsernamePassword.value == true && model.loginUseClientCertificate.value == false ->
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/DetectConfigurationFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/DetectConfigurationFragment.kt
index 48afdcfe5255fcd4bc00226fd37b3e19e566206c..e90b228947cfce5f2087416072899f483bdccf97 100644
--- a/app/src/main/java/at/bitfire/davdroid/ui/setup/DetectConfigurationFragment.kt
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/DetectConfigurationFragment.kt
@@ -17,10 +17,12 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
+import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.R
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.ui.DebugInfoActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import at.bitfire.davdroid.ECloudAccountHelper
import java.lang.ref.WeakReference
import java.util.logging.Level
import kotlin.concurrent.thread
@@ -33,6 +35,11 @@ class DetectConfigurationFragment: Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ if (model.blockProceedWithLogin(loginModel)) {
+ ECloudAccountHelper.showMultipleECloudAccountNotAcceptedDialog(requireActivity())
+ return
+ }
+
model.detectConfiguration(loginModel).observe(this, { result ->
// save result for next step
loginModel.configuration = result
@@ -63,6 +70,16 @@ class DetectConfigurationFragment: Fragment() {
private var detectionThread: WeakReference? = null
private var result = MutableLiveData()
+ /**
+ * User can't login using multiple ecloud accounts.
+ * This method checks if the login host is eelo_host then, check user already has any eelo account set up.
+ * If found eCloundAccount return true, false otherwise.
+ */
+ fun blockProceedWithLogin(loginModel: LoginModel) : Boolean {
+ val context = getApplication()
+ return (loginModel.baseURI?.host.equals(Constants.EELO_SYNC_HOST) && ECloudAccountHelper.alreadyHasECloudAccount(context))
+ }
+
fun detectConfiguration(loginModel: LoginModel): LiveData {
synchronized(result) {
if (detectionThread != null)
@@ -108,10 +125,11 @@ class DetectConfigurationFragment: Fragment() {
if (model.configuration?.encountered401 == true)
message += "\n\n" + getString(R.string.login_username_password_wrong)
- return MaterialAlertDialogBuilder(requireActivity())
+ return MaterialAlertDialogBuilder(requireActivity(), R.style.CustomAlertDialogStyle)
.setTitle(R.string.login_configuration_detection)
.setIcon(R.drawable.ic_error)
.setMessage(message)
+ .setCancelable(false)
.setNeutralButton(R.string.login_view_logs) { _, _ ->
val intent = DebugInfoActivity.IntentBuilder(requireActivity())
.withLogs(model.configuration?.logs)
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..626a2808534a0ba339458eb2929554e44f895dc4
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorFragment.kt
@@ -0,0 +1,198 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.ui.setup
+
+import android.content.Context
+import android.net.ConnectivityManager
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.core.widget.doOnTextChanged
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.fragment.app.viewModels
+import at.bitfire.davdroid.Constants
+import at.bitfire.davdroid.ECloudAccountHelper
+import at.bitfire.davdroid.R
+import at.bitfire.davdroid.databinding.FragmentEeloAuthenticatorBinding
+import at.bitfire.davdroid.db.Credentials
+import kotlinx.android.synthetic.main.fragment_eelo_authenticator.*
+import kotlinx.android.synthetic.main.fragment_eelo_authenticator.view.*
+import java.net.URI
+
+class EeloAuthenticatorFragment : Fragment() {
+
+ private val model by viewModels()
+ private val loginModel by activityViewModels()
+
+ val TOGGLE_BUTTON_CHECKED_KEY = "toggle_button_checked"
+ var toggleButtonState = false
+
+ private fun isNetworkAvailable(): Boolean {
+ val connectivityManager = requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ val activeNetworkInfo = connectivityManager.activeNetworkInfo
+ return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+
+ if (!isNetworkAvailable()) {
+ Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+
+ val v = FragmentEeloAuthenticatorBinding.inflate(inflater, container, false)
+ v.lifecycleOwner = this
+ v.model = model
+
+ v.root.server_toggle_button.setOnClickListener() { expandCollapse() }
+
+ v.root.sign_in.setOnClickListener { login() }
+
+ v.root.urlpwd_user_name.doOnTextChanged { text, _, _, _ ->
+ val domain = computeDomain(text)
+ if (domain.isEmpty()) {
+ requireView().urlpwd_server_uri_layout.hint = getString(R.string.login_server_uri)
+ } else {
+ requireView().urlpwd_server_uri_layout.hint = getString(R.string.login_server_uri_custom, domain)
+ }
+ }
+
+ // code below is to draw toggle button in its correct state and show or hide server url input field
+ //add by Vincent, 18/02/2019
+ if (savedInstanceState != null) {
+ toggleButtonState = savedInstanceState.getBoolean(TOGGLE_BUTTON_CHECKED_KEY, false)
+ }
+
+ //This allow the button to be redraw in the correct state if user turn screen
+ if (toggleButtonState) {
+ v.root.server_toggle_button.setCompoundDrawablesWithIntrinsicBounds(null, null , resources.getDrawable(R.drawable.ic_expand_less), null)
+ v.root.urlpwd_server_uri_layout.setVisibility(View.VISIBLE)
+ v.root.urlpwd_server_uri.setEnabled(true)
+ } else {
+ v.root.server_toggle_button.setCompoundDrawablesWithIntrinsicBounds(null, null , resources.getDrawable(R.drawable.ic_expand_more), null)
+ v.root.urlpwd_server_uri_layout.setVisibility(View.GONE)
+ v.root.urlpwd_server_uri.setEnabled(false)
+ }
+ return v.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ if (model.blockProceedWithLogin()) {
+ ECloudAccountHelper.showMultipleECloudAccountNotAcceptedDialog(requireActivity())
+ }
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ outState.putBoolean(TOGGLE_BUTTON_CHECKED_KEY, toggleButtonState)
+ super.onSaveInstanceState(outState)
+ }
+
+ private fun computeDomain(username: CharSequence?) : String {
+ var domain = ""
+ if (!username.isNullOrEmpty() && username.toString().contains("@")) {
+ var dns = username.toString().substringAfter("@")
+ if (dns == Constants.E_SYNC_URL) {
+ dns = Constants.EELO_SYNC_HOST
+ }
+ domain = "https://$dns"
+ }
+ return domain
+ }
+
+ private fun login() {
+ if (!isNetworkAvailable()) {
+ Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+
+ if ((urlpwd_user_name.text.toString() != "") && (urlpwd_password.text.toString() != "")) {
+ if (validate())
+ requireFragmentManager().beginTransaction()
+ .replace(android.R.id.content, DetectConfigurationFragment(), null)
+ .addToBackStack(null)
+ .commit()
+ } else {
+ Toast.makeText(context, "Please enter a valid username and password", Toast.LENGTH_LONG).show()
+ }
+
+ }
+
+ private fun validate(): Boolean {
+ var valid = false
+
+ var serverUrl = requireView().urlpwd_server_uri.text.toString()
+
+ if (serverUrl.isEmpty()) {
+ serverUrl = computeDomain(requireView().urlpwd_user_name.text.toString())
+ }
+
+ fun validateUrl() {
+
+ model.baseUrlError.value = null
+ try {
+ val uri = URI(serverUrl)
+ if (uri.scheme.equals("http", true) || uri.scheme.equals("https", true)) {
+ valid = true
+ loginModel.baseURI = uri
+ } else
+ model.baseUrlError.value = getString(R.string.login_url_must_be_http_or_https)
+ } catch (e: Exception) {
+ model.baseUrlError.value = e.localizedMessage
+ }
+ }
+
+ when {
+
+ model.loginWithUrlAndTokens.value == true -> {
+ validateUrl()
+
+ val userName = requireView().urlpwd_user_name.text.toString()
+ val password = requireView().urlpwd_password.text.toString()
+
+ if (loginModel.baseURI != null) {
+ valid = true
+ loginModel.credentials = Credentials(userName.toLowerCase(), password, null, null, loginModel.baseURI)
+ }
+ }
+
+ }
+
+ return valid
+ }
+
+ /**
+ * Show/Hide panel containing server's uri input field.
+ */
+ private fun expandCollapse() {
+ if (!toggleButtonState) {
+ server_toggle_button.setCompoundDrawablesWithIntrinsicBounds(null, null , resources.getDrawable(R.drawable.ic_expand_less), null)
+ urlpwd_server_uri_layout.setVisibility(View.VISIBLE)
+ urlpwd_server_uri.setEnabled(true)
+ toggleButtonState = true
+ } else {
+ server_toggle_button.setCompoundDrawablesWithIntrinsicBounds(null, null , resources.getDrawable(R.drawable.ic_expand_more), null)
+ urlpwd_server_uri_layout.setVisibility(View.GONE)
+ urlpwd_server_uri.setEnabled(false)
+ toggleButtonState = false
+ }
+ }
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorModel.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ce607af20cf88c454b59cc16796c6541ecf9967c
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorModel.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.ui.setup
+
+import android.app.Application
+import android.content.Intent
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import at.bitfire.davdroid.ECloudAccountHelper
+
+class EeloAuthenticatorModel(application: Application) : AndroidViewModel(application) {
+
+ private var initialized = false
+
+ val loginWithUrlAndTokens = MutableLiveData()
+
+ val baseUrl = MutableLiveData()
+ val baseUrlError = MutableLiveData()
+
+ val emailAddress = MutableLiveData()
+ val emailAddressError = MutableLiveData()
+
+ val username = MutableLiveData()
+ val usernameError = MutableLiveData()
+
+ val password = MutableLiveData()
+ val passwordError = MutableLiveData()
+
+ val certificateAlias = MutableLiveData()
+ val certificateAliasError = MutableLiveData()
+
+ init {
+ loginWithUrlAndTokens.value = true
+ }
+
+ fun initialize(intent: Intent) {
+ if (initialized)
+ return
+
+ // we've got initial login data
+ val givenUrl = intent.getStringExtra(LoginActivity.EXTRA_URL)
+ val givenUsername = intent.getStringExtra(LoginActivity.EXTRA_USERNAME)
+ val givenPassword = intent.getStringExtra(LoginActivity.EXTRA_PASSWORD)
+
+ baseUrl.value = givenUrl
+
+ password.value = givenPassword
+
+ initialized = true
+ }
+
+ fun blockProceedWithLogin(): Boolean {
+ val context = getApplication()
+ return ECloudAccountHelper.alreadyHasECloudAccount(context)
+ }
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/GoogleAuthenticatorFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/GoogleAuthenticatorFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..cba6d8e54663fc4620e9008eae6a2980720f160a
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/GoogleAuthenticatorFragment.kt
@@ -0,0 +1,434 @@
+/*
+ * Copyright ECORP SAS 2022
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.bitfire.davdroid.ui.setup
+
+import android.app.Activity
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.net.ConnectivityManager
+import android.os.AsyncTask
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.text.Layout
+import android.text.SpannableString
+import android.text.style.AlignmentSpan
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.fragment.app.viewModels
+import at.bitfire.davdroid.R
+import at.bitfire.davdroid.authorization.IdentityProvider
+import at.bitfire.davdroid.databinding.FragmentGoogleAuthenticatorBinding
+import at.bitfire.davdroid.db.Credentials
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import net.openid.appauth.*
+import org.json.JSONException
+import org.json.JSONObject
+import java.io.BufferedReader
+import java.io.IOException
+import java.io.InputStream
+import java.io.InputStreamReader
+import java.net.HttpURLConnection
+import java.net.MalformedURLException
+import java.net.URI
+import java.net.URL
+
+class GoogleAuthenticatorFragment : Fragment(), AuthorizationService.TokenResponseCallback {
+
+ private val model by viewModels()
+ private val loginModel by activityViewModels()
+
+ private val extraAuthServiceDiscovery = "authServiceDiscovery"
+ private val extraClientSecret = "clientSecret"
+
+ private var authState: AuthState? = null
+ private var authorizationService: AuthorizationService? = null
+
+ private val bufferSize = 1024
+ private var userInfoJson: JSONObject? = null
+
+ private fun isNetworkAvailable(): Boolean {
+ val connectivityManager = requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ val activeNetworkInfo = connectivityManager.activeNetworkInfo
+ return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View {
+ // Initialise the authorization service
+ authorizationService = AuthorizationService(requireContext())
+
+ val v = FragmentGoogleAuthenticatorBinding.inflate(inflater, container, false)
+ v.lifecycleOwner = this
+ v.model = model
+
+ activity?.intent?.let {
+ model.initialize(it)
+ val builder = MaterialAlertDialogBuilder(requireContext(), R.style.CustomAlertDialogStyle)
+
+ if (!with(it) { getBooleanExtra(LoginActivity.ACCOUNT_PROVIDER_GOOGLE_AUTH_COMPLETE, false) }) {
+ val title = SpannableString(getString(R.string.google_alert_title))
+ // alert dialog title align center
+ title.setSpan(
+ AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER),
+ 0,
+ title.length,
+ 0
+ )
+
+ builder.setTitle(title)
+ builder.setMessage(getString(R.string.google_alert_message))
+ builder.setPositiveButton(android.R.string.yes) { dialog, which ->
+ // Get all the account providers
+ val providers = IdentityProvider.getEnabledProviders(context)
+
+ // Iterate over the account providers
+ for (idp in providers) {
+ val retrieveCallback = AuthorizationServiceConfiguration.RetrieveConfigurationCallback { serviceConfiguration, ex ->
+ if (ex == null && serviceConfiguration != null) {
+ makeAuthRequest(serviceConfiguration, idp)
+ } else if (!isNetworkAvailable()) {
+ Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ } else {
+ Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+ }
+
+ if (idp.name == getString(R.string.google_name)) {
+ // Get configurations for the Google account provider
+ idp.retrieveConfig(context, retrieveCallback)
+ }
+ }
+ }
+ builder.setCancelable(false)
+
+ val dialog = builder.create()
+ dialog.show()
+ }
+ else {
+ if (authState == null) {
+ val response = AuthorizationResponse.fromIntent(requireActivity().intent)
+ val ex = AuthorizationException.fromIntent(requireActivity().intent)
+ authState = AuthState(response, ex)
+
+ if (response != null) {
+ exchangeAuthorizationCode(response)
+ } else if (!isNetworkAvailable()) {
+ Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ } else {
+ Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+ }
+ }
+ }
+
+ return v.root
+ }
+
+ private fun makeAuthRequest(
+ serviceConfig: AuthorizationServiceConfiguration,
+ idp: IdentityProvider) {
+
+ if (!isNetworkAvailable()) {
+ Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+
+ val authRequest = AuthorizationRequest.Builder(
+ serviceConfig,
+ idp.clientId,
+ ResponseTypeValues.CODE,
+ idp.redirectUri)
+ .setScope(idp.scope)
+ .build()
+
+ authorizationService?.performAuthorizationRequest(
+ authRequest,
+ createPostAuthorizationIntent(
+ requireContext(),
+ authRequest,
+ serviceConfig.discoveryDoc,
+ idp.clientSecret),
+ authorizationService?.createCustomTabsIntentBuilder()!!
+ .build())
+
+ requireActivity().setResult(Activity.RESULT_OK)
+ requireActivity().finish()
+ }
+
+ private fun createPostAuthorizationIntent(
+ context: Context,
+ request: AuthorizationRequest,
+ discoveryDoc: AuthorizationServiceDiscovery?,
+ clientSecret: String?): PendingIntent {
+ val intent = Intent(context, LoginActivity::class.java)
+
+ if (discoveryDoc != null) {
+ intent.putExtra(extraAuthServiceDiscovery, discoveryDoc.docJson.toString())
+ }
+
+ if (clientSecret != null) {
+ intent.putExtra(extraClientSecret, clientSecret)
+ }
+
+ intent.putExtra(LoginActivity.SETUP_ACCOUNT_PROVIDER_TYPE, LoginActivity.ACCOUNT_PROVIDER_GOOGLE)
+ intent.putExtra(LoginActivity.ACCOUNT_PROVIDER_GOOGLE_AUTH_COMPLETE, true)
+
+ return PendingIntent.getActivity(context, request.hashCode(), intent, 0)
+ }
+
+ private fun exchangeAuthorizationCode(authorizationResponse: AuthorizationResponse) {
+ if (!isNetworkAvailable()) {
+ Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+
+ val additionalParams = HashMap()
+ if (getClientSecretFromIntent(requireActivity().intent) != null) {
+ additionalParams["client_secret"] = getClientSecretFromIntent(requireActivity().intent)
+ }
+ performTokenRequest(authorizationResponse.createTokenExchangeRequest(additionalParams))
+ }
+
+ private fun getClientSecretFromIntent(intent: Intent): String? {
+ return if (!intent.hasExtra(extraClientSecret)) {
+ null
+ }
+ else intent.getStringExtra(extraClientSecret)
+ }
+
+
+ private fun performTokenRequest(request: TokenRequest) {
+ if (!isNetworkAvailable()) {
+ Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+
+ authorizationService?.performTokenRequest(
+ request, this)
+ }
+
+ override fun onTokenRequestCompleted(response: TokenResponse?, ex: AuthorizationException?) {
+ authState?.update(response, ex)
+
+ getAccountInfo()
+ }
+
+ private fun getAccountInfo() {
+ if (!isNetworkAvailable()) {
+ Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+
+ val discoveryDoc = getDiscoveryDocFromIntent(requireActivity().intent)
+
+ if (!authState!!.isAuthorized
+ || discoveryDoc == null
+ || discoveryDoc.userinfoEndpoint == null) {
+ Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+ else {
+ object : AsyncTask() {
+ override fun doInBackground(vararg params: Void): Void? {
+ if (fetchUserInfo()) {
+ Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+
+ return null
+ }
+ }.execute()
+ }
+ }
+
+ private fun getDiscoveryDocFromIntent(intent: Intent): AuthorizationServiceDiscovery? {
+ if (!intent.hasExtra(extraAuthServiceDiscovery)) {
+ return null
+ }
+ val discoveryJson = intent.getStringExtra(extraAuthServiceDiscovery)
+ try {
+ return AuthorizationServiceDiscovery(JSONObject(discoveryJson))
+ }
+ catch (ex: JSONException) {
+ throw IllegalStateException("Malformed JSON in discovery doc")
+ }
+ catch (ex: AuthorizationServiceDiscovery.MissingArgumentException) {
+ throw IllegalStateException("Malformed JSON in discovery doc")
+ }
+
+ }
+
+ private fun fetchUserInfo(): Boolean {
+ var error = false
+
+ if (authState!!.authorizationServiceConfiguration == null) {
+ return true
+ }
+
+ authState!!.performActionWithFreshTokens(authorizationService!!, AuthState.AuthStateAction { accessToken, _, ex ->
+ if (ex != null) {
+ error = true
+ return@AuthStateAction
+ }
+
+ val discoveryDoc = getDiscoveryDocFromIntent(requireActivity().intent)
+ ?: throw IllegalStateException("no available discovery doc")
+
+ val userInfoEndpoint: URL
+ try {
+ userInfoEndpoint = URL(discoveryDoc.userinfoEndpoint!!.toString())
+ }
+ catch (urlEx: MalformedURLException) {
+ error = true
+ return@AuthStateAction
+ }
+
+ var userInfoResponse: InputStream? = null
+ try {
+ val conn = userInfoEndpoint.openConnection() as HttpURLConnection
+ conn.setRequestProperty("Authorization", "Bearer " + accessToken!!)
+ conn.instanceFollowRedirects = false
+ userInfoResponse = conn.inputStream
+ val response = readStream(userInfoResponse)
+ updateUserInfo(JSONObject(response))
+ }
+ catch (ioEx: IOException) {
+ error = true
+ }
+ catch (jsonEx: JSONException) {
+ error = true
+ }
+ finally {
+ if (userInfoResponse != null) {
+ try {
+ userInfoResponse.close()
+ }
+ catch (ioEx: IOException) {
+ error = true
+ }
+
+ }
+ }
+ })
+
+ return error
+ }
+
+ @Throws(IOException::class)
+ private fun readStream(stream: InputStream?): String {
+ val br = BufferedReader(InputStreamReader(stream!!))
+ val buffer = CharArray(bufferSize)
+ val sb = StringBuilder()
+ var readCount = br.read(buffer)
+ while (readCount != -1) {
+ sb.append(buffer, 0, readCount)
+ readCount = br.read(buffer)
+ }
+ return sb.toString()
+ }
+
+ private fun updateUserInfo(jsonObject: JSONObject) {
+ Handler(Looper.getMainLooper()).post {
+ userInfoJson = jsonObject
+ onAccountInfoGotten()
+ }
+ }
+
+ private fun onAccountInfoGotten() {
+ if (!isNetworkAvailable()) {
+ Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+
+ if (userInfoJson != null) {
+ try {
+
+ var emailAddress = ""
+ if (userInfoJson!!.has("email")) {
+ emailAddress = userInfoJson!!.getString("email")
+ }
+
+ if (validate(emailAddress, authState!!))
+ requireFragmentManager().beginTransaction()
+ .replace(android.R.id.content, DetectConfigurationFragment(), null)
+ .addToBackStack(null)
+ .commit()
+
+ }
+ catch (ex: JSONException) {
+ Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+
+ }
+ else {
+ Toast.makeText(context, "Login failed, please try again later", Toast.LENGTH_LONG).show()
+ requireActivity().finish()
+ }
+
+ }
+
+ private fun validate(emailAddress: String, authState: AuthState): Boolean {
+ var valid = false
+
+ fun validateUrl() {
+ model.baseUrlError.value = null
+ try {
+ val uri = URI("https://apidata.googleusercontent.com/caldav/v2/$emailAddress/user")
+ if (uri.scheme.equals("http", true) || uri.scheme.equals("https", true)) {
+ valid = true
+ loginModel.baseURI = uri
+ } else
+ model.baseUrlError.value = getString(R.string.login_url_must_be_http_or_https)
+ } catch (e: Exception) {
+ model.baseUrlError.value = e.localizedMessage
+ }
+ }
+
+ when {
+
+ model.loginWithUrlAndTokens.value == true -> {
+ validateUrl()
+
+ model.usernameError.value = null
+
+ if (loginModel.baseURI != null) {
+ valid = true
+ loginModel.credentials = Credentials(emailAddress, null, authState, null)
+ }
+ }
+
+ }
+
+ return valid
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ authorizationService?.dispose()
+ }
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/GoogleAuthenticatorModel.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/GoogleAuthenticatorModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d7721753794b516c2f7930a8f300603a895785cd
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/GoogleAuthenticatorModel.kt
@@ -0,0 +1,48 @@
+package at.bitfire.davdroid.ui.setup
+
+import android.content.Intent
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+
+class GoogleAuthenticatorModel: ViewModel() {
+
+ private var initialized = false
+
+ val loginWithUrlAndTokens = MutableLiveData()
+
+ val baseUrl = MutableLiveData()
+ val baseUrlError = MutableLiveData()
+
+ val emailAddress = MutableLiveData()
+ val emailAddressError = MutableLiveData()
+
+ val username = MutableLiveData()
+ val usernameError = MutableLiveData()
+
+ val password = MutableLiveData()
+ val passwordError = MutableLiveData()
+
+ val certificateAlias = MutableLiveData()
+ val certificateAliasError = MutableLiveData()
+
+ init {
+ loginWithUrlAndTokens.value = true
+ }
+
+ fun initialize(intent: Intent) {
+ if (initialized)
+ return
+
+ // we've got initial login data
+ val givenUrl = intent.getStringExtra(LoginActivity.EXTRA_URL)
+ val givenUsername = intent.getStringExtra(LoginActivity.EXTRA_USERNAME)
+ val givenPassword = intent.getStringExtra(LoginActivity.EXTRA_PASSWORD)
+
+ baseUrl.value = givenUrl
+
+ password.value = givenPassword
+
+ initialized = true
+ }
+
+}
diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/InviteSuccessfulFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/InviteSuccessfulFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4ee8cc6fb57bdacc7e81ed7e8d7bee5a1026ddc6
--- /dev/null
+++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/InviteSuccessfulFragment.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright © ECORP SAS 2022.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Public License v3.0
+ * which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+package at.bitfire.davdroid.ui.setup
+
+import android.accounts.AccountManager
+import android.accounts.AccountManagerCallback
+import android.app.Activity.RESULT_OK
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.Fragment
+import at.bitfire.davdroid.R
+
+class InviteSuccessfulFragment : Fragment() {
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ (activity as AppCompatActivity?)?.supportActionBar?.hide()
+ return inflater.inflate(R.layout.fragment_invite_successful, container, false)
+ }
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val instructions = view.findViewById(R.id.instructions)
+ val formattedText = view.context.getText(R.string.instructions)
+ instructions.text = formattedText
+ view.findViewById
- Видимо име
- Адрес на WebDAV
- Недействителен адрес
- Потребителско име
- Парола
- Монтиране
- Няма услуга на WebDAV на адреса
- Достъпва се файл на WebDAV
- Изтегля се файл на WebDAV
- Изпраща се файл на WebDAV
- Дял на WebDAV
-
- Разрешения на DAVx⁵
- Необходими са допълнителни разрешения
- Приложението %s е твърде старо
- Минимално необходимо издание: %1$s
- Грешка при удостоверяване (проверете данните за вход)
- Грешка с входа/изхода или мрежата – %s
- Грешка в сървъра на HTTP – %s
- Грешка в местното хранилище – %s
- Повторен опит
- Преглед
- Получен е недействителен контакт от сървъра
- Получено е недействително събитие от сървъра
- Получен е недействителен файл от сървъра
- Пренебрегване на сбъркани данни
-
- DAVx⁵: Защита на връзката
- DAVx⁵ се натъкна на непознат сертификат. Ще му се довериш ли?
+
+ DAVx⁵
+ DAVx⁵ адресен указател
+ Адресни указатели
+ Премахване
+ Отказ
+ Задължително поле
+ Помощ
+ Изпрати
+ Други важни съобщения
+ Синхронизиране
+ Грешки при синхронизирането
+ Важни грешки, които спират синхронизирането, като неочаквани отговори от сървъра
+ Предупреждения от синхронизирането
+ Грешки с входа/изхода и мрежата.
+ Проточване на времето, проблеми с връзката, и т.н. (обикновенно временни)
+
+ Автоматична синхронизация
+ Планувана синхронизация
+ Устройството ти ще възпрепятства DAVx⁵ да синхронизира. За да се извършва редовна, периодична синхронизация, изключи “оптимизация на батерията”.
+ Изключи за DAVx⁵
+ Не показвай отново
+ Не сега
+ Информация за отворения код
+ Радваме се, че изполваш DAVx⁵ – софтуер с отворен код (GPLv3). Тъй като разработването на DAVx⁵ е много трудоемка работа, моля да направиш дарение.
+ Покажи страницата за дарения
+ Може би по-късно
+ Повече информация
+ OpenTasks не е инсталирана.
+ За да синхронизираш задачи е нужна програмата OpenTasks. Тя не е необходима за синхронизиране на контакти или събития.
+ След като инсталирате OpenTasks трябва да инсталирате отново DAVx⁵ и да добавите своите регистрации (грешката е в Андроид).
+ Инсталирай OpenTasks
+
+ Библиотеки
+ Версия %1$s (%2$d)
+ Компилирана на %s
+ Тази версия може да се разпространява само чрез Google Play.
+ Тази програма няма абсолютно никаква гаранция. Тя е свободен софтуер и можеш да я разпространяваш при определени условия.
+
+ Не можах да създада файл с протокола
+ DAVx⁵ протоколиране
+ Сега действията на %s се протоколират
+ Изпрати протокола
+
+ Адаптор за CalDAV/CardDAV синхронизиране
+ Относно / Лиценз
+ Настройки
+ Новини и нови версии
+ Външни препратки
+ Интернет страница
+ Упътване
+ Често задавани въпроси
+ Помощ и форум
+ Дарения
+ Добре дошъл при DAVx⁵!\n\nМоже да добавиш CalDAV/CardDAV регистрация сега.
+ Включи
+
+ Откриването на услугите се провали
+ Не можах да опресня списъка на ресурсите
+
+ Настройки
+ Покажи/сподели детайли за софтуера и настройките
+ Подробно протоколиране
+ Протоколирането е включено
+ Протоколирането е изключено
+ Връзка
+ Промени прокси настройките
+ Изполвай долупосочените прокси настройки
+ Изпозвай прокси настройките на системата
+ Име на HTTP прокси сървъра
+ Порт на HTTP прокси
+ Защита
+ Загуби доверието в системните сертификати
+ Издатели на сертификати познати на системата или добавени от потребителя няма да бъдат доверени
+ Издателите на сертификатите познати на системата или добавени от потребителя ще бъдат доверени (препоръчително)
+ Настройки за съобщенията
+ Управлявление на каналите за съобщения и техните настройки
+ Всички подсказки ще се покажат отново
+
+ CardDAV
+ CalDAV
+ Webcal
+ Няма адресни указатели (все още)
+ Няма календари (все още)
+ Няма абонаменти за календари (все още)
+ Дръпни надолу за да освежиш списъка от сървъра.
+ Синхронизирай сега
+ Сега се синхронизира
+ Настройки на регистрацията
+ Преименовай регистрацията
+ Данните, който не са синхронизирани със сървъра, може да се изпарят. След преименоването е нужно ново синхронизаране. Ново име на регистрацията:
+ Преименоване
+ Изтриване на регистрация
+ Наистина ли да изтрия регистрацията?
+ Всички местни копия на адресни указатели, календари и списъци със задачи ще бъдат изтрити.
+ синхронизирай този ресурс
+ само за четене
+ календар
+ списък със задачи
+ Опресни списъка с адресни указатели
+ Създай нов адресен указател
+ Опресни списъка с календари
+ Създай нов календар
+ Инсталирай ICSx⁵
+
+ Добави регистрация
+ Вход с електронен адрес
+ Електронен адрес
+ Нужен е действителен електронен адрес
+ Парола
+ Трябва парола
+ Вход с URL и потребителско име
+ Адресът трябва да започва с http(s)://
+ Адресът трябва да започва с https://
+ Нужен е адрес на сървър
+ Потребителско име
+ Нужно е потребителско име
+ Основен адрес (URL)
+ Влез с URL и сертификат
+ Избери сертификат
+ Назад
+ Създай регистрация
+ Име на регистрация
+ Метод за съхранение на групи от контакти:
+ Изисква се име на регистрацията
+ Това име на регистрация вече се използва
+ Регистрацията не можеше да бъде създадена
+ Откриване на настройките
+ Изчакай, разпитвам сървъра…
+ Не бяха открити CalDAV или CardDAV услуги.
+ Покажи подробности
+
+ Настройки: %s
+ Синхронизация
+ Период за синхронизиране на контактите
+ Само изрично
+ Всяка %dминута и веднага при местна промяна
+ Период за синхронизиране на календари
+ Период за синхронизиране на задачи
+
+ - Само изрично
+ - Всеки 15 минути
+ - На половин час
+ - Всеки час
+ - На два часа
+ - На четири часа
+ - Ежедневно
+
+ Синхронизирай само през WiFi
+ Синхронизация се прави само при WiFi връзки
+ Вида на връзката не е от значение
+ WiFi SSID ограничения
+ Ще синхронизира само през %s
+ Ще синхронизира само пред %s(изисква услуга за местоположението)
+ Всички WiFi връзки ще бъдат използвани
+ Списък на разделени със запетайка имена на мрежи (SSID WiFi) (остави празно за всички мрежи)
+ За да се четат имената на WiFi мрежите са необходими право да се чете местоположението и постоянно включена услуга за местоположението.
+ Повече информация (често задавани въпроси)
+ Потребителско име
+ Въведи потребитеско име:
+ Парола
+ Промени паролата съгласно твоя сървър.
+ Въведи парола:
+ CalDAV
+ Ограничения за събития от миналото
+ Всички събития ще се синхронизират
+
+ - Събития минали преди повече от ден ще бъдат пренебреграти.
+ - Събития минали преди повече от %dдни ще бъдат пренебрегнати.
+
+ Събития преди повече от този брой дни в миналото ще бъдат пренебрегнати (може да бъде 0). Остави празно за да се синхронизират всички събития.
+ Управлявай цвета на календарите
+ Цветовете на календарите се управляват от DAVx⁵
+ Цветовете на календарите не се задават от DAVx⁵
+ Поддръжка на цветове за събития
+ Синхронизирай цветовете на събитията
+ Не синхронизирай цветовете на събитията
+ CardDAV
+ Метод за съхранение на групи от контакти
+ Метод за съхранение на групи от контакти
+
+ Създай адресен указател
+ Моят адресен указател
+ Създай календар
+ Часова зона
+ Изисква се часова зона
+ Възможни компоненти в календара
+ Събития
+ Задачи
+ Бележки / журнал
+ Комбинирано (събития и задачи)
+ Цвят
+ Създаване на ресурс
+ Заглавие
+ Изисква се заглавие
+ Описание
+ Място на съхранение
+ Създай
+ Изтрий ресурс
+ Сигурен ли си?
+ Този ресурс (%s) и всичките данни в него ще бъдат изтрити.
+ Изтрий тези данни от сървъра
+ Изтриване на ресурс
+ Направи само за четене
+ Свойства
+ Адрес (URL)
+ Копирай адреса
+
+ Възникна грешка
+ Възникна HTTP грешка
+ Възникна входно-изходна грешка
+ Покажи подробности
+
+ Протоколът е закачен към това съобщение (изисква от получаващото приложение поддръжка за прикачени файлове).
+ Адресен указател само за четене
+ DAVx⁵ права
+ Необходими са допълнителни права
+ OpenTasks е прекалено стара
+ Изисква се версия: %1$s, а е налична %2$s.
+ Регистрирането се провали, провери потребителското име и паролата.
+ Грешка с входа/изхода или мрежата – %s
+ Грешка с HTTP сървъра – %s
+ Грешка при съхраняването на място – %s
+ Опитай отново
+ Получих развален контакт от сървъра
+ Получих сбъркан файл със събитие от сървъра
+ Получих сбъркан файл със задача от сървъра
+ Пренебрегване на сбъркани данни
+
+ DAVx⁵: Защита на връзката
+ DAVx⁵ се натъкна на непознат сертификат. Ще му се довериш ли?
+ Авторизиране
+ Използвайте специфичен сървър
+ Необходим е валиден URL адрес
+ URL на сървъра (https://server_url)
+ Вход
+ Вход с /е/ акаунт
+ Нулиране на подсказки
+ Потребителски интерфейс
+ Покажи информация за дебъгване
+ Дебъгване
+ Автоматичната синхронизация е спряна за цялата система
+ Няма интернет връзка. Синхронизацията няма да работи.
+ Политика за поверителност
+ Google Адресна книга
+ /e/ Адресна книга
+ /e/
+ Google
+ WebDAV
+ ВНИМАНИЕ
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index 32453fd23e6f296db2ce67966a1038446699bf25..22549b901ff710a12453513b08bab11286e03d42 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -1,13 +1,14 @@
- DAVx⁵
+ Responsable de comptes
El compte no existeix (eliminat)
- Llibreta d’adreces del DAVx⁵
+ Llibreta d’adreces del AccountManager
Llibreta d’adreces
+ Elimina
+ Cancel·la
Cal aquest camp
Ajuda
- Gestiona comptes
Comparteix
Base de dades malmesa
S\'han eliminat localment tots els comptes.
@@ -235,7 +236,7 @@
Inici de sessió amb un URL i un certificat de client
Selecciona el certificat
Inici de sessió
- Crea un compte
+ Afegir compte
Nom del compte
S\'ha informat que l\'ús d\'apòstrofs (\'), causa problemes en alguns dispositius.
Utilitzeu la vostra adreça de correu electrònic com a nom del compte perquè l\'Android utilitzarà el nom del compte com a camp ORGANITZADOR per als esdeveniments que creeu. No poden haver-hi dos comptes amb el mateix nom.
@@ -394,6 +395,8 @@
Contrasenya
Afegeix un muntatge
No hi ha cap servei WebDAV en aquest URL
+ Elimina el punt de muntatge
+ Es perdran els detalls de la connexió, però no se suprimiran els fitxers.
S\'està accedint al fitxer WebDAV
S\'està baixant el fitxer WebDAV
S\'està pujant el fitxer WebDAV
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 63d4fe5790454528d189b0f9f48276dcf323ab0b..e650ab75c09961db7567d91dc6274c4a18a647f1 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -1,13 +1,14 @@
- DAVx⁵
+ Správce účtu
Účet (už) neexistuje
- DAVx⁵ adresář kontaktů
+ Správce účtu adresář kontaktů
Adresáře kontaktů
+ Odebrat
+ Storno
Tuto kolonku je třeba vyplnit
Pomoc
- Spravovat účty
Sdílet
Databáze rozbitá
Všechny účty byly lokálně odebrány.
@@ -118,11 +119,12 @@
Webová stránka
Příručka
FAQ
+ Komunita
Obdarovat
Ochrana soukromí
Bez připojení k Internetu. Systém Android synchronizaci nespustí.
Zbývá málo místa na úložišti. Systém Android nespustí synchronizaci.
- Vítejte v aplikaci DAVx⁵!\n\nNyní můžete přidat CalDAV/CardDAV účet.
+ Vítejte v aplikaci Správce účtu!\n\nNyní můžete přidat CalDAV/CardDAV účet.
Automatická synchronizace v rámci celého systému je vypnutá
Zapnout
Synchronizovat všechny účty
@@ -234,7 +236,7 @@
Přihlásit pomocí URL a klientského certifikátu
Vybrat certifikát
Přihlášení
- Vytvořit účet
+ Přidat účet
Název účtu
Použití apostrofů (\') bylo u některých zařízení hlášeno jako problematické.
Pro jméno účtu použijte svou e-mailovou adresu, protože Android bude brát jméno účtu jako údaj pro ORGANIZÁTORA vytvořených událostí. Nelze mít dva účty stejného jména.
@@ -308,8 +310,8 @@
Nejsou vytvořené žádné výchozí připomínky
Pokud mají být pro události bez připomínky vytvořeny výchozí připomínky: požadovaný počet minut před událostí. Pokud výchozí připomínky nechcete, nevyplňujte.
Spravovat barvy kalendářů
- Barvy kalendáře jsou při každé synchronizaci resetovány
- Barvy kalendáře je možné nastavovat ostatními aplikacemi
+ Barvy kalendářů spravuje Správce účtu
+ Barvy kalendářů nespravuje Správce účtu
Podpora pro barvy událostí
Barvy událostí jsou synchronizovány
Barvy událostí nejsou synchronizovány
@@ -397,12 +399,14 @@
Heslo
Přidat připojení (mount)
Na této URL se nenachází žádná WebDAV služba
+ Odebrat přípojný bod
+ Podrobnosti o spojení budou ztraceny, ale soubory nebudou smazány.
Přistupuje se k WebDAV souboru
Stahuje se WebDAV soubor
Nahrává se WebDAV soubor
WebDAV připojení
- DAVx⁵ oprávnění
+ Správce účtu oprávnění
Vyžadována dodatečná oprávnění
Příliš stará verze %s
Nejnižší požadovaná verze: %1$s
@@ -417,6 +421,6 @@
Ze serveru obdržen neplatný úkol
Ignoruje se jeden či více neplatný prostředků
- DAVx⁵: Zabezpečení připojení
- DAVx⁵ nalezlo neznámý certifikát. Chcete mu důvěřovat?
+ Správce účtu: Zabezpečení připojení
+ Správce účtu nalezl neznámý certifikát. Chcete mu důvěřovat?
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index 8187429f97bab371ddfa31c9bbd44e3d13b267bc..97ad33cecc7e3a077b452b843e074d766e8ec5f7 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -1,13 +1,14 @@
- DAVx⁵
+ Kundechef
Konto findes ikke (længere)
- DAVx⁵ adressebog
+ Kundechef adressebog
Adressebøger
+ Fjern
+ Annullere
Feltet er påkrævet
Hjælp
- Administrere konti
Del
Database ødelagt
Alle konti er fjernet lokalt.
@@ -123,7 +124,7 @@
Privatlivs politik
Ingen internetforbindelse. Android kører ikke synkronisering.
Lagerplds lav. Android kører ikke synkronisering.
- Velkommen til DAVx⁵!\n\nDu kan nu tilføje en CalDAV/CardDAV konto.
+ Velkommen til Kundechef!\n\nDu kan nu tilføje en CalDAV/CardDAV konto.
Automatisk synkronisering på tværs af systemet er deaktiveret
Aktivere
Synkronisere alle konti
@@ -235,7 +236,7 @@
Log ind med URL og klientcertifikat
Vælge certifikat
Log ind
- Oprette konto
+ Tilføj konto
Kontonavn
Du kan ikke bruge anførelsestegn (\') på alle mobiler.
Brug e-mail adresse som kontonavn da Android bruger kontonavn til ORGANIZER-felt for oprettede aktiviteter. Man kan ikke have to konti med samme navn.
@@ -263,6 +264,7 @@
Synkroniseringsinterval for opgaver
- Kun manuelt
+ - Hvert andet minut
- Hvert 15. minut
- Hver halve time
- Hver time
@@ -305,8 +307,8 @@
Ingen standard påmindelse oprettet
Hvis standard påmindelse skal oprettes for hændelse uden påmindelse: antal minutter før hændelse. Efterlad tom for at deaktivere standard påmindelse.
Administrer farver for kalender
- Kalender farver nulstilles ved hver synkronisering
- Kalender farver kan sættes fra andre programmer
+ Kalenderfarver administreres af Kundechef
+ Kalenderfarver sættes ikke fra Kundechef
Farver for begivenheder
Farver for begivenheder er synkroniseret
Farver for begivenheder er ikke synkroniseret
@@ -394,12 +396,14 @@
Adgangskode
Tilføj monteringspunkt
Ingen WebDAV tjeneste på URL\'en
+ Fjern monteringspunkt
+ Forbindelses informationer vil gå tabt, men ingen filer slettes.
Tilgå WebDAV fil
Hent WebDAV fil
Overfør WebDAV fil
Montere WebDAV
- DAVx⁵-rettigheder
+ Kundechef-rettigheder
Yderligere adgang påkrævet
%s for gammel
Påkrævet version: %1$s
@@ -414,6 +418,6 @@
Modtaget ugyldig opgave fra server
Ignorere en eller flere ugyldige kilder
- DAVx⁵: Forbindelsessikkerhed
- DAVx⁵ er stødt på et ukendt certifikat. Vil du stole på det?
+ Kundechef: Forbindelsessikkerhed
+ Kundechef er stødt på et ukendt certifikat. Vil du stole på det?
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index d13ada330016d330d60a33c9041925ac906f7424..5fefbf5d1e5b9f7ff84e9ef31ce11eea9b8f7a0f 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -1,419 +1,319 @@
-
+
-
- DAVx⁵
- Konto nicht (mehr) vorhanden
- DAVx⁵-Adressbuch
- Adressbücher
- Feld wird benötigt
- Hilfe
- Konten verwalten
- Teilen
- Datenbank beschädigt
- Alle Accounts wurden lokal entfernt.
- Fehlersuche
- Andere wichtige Mitteilungen
- Weniger wichtige Statusmitteilungen
- Synchronisierung
- Synchronisierungsfehler
- Fehler, die zum Abbruch der Synchronisation führen, wie z.B. unerwartete Serverantworten
- Synchronisierungswarnungen
- Nicht fatale Synchronisierungsprobleme wie bestimmte ungültige Dateien
- Netzwerk- und E/A-Fehler
- Zeitüberschreitungen, Verbindungsprobleme, usw. (oft vorübergehend)
-
- Dein Leben. Deine Daten.
- Deine Entscheidung.
- Regelmäßige Sync-Intervalle
- Deaktiviert (nicht empfohlen)
- Aktiviert (empfohlen)
- Zur Synchronisierung in regelmäßigen Intervallen muss %s im Hintergrund laufen dürfen; ansonsten kann Android die Synchronisierung jederzeit aussetzen.
- Ich brauche keine regelmäßigen Sync-Intervalle.*
- %s-Kompatibilität
- Dieses Gerät blockiert die Synchronisierung wahrscheinlich. Dies kann nur manuell behoben werden.
- Ich habe die Einstellungen gemacht, nicht mehr erinnern.*
- * Nicht anwählen, um später erinnert zu werden. Kann unter App-Einstellungen / %s zurückgesetzt werden.
- Mehr Infos
- jtx Board
-
- Unterstützung für Aufgaben
- Falls der Server Aufgaben unterstützt, können sie mit einer unterstützten App synchronisiert werden:
- OpenTasks
- zusätzliche Apps benötigt.]]>
- Tasks
- werden (noch) nicht unterstützt.]]>
- Kein App-Store verfügbar
- Ich brauche keine Unterstützung für Aufgaben.*
- Open-Source-Software
- 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!
- Infos zum Mithelfen/Spenden
- In nächster Zeit nicht anzeigen
-
- Rechteverwaltung
- %s benötigt Berechtigungen, um ordnungsgemäß zu funktionieren.
- Alles darunter
- Hiermit können alle Funktionen aktiviert werden (empfohlen)
- Alle Berechtigungen gewährt
- Kontakte-Berechtigungen
- Keine Kontaktsynchronisierung (nicht empfohlen)
- Kontaktsynchronisierung möglich
- Kalender-Berechtigungen
- Keine Kalendersynchronisierung (nicht empfohlen)
- Kalendersynchronisierung möglich
- jtx Board-Berechtigungen
- Keine Synchronisierung von Aufgaben, Journalen & Notizen (nicht installiert)
- Keine Synchronisierung von Aufgaben, Journalen und Notizen
- Synchronisierung von Aufgaben, Journalen, Notizen möglich
- OpenTasks-Berechtigungen
- Tasks-Berechtigungen
- Keine Aufgabensynchronisierung (nicht installiert)
- Keine Aufgabensynchronisierung
- Aufgabensynchronisierung möglich
- Berechtigungen behalten
- Berechtigungen können automatisch entzogen werden (nicht empfohlen)
- Berechtigungen werden nicht automatisch entzogen
- Berechtigungen > \"Berechtigungen entfernen, wenn die App nicht verwendet wird\" abwählen
- Wenn ein Schalter nicht funktioniert, App-Einstellungen / Berechtigungen verwenden.
- App-Einstellungen
-
- WLAN-SSID-Berechtigungen
- Um auf den aktuellen WLAN-Namen (SSID) zugreifen zu können, müssen folgende Bedingungen erfüllt werden:
- Exakter Standort-Berechtigung
- Standort-Zugriff erlaubt
- Standort-Zugriff verweigert
- Hintergrund-Standort-Berechtigung
- Immer zulassen
- %s gesetzt]]>
- %s gesetzt]]>
- %s verwendet die Standort-Berechtigung ausschließlich zum Bestimmen der aktuellen WLAN-SSID für SSID-beschränkte Accounts. Dies findet auch statt, wenn die App geschlossen ist bzw. im Hintergrund läuft. Standortdaten werden weder gesammelt, gespeichert, verarbeitet noch irgendwohin gesendet.
- Standort-Dienst immer aktiviert
- Standort-Dienst aktiv
- Standort-Dienst inaktiv
-
- Übersetzungen
- Bibliotheken
- Version %1$s (%2$d)
- Erstellt am %s
- © Ricki Hirner, Bernhard Stockmann (bitfire web engineering GmbH) und Mitwirkende
- Diese Version ist nur zur Verteilung über Google Play bestimmt.
- Dieses Programm wird OHNE JEDE GEWÄHRLEISTUNG bereitgestellt. Es ist freie Software – Sie können es also unter bestimmten Bedingungen weiterverbreiten.
- Dank an: %s]]>
-
- Protokolldatei konnte nicht angelegt werden
- Alle %s-Aktivitäten werden protokolliert
- Anzeigen/teilen
- Deaktivieren
-
- Hauptmenü anzeigen
- Hauptmenü schließen
- CalDAV/CardDAV-Sync-Adapter
- Über / Lizenz
- Beta-Rückmeldung
- Bitte installieren Sie eine E-Mail-Anwendung
- Bitte installieren Sie einen Web-Browser
- Einstellungen
- Aktuelles
- Werkzeuge
- Externe Links
- Homepage
- Handbuch
- FAQ
- Community
- Spenden
- Datenschutzerklärung
- Keine Internet-Verbindung. Android wird die Synchronisierung daher nicht starten.
- Speicher knapp. Android wird keine Synchronisierung ausführen.
- Herzlich willkommen!\n\nSie können jetzt ein CalDAV/CardDAV-Konto hinzufügen.
- Systemweite automatische Synchronisierung ist nicht aktiv
- Aktivieren
- Alle Konten synchronisieren
-
- Diensterkennung fehlgeschlagen
- Ordnerliste konnte nicht aktualisiert werden
-
- Darf nicht im Vordergrund ausgeführt werden
- Ausnahme von Akku-Optimierung erforderlich
-
- Läuft im Vordergrund
- Auf manchen Geräten für die automatische Synchronisierung benötigt
-
- Einstellungen
- Fehlersuche
- Informationen zur Fehlersuche
- Software- und Konfigurationsdetails anzeigen und teilen
- Ausführliche Protokollierung
- Protokollierung läuft
- Keine Protokollierung
- Akku-Optimierung
- App ist ausgenommen (empfohlen)
- App ist nicht ausgenommen (nicht empfohlen)
- Im Vordergrund bleiben
- Kann helfen, wenn das Gerät automatische Synchronisierung verhindert
- Verbindung
- Proxy-Typ
-
- - System-Standard
- - Kein Proxy
- - HTTP
- - SOCKS (für Orbot)
-
- Proxy-Rechnername
- Proxy-Port
- Sicherheit
- App-Berechtigungen
- Für die Synchronisierung benötigte Berechtigungen prüfen
- Systemzertifikaten nicht vertrauen
- System- und installierten CAs wird nicht vertraut
- System- und installierten CAs wird vertraut (empfohlen)
- Zertifikat-Vertrauen zurücksetzen
- Setzt angenommene/abgelehnte Zertifikate zurück
- Angenommene/abgelehnte Zertifikate zurückgesetzt
- Oberfläche
- Benachrichtigungseinstellungen
- Benachrichtigungskanäle und -einstellungen verwalten
- Aussehen wählen
-
- - wie System
- - heller Stil
- - dunkler Stil
-
- Hinweise zurücksetzen
- Hinweise, die deaktiviert wurden, wieder anzeigen
- Alle Hinweise werden wieder angezeigt
- Integration
- Aufgaben-App
- Synchronisierung mit %s
- Keine kompatible Aufgaben-App gefunden
-
- CardDAV
- CalDAV
- Webcal
- Keine Kontaktsynchronisierung (fehlende Rechte)
- Keine Kalendersynchronisierung (fehlende Rechte)
- Keine Aufgabensynchronisierung (fehlende Rechte)
- Keine Kalender- und Kontaktsynchronisierung (fehlende Rechte)
- Fehlender Zugang zu Kalendern (fehlende Rechte)
- Berechtigungen
- (Noch) keine Adressbücher vorhanden
- (Noch) keine Kalender vorhanden
- (Noch) keine Kalender-Abos vorhanden
- Nach unten wischen, um neue Einträge am Server zu suchen.
- Jetzt synchronisieren
- Synchronisierung gestartet
- Konto-Einstellungen
- Konto umbenennen
- Ungespeicherte lokale Änderungen können verloren gehen. Nach dem Umbenennen muss neu synchronisiert werden. Neuer Kontoname:
- Umbenennen
- Konto konnte nicht umbenannt werden
- Konto löschen
- Konto wirklich löschen?
- Alle Adressbücher, Kalender und Aufgabenlisten werden vom Gerät (nicht am Server) gelöscht.
- Diesen Ordner synchronisieren
- schreibgeschützt
- Kalender
- Aufgabenliste
- Journal
- Nur eigene anzeigen
- Adressbücher neu erkennen
- Neues Adressbuch erstellen
- Kalender neu erkennen
- Neuen Kalender erstellen
- Keine Webcal-App gefunden
- ICSx⁵ installieren
-
- Konto hinzufügen
- Mit E-Mail-Adresse anmelden
- E-Mail-Adresse
- Gültige E-Mail-Adresse benötigt
- Passwort
- Passwort wird benötigt
- Mit URL und Benutzername anmelden
- URL muss mit http(s):// beginnen
- Benutzername
- Benutzername wird benötigt
- Basis-URL
- Mit URL und Client-Zertifikat anmelden
- Zertifikat auswählen
- Anmelden
- Konto anlegen
- Kontoname
- Auf manchen Geräten führt die Verwendung von einfachen Anführungszeichen (\') zu Problemen.
- 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.
- Kontaktgruppen-Methode:
- Kontoname wird benötigt
- Kontoname bereits verwendet
- Konto konnte nicht angelegt werden
- Erweiterter Login (für spezielle Anwendungsfälle)
- Name/Passwort benutzen
- Client-Zertifikat benutzen
- Kein Zertifikat gefunden
- Zertifikat installieren
- Ressourcen-Erkennung
- Server-Informationen werden abgerufen. Bitte warten …
- Es konnte weder ein CalDAV- noch ein CardDAV-Dienst gefunden werden.
- Benutzername (Email-Adresse) / Passwort falsch?
- Details anzeigen
-
- Einstellungen: %s
- Synchronisierung
- Häufigkeit der Kontakte-Synchronisierung
- Nur manuell
- Alle %d Minuten + sofort bei lokalen Änderungen
- Häufigkeit der Kalender-Synchronisierung
- Häufigkeit der Aufgaben-Synchronisierung
-
- - Nur manuell
- - Alle 15 Minuten
- - Alle 30 Minuten
- - Jede Stunde
- - Alle 2 Stunden
- - Alle 4 Stunden
- - Einmal am Tag
-
- Nur über WLAN synchronisieren
- Synchronisierung nur bei aktiver WLAN-Verbindung
- Verbindungstyp wird nicht beachtet
- WLAN-SSID-Beschränkung
- Synchronisierung nur über %s
- Synchronisierung nur über %s (benötigt aktive Standortdienste)
- Alle WLAN-Verbindungen werden verwendet
- Erlaubte WLAN-Namen (SSIDs, mit Komma getrennt, leer lassen für alle)
- WLAN-SSID-Einschränkung benötigt weitere Einstellungen
- Verwalten
- Mehr Infos (FAQ)
- Anmeldeinformationen
- Benutzername
- Benutzername eingeben:
- Passwort
- Aktualisieren Sie Ihr Passwort gemäß den Server-Einstellungen.
- Passwort eingeben:
- Client-Zertifikat (Alias)
- Kein Zertifikat ausgewählt
- CalDAV
- Abrufbeschränkung vergangener Termine
- Alle Termine werden synchronisiert
-
- - Termine, die mehr als einen Tag in der Vergangenheit liegen, werden ignoriert
- - Termine, die mehr als %d Tage in der Vergangenheit liegen, werden ignoriert
-
- 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.
- Standard-Erinnerung
-
- - Standard-Erinnerung eine Minute vor dem Ereignis
- - Standard-Erinnerung %d Minuten vor dem Ereignis
-
- Keine Standard-Erinnerungen
- 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.
- Kalenderfarben verwalten
- Kalenderfarben werden bei jeder Synchronisierung neu gesetzt
- Kalenderfarben können von anderen Apps festgesetzt werden
- Unterstützung für Terminfarben
- Terminfarben werden synchronisiert
- Terminfarben werden nicht synchronisiert
- CardDAV
- Kontaktgruppen-Methode
-
- - Gruppen sind eigene vCards
- - Gruppen sind Kategorien der Kontakte
-
- Gruppen-Methode ändern
-
- Adressbuch erstellen
- Meine Adressen
- Kalender anlegen
- Zeitzone
- Mögliche Kalendereinträge
- Termine
- Aufgaben
- Notizen / Journal
- Kombiniert (Termine und Aufgaben)
- Farbe
- Ordner wird angelegt
- Titel
- Ein Titel wird benötigt
- Beschreibung
- optional
- Speicherort
- Speicherort wird benötigt
- Erstellen
- Ordner löschen
- Sind Sie sicher?
- Dieser Ordner (%s) und alle enthaltenen Daten werden dauerhaft gelöscht.
- Diese Daten sollen vom Server gelöscht werden.
- Ordner wird gelöscht
- Schreibschutz erzwingen
- Eigenschaften
- Adresse (URL):
- URL kopieren
- Besitzer:
-
- Informationen zur Fehlersuche
- ZIP-Archiv
- Beinhaltet Debug-Info und Logs
- Das Archiv teilen, um es zu einem Rechner zu übertragen, per Email zu verschicken oder an ein Support-Ticket anzuhängen.
- Archiv teilen
- Debug-Informationen sind dieser Nachricht beigelegt (benötigt Unterstützung für Anhänge in der empfangenden App).
- HTTP-Fehler
- Serverfehler
- WebDAV-Fehler
- E/A-Fehler
- Die Anfrage wurde abgelehnt. Details unter Beteiligte Ressourcen und in den Debug-Informationen.
- Die Ressource existiert nicht (mehr). Details unter Beteiligte Ressourcen und in den Debug-Informationen.
- Ein serverseitiges Problem ist aufgetreten. Bitte kontaktieren Sie den Server-Support.
- Ein unerwarteter Fehler ist aufgetreten. Details in den Debug-Informationen.
- Details anzeigen
- Debug-Informationen wurden gesammelt
- Beteiligte Ressourcen
- haben mit dem Problem zu tun
- Entfernte Ressource:
- Lokale Ressource:
- In App öffnen
- Protokoll
- Ausführliches Protokoll verfügbar
- Logs anzeigen
-
- Ein Fehler ist aufgetreten.
- Ein HTTP-Fehler ist aufgetreten.
- Ein E/A-Fehler ist aufgetreten.
- Details anzeigen
-
- Synchronisation pausiert
- Kaum noch Speicherplatz vorhanden
-
- WebDAV-Zugänge
- Speicher belegt: %1$s / verfügbar: %2$s
- Inhalt teilen
- Aushängen
- WebDAV-Zugang hinzufügen
- Greifen Sie mit einem WebDAV-Zugang direkt auf Ihre Cloud-Dateien zu!
- wie WebDAV-Zugänge funktionieren.]]>
- Anzeigename
- WebDAV-Adresse
- Ungültige Adresse
- Anmeldename
- Passwort
- Einhängen
- Kein WebDAV-Dienst unter dieser Adresse
- WebDAV-Dateizugriff
- WebDAV-Download
- WebDAV-Upload
- WebDAV-Zugang
-
- DAVx⁵-Berechtigungen
- Zusätzliche Berechtigungen benötigt
- %s zu alt
- Benötigte Mindestversion: %1$s
- Anmeldungsfehler (Login-Daten überprüfen)
- Netzwerk- oder E/A-Fehler – %s
- HTTP-Serverfehler – %s
- Lokaler Speicherfehler – %s
- Wiederholen
- Untersuchen
- Ungültigen Kontakt vom Server erhalten
- Ungültigen Termin vom Server erhalten
- Ungültige Aufgabe vom Server erhalten
- Eine/mehrere ungültige Ressourcen ignoriert
-
- DAVx⁵: Verbindungssicherheit
- DAVx⁵ ist auf ein unbekanntes Zertifikat gestoßen. Ist dieses vertrauenswürdig?
+
+ Kontenverwalter
+ WebDAV-Adressbuch
+ Adressbücher
+ Hilfe
+ Senden
+ Fehlersuche
+ Andere wichtige Mitteilungen
+ Synchronisierung
+ Synchronisierungsfehler
+ Fehler, die zum Abbruch der Synchronisation führen, wie beispielsweise unerwartete Serverantworten
+ Synchronisierungswarnungen
+ Nicht fatale Synchronisierungsprobleme wie bestimmte ungültige Dateien
+ Netzwerk- und E/A-Fehler
+ Zeitüberschreitungen, Verbindungsprobleme, usw. (oft vorübergehend)
+
+ Automatische Synchronisierung
+ %s-Firmware verhindert oftmals das automatische Synchronisieren. In diesem Fall müssen Sie das automatische Synchronisieren in den Android-Einstellung erlauben.
+ Geplante Synchronisierung
+ Ihr Gerät wird die Konten Manager-Synchronisierung einschränken. Damit regelmäßig synchronisiert werden kann, muss die »Akku-Leistungsoptimierung« deaktiviert werden.
+ Für Konten Manager deaktivieren
+ Nicht mehr anzeigen
+ Später
+ Open-Source-Information
+ Es freut uns, dass Sie den Konten Manager und damit Open-Source-Software (GPLv3) verwenden. Da in dem Konten Manager tausende Stunden harter Arbeit stecken und er immer noch weiter entwickelt wird, gibt es die Möglichkeit, an uns zu spenden.
+ Spendenseite anzeigen
+ Vielleicht später
+ Mehr Information
+ OpenTasks nicht installiert
+ Für die Synchronisierung von Aufgaben wird die freie App OpenTasks benötigt. (Nicht benötigt für Kontakte/Termine.)
+ Nach der Installation von OpenTasks muss der Kontenverwalter NEU INSTALLIERT und die Konten neu hinzugefügt werden (Android-Bug).
+ OpenTasks installieren
+
+ Bibliotheken
+ Version %1$s (%2$d)
+ Erstellt am %s
+ Diese Version ist nur zur Verteilung über Google Play bestimmt.
+ Dieses Programm wird OHNE JEDE GEWÄHRLEISTUNG bereitgestellt. Es ist freie Software – Sie können es also unter bestimmten Bedingungen weiterverbreiten.
+
+ Protokolldatei konnte nicht angelegt werden
+ Konten Manager-Protokollierung
+ Alle %s-Aktivitäten werden nun protokolliert
+ Protokoll senden
+
+ Menüleiste öffnen
+ Menüleiste schließen
+ Sync-Adapter für Kontakte/Kalender
+ Über / Lizenz
+ Beta-Rückmeldung
+ Bitte installieren Sie eine Email-Anwendung
+ Bitte installieren Sie einen Web-Browser
+ Einstellungen
+ Neuigkeiten & Aktualisierungen
+ Externe Links
+ Homepage
+ Handbuch
+ FAQ
+ Hilfe / Foren
+ Spenden
+ Datenschutzerklärung
+ Keine Internet-Verbindung. Android wird die Synchronisierung daher nicht starten.
+ Willkommen beim Kontenverwalter!
+\n
+\nSie können jetzt ein Kontakte-/Kalender-Konto hinzufügen.
+ Systemweite automatische Synchronisierung ist deaktiviert
+ Aktivieren
+
+ Diensterkennung fehlgeschlagen
+ Ordnerliste konnte nicht aktualisiert werden
+
+ Einstellungen
+ Fehlersuche
+ Informationen zur Fehlersuche
+ Software- und Konfigurationsdetails anzeigen und teilen
+ Ausführliche Protokollierung
+ Protokollierung läuft
+ Keine Protokollierung
+ Verbindung
+ Proxy-Einstellungen überschreiben
+ Eigene Proxy-Einstellungen werden verwendet
+ System-Proxy-Einstellungen werden verwendet
+ HTTP-Proxy-Rechnername
+ HTTP-Proxy-Port
+ Sicherheit
+ Systemzertifikaten nicht vertrauen
+ System- und Benutzer-installierten Sicherheitszertifikaten wird nicht vertraut
+ System- und Benutzer-installierten Sicherheitszertifikaten wird vertraut (empfohlen)
+ Zertifikat-Vertrauen zurücksetzen
+ Setzt angenommene/abgelehnte Zertifikate zurück
+ Alle Informationen über angenommene/abgelehnte Zertifikate wurden zurückgesetzt
+ Benutzeroberfläche
+ Benachrichtigungseinstellungen
+ Benachrichtigungskanäle und -einstellungen verwalten
+ Hinweise zurücksetzen
+ Hinweise, die deaktiviert wurden, wieder anzeigen
+ Alle Hinweise werden wieder angezeigt
+
+ CardDAV
+ CalDAV
+ Webcal
+ (Noch) keine Adressbücher vorhanden.
+ (Noch) keine Kalender vorhanden.
+ (Noch) keine Kalender-Abos vorhanden.
+ Nach unten wischen, um neue Einträge am Server zu suchen.
+ Jetzt synchronisieren
+ Synchronisation gestartet
+ Konto-Einstellungen
+ Konto umbenennen
+ Ungespeicherte lokale Änderungen können verloren gehen. Nach dem Umbenennen muss neu synchronisiert werden. Neuer Kontoname:
+ Umbenennen
+ Konto löschen
+ Konto wirklich löschen?
+ Alle Adressbücher, Kalender und Aufgabenlisten werden vom Gerät (nicht am Server) gelöscht.
+ diesen Ordner synchronisieren
+ schreibgeschützt
+ Kalender
+ Aufgabenliste
+ Adressbücher neu erkennen
+ Neues Adressbuch erstellen
+ Kalender neu erkennen
+ Neuen Kalender erstellen
+ Keine Webcal-App gefunden
+ ICSx⁵ installieren
+
+ Konto hinzufügen
+ Mit E-Mail-Adresse anmelden
+ E-Mail-Adresse
+ Gültige E-Mail-Adresse benötigt
+ Passwort
+ Passwort wird benötigt
+ Mit URL und Benutzername anmelden
+ URL muss mit http(s):// beginnen
+ URL muss mit https:// beginnen
+ Hostname wird benötigt
+ Benutzername
+ Benutzername wird benötigt
+ Basis-URL
+ Mit URL und Client-Zertifikat anmelden
+ Zertifikat auswählen
+ Anmelden
+ Zurück
+ hinzufügen anlegen
+ Kontoname
+ 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.
+ Kontaktgruppen-Methode:
+ Kontoname wird benötigt
+ Kontoname bereits verwendet
+ Konto konnte nicht angelegt werden
+ Ressourcen-Erkennung
+ Server-Informationen werden abgerufen. Bitte warten …
+ Es konnte weder ein CalDAV- noch ein CardDAV-Dienst gefunden werden.
+ Details anzeigen
+
+ Einstellungen: %s
+ Synchronisierung
+ Häufigkeit der Kontakte-Synchronisierung
+ Nur manuell
+ Alle %d Minuten + sofort bei lokalen Änderungen
+ Häufigkeit der Kalender-Synchronisierung
+ Häufigkeit der Aufgaben-Synchronisierung
+
+ - Nur manuell
+ - alle 2 Minuten
+ - Alle 15 Minuten
+ - Alle 30 Minuten
+ - Jede Stunde
+ - Alle 2 Stunden
+ - Alle 4 Stunden
+ - Einmal am Tag
+
+ Nur über WLAN synchronisieren
+ Synchronisierung nur bei aktiver WLAN-Verbindung
+ Verbindungstyp wird nicht beachtet
+ WLAN-SSID-Beschränkung
+ Synchronisierung nur über %s
+ Synchronisierung nur über %s (benötigt aktive Standortdienste)
+ Alle WLAN-Verbindungen werden verwendet
+ Erlaubte WLAN-Namen (SSIDs, mit Beistrich getrennt, leer lassen für alle)
+ Zum Auslesen von WLAN-Namen sind die Standort-Berechtigung und die ständige Aktivierung der Standortdienste notwendig.
+ Mehr Info (FAQ)
+ Anmeldeinformationen
+ Benutzername
+ Benutzername eingeben:
+ Passwort
+ Aktualisieren Sie Ihr Passwort gemäß den Server-Einstellungen.
+ Passwort eingeben:
+ Client-Zertifikat (Alias)
+ CalDAV
+ Abrufbeschränkung vergangener Termine
+ Alle Termine werden synchronisiert
+
+ - Termine, die mehr als einen Tag in der Vergangenheit liegen, werden ignoriert
+ - Termine, die mehr als %d Tage in der Vergangenheit liegen, werden ignoriert
+
+ 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.
+ Standard-Erinnerung
+
+ - Standard-Erinnerung eine Minute vor dem Ereignis
+ - Standard-Erinnerung %d Minuten vor dem Ereignis
+
+ Keine Standard-Erinnerungen
+ 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.
+ Kalenderfarben verwalten
+ Kalenderfarben werden von Konten Manager verwaltet
+ Konten Manager setzt keine Kalenderfarben
+ Unterstützung für Terminfarben
+ Terminfarben werden synchronisiert
+ Terminfarben werden nicht synchronisiert
+ CardDAV
+ Kontaktgruppen-Methode
+
+ - Gruppen sind eigene vCards
+ - Gruppen sind Kategorien der Kontakte
+
+ Gruppen-Methode ändern
+
+ Adressbuch erstellen
+ Meine Adressen
+ Kalender anlegen
+ Zeitzone
+ Zeitzone benötigt
+ Mögliche Kalendereinträge
+ Termine
+ Aufgaben
+ Notizen / Journal
+ Kombiniert (Termine und Aufgaben)
+ Farbe
+ Ordner wird angelegt
+ Titel
+ Ein Titel wird benötigt
+ Beschreibung
+ fakultativ
+ Speicherort
+ Erstellen
+ Ordner löschen
+ Sind Sie sicher?
+ Dieser Ordner (%s) und alle enthaltenen Daten werden dauerhaft gelöscht.
+ Diese Daten sollen vom Server gelöscht werden.
+ Ordner wird gelöscht
+ Schreibschutz erzwingen
+ Eigenschaften
+ Adresse (URL):
+ URL kopieren
+
+ Ein Fehler ist aufgetreten.
+ Ein HTTP-Fehler ist aufgetreten.
+ Ein E/A-Fehler ist aufgetreten.
+ Details anzeigen
+
+ Informationen zur Fehlersuche
+ Das Protokoll liegt als Anhang bei (benötigt Unterstützung für Anhänge in der empfangenden App).
+ Schreibgeschütztes Adressbuch
+ Konten Manager-Berechtigungen
+ Zusätzliche Berechtigungen benötigt
+ OpenTasks zu alt
+ Version %1$s benötigt (derzeit %2$s)
+ Anmeldungsfehler (Login-Daten überprüfen)
+ Netzwerk- oder E/A-Fehler – %s
+ HTTP-Serverfehler – %s
+ Lokaler Speicherfehler – %s
+ Wiederholen
+ Untersuchen
+ Ungültigen Kontakt vom Server erhalten
+ Ungültigen Termin vom Server erhalten
+ Ungültige Aufgabe vom Server erhalten
+ Eine/mehrere ungültige Ressourcen ignoriert
+
+ Kontenverwalter: Verbindungssicherheit
+ Der Kontenverwalter ist auf ein unbekanntes Zertifikat gestoßen. Soll diesem vertraut werden\?
+ Google
+ /e/ wird Google ein falsches Gerätemodell angeben, um Ihre Privatsphäre zu schützen.
+\nSie können es unter \"Meine Geräte\" auf Google überprüfen, nachdem Sie sich angemeldet haben.
+ WARNUNG
+ Benutzernamen und Passwort aktualisieren
+ Zugangsdaten
+ Einen bestimmten Server benutzen
+ Gültige Server-URL-Adresse benötigt
+ Server URL (https://server_url)
+ Eigenen Server verwenden
+ Benutze deine e.email oder murena.io-ID, um dich anzumelden:
+ Zugangsdaten, Synchronisationsintervall, usw.
+ Google-Adressbuch
+ /e/ Adressbuch
+ /e/
+ WebDAV
+ Mein Konto
+ /e/-Konto Übersicht
+ Du kannst nur ein ecloud-Konto auf deinem Gerät einrichten
+ Anleitungen
+ Auf diesem Gerät anmelden
+ Später einrichten
+ Konto erstellen
+ Die Einladung wurde per E-Mail verschickt. Wenn du es nicht empfangen hast, überprüfe bitte deinen Spam-Ordner.
+ 1 - Öffne nun von einem anderen Gerät oder Computer das Einladungs-E-Mail und schließe die Kontoeinrichtung ab.
+\n
+\n2 - Komme dann zu diesem Bildschirm hier zurück und melde dich mit deinem neuen murena.io-Konto an.
+\n
+\nNote: Du kannst diesen Schritt auch überspringen und dein Konto später in den Einstellungen hinzufügen.
+ Bitte gebe deine E-Mail-Adresse an, um eine Einladung für eine gratis murena.io-ID zu erhalten, mit einem persönlichen E-Mail-Konto und Cloud-Speicher.
+ Senden
+ Dieser Benutzername existiert schon
+ Das Cloud-Konto wurde bereits mit dieser E-Mail-Adresse erstellt. Du kannst dich nun anmelden.
+ Überspringen
+ Anmelden
+ Nochmals versuchen
+ Bitte gib eine gültige E-Mail-Adresse an
+ Fehler
+ Gib bitte deine E-Mail-Adresse an, um die Einladung zu empfangen
+ Bitte überprüfe deine Internetverbindung
+ Die Einladung konnte nicht an deine E-Mail-Adresse geschickt werden, wegen eines Internet-Fehlers.
+\n
+\nBitte versuche es später noch einmal.
+\n
+\nBemerkung: Du kannst diesen Schritt auch überspringen, und ein Konto später unter den Einstellungen hinzufügen. Falls du auf Schwierigkeiten triffst, kontaktiere bitte den Kundendienst.
+ Anmelden
+ Server-URL (%s)
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 050a4d2c2e44cf546b2c0d83a5561b91bc1a3811..52870b2ade5db238f8f005a2bb37d6deb1468626 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -7,7 +7,6 @@
Βιβλία διευθύνσεων
Αυτό το πεδίο είναι απαραίτητο
Βοήθεια
- Διαχείριση λογαριασμών
Διαμοιρασμός
Υπάρχει σφάλμα στην βάση δεδομένων
Όλοι οι λογαριασμοί έχουν διαγραφεί τοπικά
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 3dc8a1c11b40e39e05ec89c10ab57a2fd8ea16df..188070bf4c38e3123705317359ea3001679b300d 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -1,421 +1,284 @@
-
+
-
- DAVx⁵
- La cuenta (ya) no existe
- Agenda DAVx⁵
- Agendas
- Este campo es requerido
- Ayuda
- Administrar cuentas
- Compartir
- Base de datos corrompida
- Toda las cuentas han sido eliminadas localmente.
- Depuración
- Otros mensajes importantes
- Mensajes de baja prioridad
- Sincronización
- Errores de sincronización
- Errores importantes que detienen la sincronización como respuestas inesperadas del servidor
- Advertencias de sincronización
- Problemas de sincronización no-fatales como ciertos archivos inválidos
- Errores de Red y E/S
- Timeouts, problemas de conección, etc. (muchas veces temporal)
-
- Sus datos. Su elección.
- Tome el control.
- Sincronización a intervalos regulares
- Deshabilitado (no se recomienda)
- Habilitado (se recomienda)
- Para sincronizar a intervalos regulares, se tiene que permitir a %sejecutarse como tarea de fondo. En caso contrario, Android podría pausar la sincronización en cualquier instante.
- No necesito la sincronización a intervalos regulares.*
- Compatibilidad %s
- Este dispositivo bloquea la sincronización. Si está afectado, sólo lo puede resolver manualmente.
- No tengo los ajustes requeridos. No volver a recordar.*
- * Déjelo desmarcado para que se le recuerde más tarde. Se puede reconfigurar en los ajustes de la aplicación / %s
- Información adicional
- Tablero jtx
-
- Soporte de tareas
- Si las tareas son compatibles con tu servidor, pueden sincronizarse con una aplicación de tareas compatible:
- OpenTasks
- aplicaciones adicionales.]]>
- Tareas
- no son compatibles (todavía).]]>
- Ninguna tienda de aplicaciones disponible
- No necesito soporte para tareas.*
- Software open-source
- Nos complace que use%s, que es software open-source. Desarrollar, mantener y asistir a usuarios es un trabajo duro. Por favor, considere contribuir (hay muchas maneras) o hacer una donación. ¡Se agradecería mucho!
- Cómo contribuir o donar
- No mostrar en un futuro próximo
-
- Permisos
- %s necesita permisos para funcionar correctamente.
- Todos los siguientes
- Usa esto para activar todas las características (recomendado)
- Todos los permisos concedidos
- Permisos de contactos
- No sincronizar contactos (no recomendado)
- Sincronización de contactos permitida
- Permisos de calendario
- Sin sincronización de calendario (no recomendado)
- Sincronización de calendario permitida
- Permisos de tablero jtx
- Tareas, diarios y notas sin sincronizar (no instalado)
- Tareas, diarios, notas sin sincronizar
- Sincronización posible de tareas, diarios y notas
- Permisos de OpenTasks
- Permisos de las tareas
- Sin sincronización de tareas (no instalado)
- Sin sincronización de tareas
- Sincronización de tareas permitidas
- Mantener permisos
- Los permisos pueden restablecerse automáticamente (no recomendado)
- Los permisos no se restablecerán automáticamente
- Haga clic en Permisos > desmaque \"Quitar permisos si la aplicación no se utiliza\"
- Si un interruptor no funciona usa Configuraciones de la app / Permisos.
- Configuraciones de la app
-
- Permisos del SSID WiFi
- Para poder acceder al nombre del WiFi actual (SSID), deben cumplirse estas condiciones:
- Permiso de ubicación precisa
- Permiso de ubicación concedido
- Permiso de ubicación denegado
- Permiso de ubicación en segundo plano
- Permitir todo el tiemp
- %s]]>
- %s]]>
- %s usa el permiso de ubicación solo para determinar el SSID del WiFi actual para las cuentas con restricción de SSID. Esto ocurrirá incluso cuando la aplicación esté en segundo plano. No se recogen, almacenan, procesan o envían datos de ubicación a ninguna parte.
- Ubicación siempre activada
- El servicio de ubicación está activado
- El servicio de ubicación está desactivado
-
- Traducciones
- Bibliotecas
- Versión %1$s (%2$d)
- Compilada en %s
- © Ricki Hirner, Bernhard Stockmann (bitfire web engineering GmbH) y colaboradores
- Esta versión sólo está disponible para distribución en Google Play.
- Este programa viene sin NINGÚN TIPO DE GARANTÍA. Es software libre, y cualquier contribución es bienvenida y redistribuida bajo ciertas condiciones.
- Agradecimientos para: %s]]>
-
- No se puede crear el fichero del registro.
- Ahora se registran todas las activdades %s
- Ver/compartir
- Desactivar
-
- Abrir panel de navegación
- Cerrar panel de navegación
- Adaptador de sincronización CalDAV/CardDAV
- Acerca de / Licencia
- Retroalimentación Beta
- Por favor, instale un cliente de email
- Por favor, instale un navegador web
- Ajustes
- Noticias y actualizaciones
- Herramientas
- Enlaces externos
- Sitio web
- Manual
- Preguntas frequentes
- Comunidad
- Donar
- Reglamento de privacidad
- No hay conexión a Internet. Android no se sincronizará.
- Espacio de almacenamiento bajo. Android no ejecutará la sincronización.
- Bienvenido a DAVx⁵!\n\nAhora puedes añadir una cuenta CalDAV/CardDAV.
- Sincronización automática del sistema completo está deshabilitada
- Activar
- Sincronizar todas las cuentas
-
- Falló la detección del servicio
- No se pudo refrescar lista de colección
-
- No puede ejecutarse en primer plano
- Se requiere agregar a la lista blanca de optimización de batería
-
- Funcionando en primer plano.
- En algunos dispositivos, esto es necesario para la sincronización automática.
-
- Ajustes
- Depuración
- Mostrar la información de depuración
- Ver/compartir detalles de software y configuración
- Registro extendido
- El registro está activo
- El registro está deshabilitado
- Optimización de batería
- La app está la lista blanca (recomendado)
- La app no está en la lista blanca (no recomendado)
- Mantener en primer plano.
- Puede ayudar si tu dispositivo impide la sincronización automática.
- Conexión
- Tipo de proxy
-
- - Por defecto del sistema
- - Sin proxy
- - HTTP
- - SOCKS (para Orbot)
-
- Nombre de proxy anfitrión
- Puerto proxy
- Seguridad
- Permisos de la aplicación
- Revisar los permisos necesarios para la sincronización
- Invalidar los certificados del sistema
- Los CA del sistema y los añadidos por el usuario no serán válidos
- Los CA del sistema y los añadidos por el usuario serán usados y de confianza (recomendado)
- Reiniciar certificados (in)validados
- Reinicia la validez de todos los certificados particulares
- Todos los certificados particulares han sido limpiados
- Interfaz de usuario
- Ajustes de notificación
- Administrar notificación de canales y sus ajustes
- Seleccionar tema
-
- - Por defecto del sistema
- - Claro
- - Oscuro
-
- Restablecer advertencias
- Habilita las advertencias que han sido rechazadas con anterioridad
- Todas las advertencias se mostrarán nuevamente
- Integración
- Aplicación de tareas
- Sincronizando con %s
- No se han encontrado aplicaciones de tareas compatibles
-
- CardDAV
- CalDAV
- Webcal
- Sin sincronización de contactos (faltan permisos)
- Sin sincronización de calendario (faltan permisos)
- Sin sincronización de tareas (faltan permisos)
- Sin sincronización de calendario y tareas (faltan permisos)
- No se puede acceder a los calendarios (faltan permisos)
- Permisos
- No hay libretas de direciones (todavía).
- No hay calendarios (todavía).
- No hay suscripciones a calendarios (todavía).
- Desliza hacia abajo para actualizar la lista desde el servidor.
- Sincronizar ahora
- Sincronizando…
- Ajustes de cuenta
- Renombrar cuenta
- Información local no guardada puede ser desechada. Se requiere resincronizar después de renombrar. Nuevo nombre de cuenta:
- Renombrar
- No se puede renombrar la cuenta
- Eliminar cuenta
- ¿Seguro que deseas eliminar la cuenta?
- Todas las copias locales de tus contactos, calendarios y tareas serán eliminadas.
- sincronizar ésta colección
- solo lectura
- calendario
- lista de tareas
- diario
- Mostrar solo personal
- Refrescar contactos
- Crear nueva agenda
- Refrescar calendario
- Crear nuevo calendario
- No se encontró aplicación para administrar Webcal
- Instalar ICSx⁵
-
- Añadir cuenta
- Acceder con cuenta de correo
- Dirección de correo
- Se requiere una dirección de correo válida
- Contraseña
- Contraseña requerida
- Acceder con URL y nombre de usuario
- La URL debe comenzar con http(s)://
- Nombre de usuario
- Nombre de usuario requerido
- URL base
- Iniciar sesión con URL y certificado del cliente
- Seleccionar un certificado
- Registrar
- Crear cuenta
- Nombre de cuenta
- Se han reportado problemas con el uso de apóstrofes(\') en algunos dispositivos.
- Usa tu dirección de correo como nombre de cuenta puesto que Android usará el nombre de la cuenta como campo de \"organizador\" en los eventos que cree. No puedes tener dos cuentas con el mismo nombre.
- Método de contacto de grupo:
- Nombre de cuenta requerido
- El nombre de la cuenta ya está siendo utilizado
- La cuenta no pudo ser creada
- Inicio de sesión avanzado (casos de uso especiales)
- Usar nombre de usuario/contraseña
- Usar certificado de cliente
- No se ha encontrado ningún certificado
- Instalar certificado
- Detectar configuración
- Por favor espera, consultando al servidor…
- No se pudo encontrar el servicio CalDAV o CardDAV.
- ¿Nombre de usuario (dirección de correo electrónico) / contraseña incorrecta?
- Mostrar detalles
-
- Ajustes: %s
- Sincronización
- Intervalo de sincronización de contactos
- Solo manualmente
- Cada %d minutos + inmediatamente con cambios locales
- Intervalo de sincronización de calendarios
- Intervalo de sincronizacion de Tasks
-
- - Solo manualmente
- - Cada 15 minutos
- - Cada 30 minutos
- - Cada hora
- - Cada 2 horas
- - Cada 4 horas
- - Una vez al dia
-
- Sincronizar sólo sobre WiFi
- La sincronización está restringida a conexiones WiFi
- Tipo de conexión no tenido en cuenta
- Restricción WiFi SSID
- Solo se sincronizará a través de %s
- Solo sincronizará sobre %s (requiere servicios de ubicación activos)
- Todas las conexiones WiFi serán usadas
- Nombres separados por comas (SSIDs) de redes WiFi permitidas (deje vacío para todas)
- La restricción del SSID WiFi requiere más ajustes
- Administrar
- Más información (preguntas frecuentes)
- Autenticación
- Nombre de usuario
- Introduce tu nombre de usuario:
- Contraseña
- Actualiza la contraseña de acuerdo a tu servidor.
- Introduce tu contraseña:
- Alias del certificado cliente
- No se ha seleccionado ningún certificado
- CalDAV
- Límite de tiempo de eventos pasados
- Todos los eventos serán sincronizados
-
- - Los eventos anteriores a un día serán ignorados
- - Los eventos anteriores a %d días serán ignorados
- - Los eventos anteriores a %d días serán ignorados
-
- Los eventos anteriores a este número de días serán ignorados (puede ser 0). Deja en blanco el campo para sincronizar todos los eventos.
- Recordatorio por defecto
-
- - Recordatorio por defecto un minuto antes del evento
- - Recordatorio por defecto %dminutos antes del evento
- - Recordatorio por defecto %dminutos antes del evento
-
- No se han creado recordatorios por defecto
- Si se crearán recordatorios por defecto para los eventos que no los tengan: el número de minutos antes del evento. Déjelo en blanco para deshabilitar los recordatorios por defecto.
- Colores de calendario
- Los colores del calendario se restablecen en cada sincronización
- Los colores del calendario pueden ser establecidos por otras aplicaciones
- Soporte de colores en eventos
- Los colores de los eventos están sincronizados
- Los colores de los eventos no están sincronizados
- CardDAV
- Método de contacto de grupo
-
- - Los grupos son vCards separadas
- - Los grupos son categorías de cada contacto
-
- Cambie método de grupo
-
- Crear nueva agenda
- Agendas
- Crear calendario
- Huso horario
- Posibles entradas de calendario
- Eventos
- Tareas
- Notas / jornal
- Combinado (eventos y tareas)
- Color
- Crear colección
- Título
- Título requerido
- Descripción
- opcional
- Ubicación del almacenamiento
- Se requiere ubicación de almacenamiento
- Crear
- Eliminar colección
- ¿Estás seguro/a?
- Esta colección (%s) y todos sus datos serán eliminados permanentemente.
- Estos datos se eliminarán del servidor.
- Eliminando colección
- Forzar solo-lectura
- Propiedades
- Dirección (URL):
- Copiar URL
- Propietario:
-
- Información de depuración
- Archivo ZIP
- Contiene información de depuración y registro
- Comparte el archivo para transferirlo al ordenador, para enviarlo por email o para adjuntarlo a un ticket de soporte.
- Compartir archivo
- Información de depuración adjunta a este mensaje (requiere soporte de adjuntos de la aplicación receptora).
- Error HTTP
- Error del servidor
- Error de WebDAV
- Error de E/S
- La solicitud ha sido denegada. Comprueba los recursos implicados y la información de depuración para obtener más detalles.
- El recurso solicitado (ya) no existe. Comprueba los recursos implicados y la información de depuración para obtener más detalles.
- Se ha producido un problema en el servidor. Por favor, ponte en contacto con el soporte de su servidor.
- Se ha producido un error inesperado. Ve la información de depuración para más detalles.
- Ver detalles
- Se ha recogido la información de depuración
- Recursos implicados
- Relacionado con el problema
- Recurso remoto:
- Recurso local:
- Ver con la aplicación
- Registros
- Los registros verbosos están disponibles
- Ver registros
-
- Ocurrió un error.
- Ha ocurrido un error HTTP.
- Ha ocurrido un error I/O.
- Mostrar detalles
-
- Sincronización pausada
- Casi no hay espacio disponible
-
- Montajes WebDAV
- Cuota usada: %1$s/ disponible: %2$s
- Compartir contenido
- Desmontar
- Agregar montaje WebDAV
- Accede directamente a tus archivos en la nube agregando un punto de montaje WebDAV
- cómo funcionan los puntos de montaje WebDAV.]]>
- Mostrar nombre
- URL WebDAV
- URL inválida
- Nombre de usuario
- Contraseña
- Agregar montaje
- No hay un servicio WebDAV en esta URL
- Accediendo al fichero WebDAV
- Descargando el fichero WebDAV
- Subiendo fichero WebDAV
- Montaje WebDAV
-
- Permisos de DAVx⁵
- Permisos adicionales requeridos
- %s muy antiguo
- Mínima versión requerida: %1$s
- Falló la autenticación (revise credenciales de inicio de sesión)
- Error de red o E/S – %s
- Error de servidor – %s
- Error de almacenamiento local – %s
- Reintentar
- Ver item
- Contacto inválido recibido del servidor
- Evento inválido recibido del servidor
- Tarea inválida recibidas del servidor
- Ignorando uno o más recursos inválidos
-
- DAVx⁵: Seguridad de conexión
- DAVx⁵ ha encontrado un certificado desconocido. ¿Quieres que sea válido?
+
+ Administrador de Cuentas
+ Contactos WebDav
+ Agendas
+ Ayuda
+ Enviar
+ Depuración
+ Otros mensajes importantes
+ Sincronización
+ Errores de sincronización
+ Errores importantes que detienen la sincronización como respuestas inesperadas del servidor
+ Advertencias de sincronización
+ Problemas de sincronización no-fatales como ciertos archivos inválidos
+ Errores de Red y E/S
+ Timeouts, problemas de conección, etc. (muchas veces temporal)
+
+ Sincronización automática
+ El firmware de %s muchas veces bloquea la sincronización automática. En este caso, permita la sincronización automática en sus ajustes de Android.
+ Sincronización programada
+ Su dispositivo restringirá la sincronización de Gerente de cuentas. Para hacer cumplir los intervalos de sincronización regulares de Gerente de cuentas, apague la \"optimización de batería\".
+ Apagar para Gerente de cuentas
+ No mostrar de nuevo
+ Ahora no
+ Información de código abierto
+ Nos alegra que uses Gerente de cuentas, que es software de código abierto (GPLv3). Debido al duro trabajo que supone el desarrollo de Gerente de cuentas y los cientos de horas de trabajo, por favor, considera hacer una donación.
+ Mostrar página de donación
+ Quizás luego
+ Más información
+ OpenTasks no está instalado
+ Para sincronizar tareas, la aplicación libre OpenTasks es requerida. (No necesaria para contactos/eventos.)
+ Tras instalar OpenTasks, tendrás que re-instalar Gerente de cuentas y añadir tus cuentas de nuevo (por un error de Android).
+ Instalar OpenTasks
+
+ Librerías
+ Versión %1$s (%2$d)
+ Compilada en %s
+ Esta versión sólo está disponible para distribución en Google Play.
+ Este programa viene sin NINGÚN TIPO DE GARANTÍA. Es software libre, y cualquier contribución es bienvenida y redistribuida bajo ciertas condiciones.
+
+ No se pudo crear el archivo de registro
+ Registro Gerente de cuentas
+ Ahora registrando todas las actividades de %s
+ Enviar registro
+
+ Abrir panel de navegación
+ Cerrar panel de navegación
+ Adaptador de sincronización de Calendarios/Contactos
+ Acerca de / Licencia
+ Retroalimentación Beta
+ Ajustes
+ Noticias y actualizaciones
+ Enlaces externos
+ Sitio web
+ Manual
+ Preguntas frequentes
+ Ayuda / Foros
+ Donar
+ Bienvenido al manager de cuentas!
+\n
+\nYa puedes añadir una cuenta de Calendario/Contactos.
+ Sincronización automática del sistema completo está deshabilitada
+ Activar
+
+ Falló la detección del servicio
+ No se pudo refrescar lista de colección
+
+ Ajustes
+ Depuración
+ Mostrar la información de depuración
+ Ver/compartir detalles de software y configuración
+ Registro extendido
+ El registro está activo
+ El registro está deshabilitado
+ Conexión
+ Anular ajustes del proxy
+ Usar ajustes personalizados del proxy
+ Usar ajustes del proxy predefinidos por el sistema
+ Nombre del host del proxy HTTP
+ Puerto del proxy HTTP
+ Seguridad
+ Invalidar los certificados del sistema
+ Los CA del sistema y los añadidos por el usuario no serán válidos
+ Los CA del sistema y los añadidos por el usuario serán usados y de confianza (recomendado)
+ Reiniciar certificados (in)validados
+ Reinicia la validez de todos los certificados particulares
+ Todos los certificados particulares han sido limpiados
+ Interfaz de usuario
+ Ajustes de notificación
+ Administrar notificación de canales y sus ajustes
+ Restablecer advertencias
+ Habilita las advertencias que han sido rechazadas con anterioridad
+ Todas las advertencias se mostrarán nuevamente
+
+ CardDAV
+ CalDAV
+ Webcal
+ No hay libretas de direciones (todavía).
+ No hay calendarios (todavía).
+ No hay suscripciones a calendarios (todavía).
+ Desliza hacia abajo para actualizar la lista desde el servidor.
+ Sincronizar ahora
+ Sincronizando
+ Ajustes de cuenta
+ Renombrar cuenta
+ Información local no guardada puede ser desechada. Se requiere resincronizar después de renombrar. Nuevo nombre de cuenta:
+ Renombrar
+ Eliminar cuenta
+ ¿Seguro que deseas eliminar la cuenta?
+ Todas las copias locales de tus contactos, calendarios y tareas serán eliminadas.
+ sincronizar ésta colección
+ solo lectura
+ calendario
+ lista de tareas
+ Refrescar contactos
+ Crear nueva agenda
+ Refrescar calendario
+ Crear nuevo calendario
+ No se encontró aplicación para administrar Webcal
+ Instalar ICSx⁵
+
+ Añadir cuenta
+ Acceder con cuenta de correo
+ Dirección de correo
+ Se requiere una dirección de correo válida
+ Contraseña
+ Contraseña requerida
+ Acceder con URL y nombre de usuario
+ La URL debe comenzar con http(s)://
+ El URL debe comenzar con https://
+ Nombre de servidor requerido
+ Nombre de usuario
+ Nombre de usuario requerido
+ URL base
+ Iniciar sesión con URL y certificado del cliente
+ Seleccionar un certificado
+ Registrar
+ Volver
+ Añadir cuenta
+ Nombre de cuenta
+ Usa tu dirección de correo como nombre de cuenta puesto que Android usará el nombre de la cuenta como campo de \"organizador\" en los eventos que cree. No puedes tener dos cuentas con el mismo nombre.
+ Método de contacto de grupo:
+ Nombre de cuenta requerido
+ El nombre de la cuenta ya está siendo utilizado
+ La cuenta no pudo ser creada
+ Detectar configuración
+ Por favor espera, consultando al servidor…
+ No se pudo encontrar el servicio CalDAV o CardDAV.
+ Mostrar detalles
+
+ Ajustes: %s
+ Sincronización
+ Intervalo de sincronización de contactos
+ Solo manualmente
+ Cada %d minutos + inmediatamente con cambios locales
+ Intervalo de sincronización de calendarios
+ Intervalo de sincronizacion de Tasks
+
+ - Solo manualmente
+ - Cada 15 minutos
+ - Cada 30 minutos
+ - Cada hora
+ - Cada 2 horas
+ - Cada 4 horas
+ - Una vez al dia
+
+ Sincronizar sólo sobre WiFi
+ La sincronización está restringida a conexiones WiFi
+ Tipo de conexión no tenido en cuenta
+ Restricción WiFi SSID
+ Solo se sincronizará a través de %s
+ Solo sincronizará sobre %s (requiere servicios de ubicación activos)
+ Todas las conexiones WiFi serán usadas
+ Nombres separados por comas (SSIDs) de redes WiFi permitidas (deje vacío para todas)
+ Para leer nombres de WiFi, los permisos de Ubicación y servicios de ubicación permanente son necesarios.
+ Más información (preguntas frecuentes)
+ Autenticación
+ Nombre de usuario
+ Introduce tu nombre de usuario:
+ Contraseña
+ Actualiza la contraseña de acuerdo a tu servidor.
+ Introduce tu contraseña:
+ Alias del certificado cliente
+ CalDAV
+ Límite de tiempo de eventos pasados
+ Todos los eventos serán sincronizados
+
+ - Los eventos anteriores a un día serán ignorados
+ - Los eventos anteriores a %d días serán ignorados
+
+ Los eventos anteriores a este número de días serán ignorados (puede ser 0). Deja en blanco el campo para sincronizar todos los eventos.
+ Colores de calendario
+ Los colores de los calendarios son administrados por Gerente de cuentas
+ Los colores de los calendarios no son establecidos por Gerente de cuentas
+ Soporte de colores en eventos
+ Sincronizar colores de eventos
+ No sincronizar colores de eventos
+ CardDAV
+ Método de contacto de grupo
+ Cambie método de grupo
+
+ Crear nueva agenda
+ Agendas
+ Crear calendario
+ Huso horario
+ El huso horario es necesario
+ Posibles entradas de calendario
+ Eventos
+ Tareas
+ Notas / jornal
+ Combinado (eventos y tareas)
+ Color
+ Crear colección
+ Título
+ Título requerido
+ Descripción
+ opcional
+ Ubicación del almacenamiento
+ Crear
+ Eliminar colección
+ ¿Estás seguro/a?
+ Esta colección (%s) y todos sus datos serán eliminados permanentemente.
+ Estos datos se eliminarán del servidor.
+ Eliminando colección
+ Forzar solo-lectura
+ Propiedades
+ Dirección (URL):
+ Copiar URL
+
+ Ocurrió un error.
+ Ha ocurrido un error HTTP.
+ Ha ocurrido un error I/O.
+ Mostrar detalles
+
+ Información de depuración
+ Los registros van adjuntos a este mensaje (requiere suporte de adjuntos en la app que los recibe).
+ Libro de direcciones solo-lectura
+ Permisos de Gerente de cuentas
+ Permisos adicionales requeridos
+ OpenTasks muy viejo
+ Versión requerida: %1$s (actual %2$s)
+ Falló la autenticación (revise credenciales de inicio de sesión)
+ Error de red o E/S – %s
+ Error de servidor – %s
+ Error de almacenamiento local – %s
+ Reintentar
+ Ver item
+ Contacto inválido recibido del servidor
+ Evento inválido recibido del servidor
+ Tarea inválida recibidas del servidor
+ Ignorando uno o más recursos inválidos
+
+ Administrador de cuentas: Seguridad de la conexión
+ El administrador de cuentas ha encontrado un certificado desconocido. ¿Quieres que sea válido\?
+ e.foundation.webdav.eelo
+ /e/
+ Google
+ WebDAV
+ Por favor instala un cliente de correo
+ Credenciales, sincronización, etc.
+ Contactos Google
+ Contactos /e/
+ Por favor instale un navegador web
+ Iniciar sesión con una cuenta /e/
+ No hay conexión a internet. Android no se sincronizará.
+ Política de privacidad
+ Usar servidor personalizado
+ URL del servidor (https://server_url)
+ Se requiere un URL de servidor válido
+ Usar un servidor específico
+ Actualizar nombre de usuario y contraseña
+ Credenciales
+ Recordatorio predeterminado
+
+ - Recordatorio predeterminado un minuto antes del evento
+ - Recordatorio predeterminado %d minutos antes del evento
+
+ No se ha creado ningún recordatorio predeterminado
+ Si se deben crear recordatorios para eventos predeterminados sin recordatorio: el número deseado de minutos antes del evento. Déjelo en blanco para deshabilitar los recordatorios predeterminados.
+ /e/ reportará un dispositivo falso a Google para proteger su privacidad.
+\nPuedes revisar cuáles en \"Tus dispositivos\" de Google después de iniciar sesión.
+ ADVERTENCIA
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index c72ca1efcdd896c8bc2eb116826d32e5beb5076d..a0da730513147f5eb3dc78a8a6f9adce07214cc6 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -1,419 +1,274 @@
-
+
-
- DAVx⁵
- Kontua ez da existitzen (dagoeneko)
- DAVx⁵ Helbide liburua
- Helbide liburuak
- Eremu hau beharrezkoa da
- Laguntza
- Kudeatu kontuak
- Partekatu
- Datu-basea hondatua
- Kontu lokal guztiak ezabatu dira.
- Arazten
- Beste mezu garrantzitsu batzuk
- Prioritate baxuko egoera mezuak
- Sinkronizazioa
- Sinkronizazio erroreak
- Sinkronizazioa gelditzen duten errore garrantzitsuak, esaterako ustekabeko zerbitzariaren erantzunak
- Sinkronizazio abisuak
- Fitxategi baliogabe moduko sinkronizazio arazo ez-kritikoak
- Sare eta S/I erroreak
- Denbora-mugak, konexio arazoak, etab. (normalean behin-behinekoak)
-
- Zure datuak. Zure aukera.
- Har ezazu kontrola.
- Sinkronizazio tarte erregularrak
- Desgaituta (ez gomendatuta)
- Gaituta (gomendatuta)
- Sinkronizazioa tarte erregularretan ahalbidetzeko, %s atzeko planoan exekutatzen utzi behar da. Bestela, Androidek sinkronizazioa gelditu dezake edozein unean.
- Ez ditut sinkronizazio tarte erregularrak behar.*
- %s bateragarritasuna
- Gailu honek ziurrenik sinkronizazioa blokeatzen du. Hau jasaten baduzu, eskuz konpondu dezakezu soilik.
- Beharrezko ezarpenak bukatu ditut. Ez gogorarazi berriro.*
- * Utzi aktibatu gabe gero gogorarazteko. Aplikazioaren ezarpenetan berrezarri daiteke / %s
- Informazio gehiago
- jtx taula
-
- Tasks bateragarritasuna
- Zereginak zure zerbitzarian onartuta badaude, onartutako zeregin aplikazio batekin sinkronizatu daitezke:
- OpenTasks
- aplikazio gehigarriak behar izatea.]]>
- Tasks
- ez dira onartzen (oraindik).]]>
- Ez dago denda aplikaziorik eskuragarri
- Ez dut zereginen funtzionalitatea behar.*
- Kode irekiko softwarea
- %s erabiltzen duzula pozik gaude, software irekia delako. Garapen, mantentze eta laguntza lan gogorrak dira. Mesedez pentsatu kolaboratzen (modu asko daude) edo dohaintza bat. Asko eskertuko genuke!
- Nola lagundu/dirua eman
- Ez erakutsi etorkizunean
-
- Baimenak
- %s baimenak behar ditu ondo funtzionatzeko.
- Azpiko guztiak
- Erabili hau ezaugarri guztiak gaitzeko (gomendatuta)
- Baimen guztiak eman dira
- Kontaktuen baimenak
- Kontaktu sinkronizaziorik ez (ez gomendatuta)
- Kontaktuen sinkronizazioa posible
- Egutegiaren baimenak
- Egutegi sinkronizaziorik ez (ez gomendatuta)
- Egutegiaren sinkronizazioa posible
- jtx taularen baimenak
- Zereginen, egunkarien eta noten sinkronizaziorik ez (instalatu gabe)
- Zeregin, egunkari, noten sinkronizaziorik ez
- Zeregin, egunkari, noten sinkronizazioa posible
- OpenTasks baimenak
- Tasks baimenak
- Ez sinkronizatu zereginak (instalatu gabe)
- Zeregin sink. ez
- Zereginen sinkronizazioa posible
- Mantendu baimenak
- Baimenak automatikoki berezarri daitezke (ez gomendatuta)
- Baimenak ez dira automatikoki berezarriko
- Egin klik Baimenak atalean > kendu marka \"Kendu baimenak aplikazioa ez bada erabiltzen\" aukeratik
- Interruptore batek funtzionatzen ez badu, erabili aplikazioaren ezarpenak / Baimenak.
- Aplikazioaren ezarpenak
-
- WiFi SSID baimenak
- Uneko WiFi izena (SSID) atzitzeko, baldintza hauek bete behar dira:
- Kokapen zehatz baimena
- Kokapen baimena emanda
- Kokapen baimena ukatuta
- Atzeko planoko kokapen baimena
- Baimendu beti
- %s(e)ra ezarri da]]>
- %s(e)ra ezarri]]>
- %s zure kokapen baimena erabiltzen du uneko WiFi SSIDa SSIDz murriztatutako kontuen kontra egiaztatzeko. Hau aplikazioa atzeko planoan badago ere gertatuko da. Ez da kokapen daturik biltzen, gordetzen, prozesatzen edo inora bidaltzen.
- Kokapena beti gaituta
- Kokapen zerbitzua gaituta dago
- Kokapen zerbitzua desgaituta dago
-
- Itzulpenak
- Liburutegiak
- %1$s (%2$d) bertsioa
- %s(e)an konpilatuta
- © Ricki Hirner, Bernhard Stockmann (bitfire web engineering GmbH) eta kolaboratzaileak
- Bertsio hau Google Play bidez soilik banatu daiteke.
- Programa hau INOLAKO BERMERIK GABE dator. Software librea da, eta birbanatzeko baimena duzu baldintza batzuk kontuan hartuz.
- Eskerrik asko: %s]]>
-
- Ezin izan da egunkari fitxategia sortu
- %s jarduera guztiak erregistratzen
- Ikusi/partekatu
- Desgaitu
-
- Ireki nabigatzeko menu lerrakorra
- Itxi nabigatzeko menu lerrakorra
- CalDAV/CardDAV sinkronizazio moldagailua
- Honi buruz / Lizentzia
- Beta iritzia
- Instalatu e-mail bezero bat
- Instalatu web nabigatzaile bat
- Ezarpenak
- Berriak eta eguneraketak
- Tresnak
- Kanpo loturak
- Webgunea
- Manuala
- FAQ
- Komunitatea
- Dohaintza egin
- Pribatutasun gidalerroak
- Ez dago internetik. Androidek ez du sinkronizaziorik egingo.
- Biltegiratze-lekua baxua da. Androidek ez du sinkronizatuko.
- Ongi etorri DAVx⁵ aplikaziora!\n\nCalDAV/CardDAV kontu bat gehitu dezakezu orain.
- Sistema osoko sinkronizazio automatikoa desgaituta dago
- Gaitu
- Sinkronizatu kontu guztiak
-
- Zerbitzuaren detekzioak huts egin du
- Ezin izan da bilduma zerrenda freskatu
-
- Ezin da aurrealdean exekutatu
- Bateriaren optimizazioaren zerrenda zuria behar da
-
- Aurrealdean exekutatzen
- Gailu batzuetan, hau beharrezkoa da sinkronizazio automatikorako.
-
- Ezarpenak
- Arazketa
- Erakutsi arazte informazioa
- Ikusi/partekatu software eta konfigurazio xehetasunak
- Erregistro xehatuak
- Erregistratzea gaituta dago
- Erregistratzea desgaituta dago
- Bateria optimizazioa
- Aplikazioa zerrenda zurian dago (gomendatuta)
- Aplikazioa ez dago zerrenda zurian (ez gomendatuta)
- Mantendu aurrealdean
- Zure gailuak sinkronizazio automatikoa galarazten badu lagundu dezake
- Konexioa
- Proxy mota
-
- - Sistemaren lehenetsia
- - Proxyrik ez
- - HTTP
- - SOCKS (Orbot-erako)
-
- Proxy ostalariaren izena
- Proxy ataka
- Segurtasuna
- Aplikazioaren baimenak
- Berrikusi sinkronizaziorako beharrezkoak diren baimenak
- Mesfidatu sistemaren ziurtagiritaz
- Sistemako eta erabiltzaileak gehitutako CAk ez dira fidagarritzat hartuko
- Sistemako eta erabiltzaileak gehitutako CAk fidagarritzat hartuko dira (gomendatuta)
- Berezarri (mes)fidatutako ziurtagiriak
- Ziurtagiri pertsonalizatu guztien fidagarritasuna berezartzen du
- Ziurtagiri pertsonalizatu guztiak garbitu dira
- Erabiltzaile interfazea
- Jakinarazpen-ezarpenak
- Kudeatu jakinarazpen kanalak eta haien ezarpenak
- Hautatu gaia
-
- - Sistemaren lehenetsia
- - Argia
- - Iluna
-
- Berezarri aholkuak
- Lehen baztertu diren aholkuak berriro gaitzen ditu
- Aholku guztiak erakutsiko dira berriro
- Integrazioa
- Tasks aplikazioa
- %s(r)ekin sinkronizatzen
- Ez da zeregin aplikazio bategarririk aurkitu
-
- CardDAV
- CalDAV
- Webcal
- Kontaktu sinkronizaziorik ez (baimenak falta dira)
- Egutegi sinkronizaziorik ez (baimenak falta dira)
- Zeregin sinkronizaziorik ez (baimenak falta dira)
- Egutegi eta zeregin sinkronizaziorik ez (baimenak falta dira)
- Ezin dira egutegiak atzitu (baimenak falta dira)
- Baimenak
- Ez dago helbide libururik (oraindik).
- Ez dago egutegirik (oraindik).
- Ez dago egutegi harpidetzarik (oraindik).
- Lerratu beherantz zerbitzariaren zerrenda freskatzeko.
- Sinkronizatu orain
- Sinkronizatzen orain
- Kontuaren ezarpenak
- Berrizendatu kontua
- Gorde gabeko datu lokalak baztertu daitezke. Berriro sinkronizatu behar da izena aldatu ostean. Kontuaren izen berria:
- Berrizendatu
- Ezin izan da kontua berrizendatu
- Ezabatu kontua
- Ezabatu kontua?
- Helbide liburu, egutegi eta zeregin zerrenden kopia lokal guztiak ezabatuko dira.
- sinkronizatu kolekzio hau
- irakurri-soilik
- egutegia
- zeregin zerrenda
- egunkaria
- Erakutsi pertsonala soilik
- Freskatu helbide liburuen zerrenda
- Sortu helbide liburu berria
- Freskatu egutegi zerrenda
- Sortu egutegi berria
- Ez da Webcal-ekin bateragarria den aplikaziorik aurkitu
- Instalatu ICSx⁵
-
- Gehitu kontua
- Saioa hasi helbide elektronikoarekin
- Helbide elektornikoa
- Baliozko eposta beharrezkoa da
- Pasahitza
- Pasahitza beharrezkoa
- Saioa hasi URL eta erabiltzaile izenarekin
- URLa http(s):// hasi behar da
- Erabiltzaile izena
- Erabiltzaile izena beharrezkoa
- Oinarri URL
- Saioa hasi URL eta bezero ziurtagiriarekin
- Aukeratu ziurtagiria
- Saioa hasi
- Sortu kontua
- Kontuaren izena
- Apostrofeen erabilera (\'), gailu batzuetan arazoak sortzen ditu.
- Erabili zure eposta helbidea kontu izen bezala Androidek kontuaren izena ANTOLATZAILE eremuan ezarriko duelako sortzen dituzun gertaerentzako. Ezin dituzu bi kontu izen berdinarekin eduki.
- Kontaktuen taldekatze metodoa:
- Kontuaren izena beharrezkoa
- Kontuaren izena hartuta dago
- Ezin izan da kontua sortu
- Saio-hasiera aurreratua (kasu bereziak)
- Erabili erabiltzaile-izena/pasahitza
- Erabili bezero ziurtagiria
- Ez da ziurtagiririk aurkitu
- Instalatu ziurtagiria
- Konfigurazio detekzioa
- Mesedez itxaron, zerbitzaria kontsultatzen...
- Ezin izan da CalDAV edo CardDAV zerbitzua aurkitu.
- Erabiltzaile-izena (eposta) / pasahitza txarto dago?
- Erakutsi xehetasunak
-
- Ezarpenak: %s
- Sinkronizazioa
- Kontaktuen sink. tartea
- Eskuz soilik
- %d minuturo + berehala aldaketa lokaletan
- Egutegien sink. tartea
- Zereginen sink. tartea
-
- - Eskuz soilik
- - 15 minuturo
- - 30 minuturo
- - Ordu batero
- - 2 orduro
- - 4 orduro
- - Egunero
-
- Sinkronizatu soilik WiFi bidez
- Sinkronizazioa WiFi konexioetara murriztuta dago
- Konexio mota ez da kontuan hartzen
- WiFi SSID murriztapena
- %s(r)en bidez soilik sinkronizatuko du
- %s(r)en bidez soilik sinkronizatuko du (kokapen zerbitzua gaituta behar du)
- WiFi konexio guztiak erabiliko dira
- Komaz banatutako izenak (SSIDak) baimendutako WiFi sareentzako (utzi hutsik denentzako)
- WiFi SSID murriztapenak ezarpen gehiago behar ditu
- Kudeatu
- Informazio gehiago (FAQ)
- Autentifikazioa
- Erabiltzaile izena
- Sartu erabiltzaile izena:
- Pasahitza
- Eguneratu pasahitza zure zerbitzariaren arabera
- Sartu zure pasahitza:
- Bezeroaren ziurtagiriaren aliasa
- Ez da ziurtagiririk hautatu
- CalDAV
- Aurreko gertaeren denbora muga
- Ekintza guztiak sinkronizatuko dira
-
- - Egun bat baino gehiago dituzten gertaerak ezikusiko dira
- - %d egun baino gehiago dituzten gertaerak ezikusiko dira
-
- Orain dela egun hauek gertatu ziren gertaerak ezikusiko dira (0 izan daiteke). Utzi hutsik gertaera guztiak sinkronizatzeko.
- Abisu lehentsia
-
- - Abisu lehenetsia gertaera baino minutu bat lehenago
- - Abisu lehenetsia gertaera baino %d minutu lehenago
-
- Ez dago abisu lehenetsirik sortuta
- Abisu lehenetsiak sortu behar badira abisurik gabeko gertaerentzat: nahi den minutu kopurua gertaera baino lehen. Utzi hutsik abisu lehenetsiak desgaitzeko.
- Kudeatu egutegi koloreak
- Egutegiaren koloreak sinkronizazio bakoitzean berrezarten dira
- Egutegiaren koloreak beste aplikazio batzuetatik ezarri daitezke
- Gertaera kolore bateragarritasuna
- Gertaera koloreak sinkronizatuta daude
- Gertaera koloreak ez daude sinkronizatuta
- CardDAV
- Kontaktu taldekatze metodoa
-
- - Taldeak vCard banatuak dira
- - Taldeak kontaktu bakoitzeko kategoriak dira
-
- Aldatu taldekatze metodoa
-
- Sortu helbide liburua
- Nire Helbide Liburua
- Sortu egutegia
- Ordu-zona
- Egutegi sarrera posibleak
- Gertaerak
- Zereginak
- Notak / egunkaria
- Elkartuta (gertaera eta zereginak)
- Kolorea
- Kolekzioa sortzen
- Izenburua
- Izenburua beharrezkoa da
- Deskribapena
- aukerazkoa
- Biltegiratze kokapena
- Biltegiaren kokapena beharrezkoa da
- Sortu
- Ezabatu kolekzioa
- Ziur zaude?
- Bilduma hau (%s) eta bere datu guztiak behin betiko ezabatuko dira.
- Datu hauek zerbitzaritik ezabatu beharko litzakete.
- Kolekzioa ezabatzen
- Behartu irakurri-soilik
- Propietateak
- Helbidea (URL):
- Kopiatu URL
- Jabea:
-
- Arazketa informazioa
- ZIP artxiboa
- Arazte informazioa eta erregistroak ditu
- Partekatu artxiboa ordenagailu batera transferitzeko, e-posta edo ticket baten bidez bidaltzeko.
- Partekatu artxiboa
- Arazketa informazioa mezuan erantsiko da (hartuko dituen aplikazioak eranskinak onartu behar ditu).
- HTTP errorea
- Zerbitzari errorea
- WebDAV errorea
- S/I errorea
- Eskaera ukatu egin da. Egiaztatu parte hartzen dituzten baliabideak eta arazketa informazioa xehetasun gehiagorako.
- Eskatutako baliabidea ez dago (jada). Egiaztatu parte hartzen dituzten baliabideak eta arazketa informazioa xehetasun gehiagorako.
- Zerbitzariak arazo bat izan du. Mesedez jarri harremanetan zure zerbitzariaren laguntzarekin.
- Ustekabeko errore bat gertatu da. Ikusi arazketa informazioa xehetasunentzako.
- Ikusi xehetasunak
- Arazketa informazioa lortu da
- Parte hartzen duten baliabideak
- Arazoarekin erlazionatuta
- Kanpoko baliabidea:
- Baliabide lokala:
- Ikusi aplikazioarekin
- Egunkariak
- Erregistro xehetuak eskuragarri daude
- Ikusi egunkariak
-
- Errore bat gertatu da
- HTTP errore bat gertatu da.
- S/I errore bat gertatu da.
- Erakutsi xehetasunak
-
- Sinkronizazioa geldituta
- Ia ez dago leku librerik
-
- WebDAV muntaiak
- Erabilitako kuota: %1$s / eskuragarri: %2$s
- Partekatu edukia
- Desmuntatu
- Gehitu WebDAV muntaia
- Atzitu zure cloud fitxategiak zuzenean WebDAV muntaia bat gehitzen!
- WebDAV muntaiak nola funtzionatzen duten.]]>
- Bistaratze-izena
- WebDAV URL
- URL baliogabea
- Erabiltzaile izena
- Pasahitza
- Gehitu muntaia
- Ez dago WebDAV zerbitzurik URL honetan
- WebDAV fitxategia atzitzen
- WebDAV fitxategia deskargatzen
- WebDAV fitxategia kargatzen
- WebDAV muntaia
-
- DAVx⁵ baimenak
- Baimen gehigarriak beharrezkoak
- %s zaharregia
- Beharrezko bertsio minimoa: %1$s
- Autentifikazioak huts egin du (egiaztatu saio-hasiera kredentzialak)
- Sare edo S/I errorea – %s
- HTTP zerbitzari-errorea – %s
- Biltegiratze lokal errorea – %s
- Saiatu berriz
- Ikusi elementua
- Kontaktu baliogabea jaso da zerbitzaritik
- Gertaera baliogabea jaso da zerbitzaritik
- Zeregin baliogabea jaso da zerbitzaritik
- Baliabide baliogabe bat edo gehiago ezikusten
-
- DAVx⁵: Konexio segurtasuna
- DAVx⁵ aplikazioak ziurtagiri ezezagun bat aurkitu du. Fidagarritzat jo nahi duzu?
+
+ Kontu-kudeatzailea
+ WebDav helbide liburua
+ Helbide liburuak
+ Laguntza
+ Bidali
+ Arazten
+ Beste mezu garrantzitsu batzuk
+ Sinkronizazioa
+ Sinkronizazio erroreak
+ Sinkronizazioa gelditzen duten errore garrantzitsuak, esaterako ustekabeko zerbitzariaren erantzunak
+ Sinkronizazio abisuak
+ Sare eta S/I erroreak
+
+ Sinkronizazio automatikoa
+ Programatutako sinkronizazioa
+ Desgaitu Kontu-kudeatzailearentzat
+ Ez erakutsi berriro
+ Orain ez
+ Kode-Ireki Informazioa
+ Erakutsi dohaintza orrialdea
+ Agian geroago
+ Informazio gehiago
+ OpenTask ez dago instalatuta
+ Instalatu OpenTasks
+
+ Liburutegiak
+ %1$s (%2$d) bertsioa
+ %s(e)an konpilatuta
+
+ Ezin izan da egunkari fitxategia sortu
+ Bidali egunkaria
+
+ Honi buruz / Lizentzia
+ Instalatu e-mail bezero bat
+ Instalatu web nabigatzaile bat
+ Ezarpenak
+ Berriak eta eguneraketak
+ Kanpo loturak
+ Webgunea
+ Eskuz
+ FAQ
+ Laguntza / Foroak
+ Dohaintza egin
+ Pribatutasun politika
+ Gaitu
+
+
+ Ezarpenak
+ Arazketa
+ Erakutsi arazte informazioa
+ Konexioa
+ HTTP proxy hostalari izena
+ HTTP proxy portua
+ Segurtasuna
+ Erabiltzaile interfazea
+ Jakinarazpen-ezarpenak
+
+ Kontaktuak
+ Egutegia
+ Webcal
+ Sinkronizatu orain
+ Sinkronizatzen orain
+ Kontuaren ezarpenak
+ Berrizendatu kontua
+ Berrizendatu
+ Ezabatu kontua
+ irakurri-soilik
+ egutegia
+ zeregin zerrenda
+ Freskatu helbide liburuen zerrenda
+ Sortu helbide liburu berria
+ Freskatu egutegi zerrenda
+ Sortu egutegi berria
+ Instalatu ICSx⁵
+
+ Gehitu kontua
+ Saioa hasi helbide elektronikoarekin
+ Helbide elektornikoa
+ Pasahitza
+ Pasahitza beharrezkoa
+ Saioa hasi URL eta erabiltzaile izenarekin
+ Hostalari izena beharrezkoa
+ Erabiltzaile izena
+ Erabiltzaile izena beharrezkoa
+ Oinarri URL
+ Saioa hasi URL eta bezero ziurtagiriarekin
+ Aukeratu ziurtagiria
+ Saioa hasi
+ Atzera
+ Gehitu kontua
+ Kontuaren izena
+ Erakutsi xehetasunak
+
+ Ezarpenak: %s
+ Sinkronizazioa
+ Sinkronizatu soilik WiFi bidez
+ Autentifikazioa
+ Erabiltzaile izena
+ Sartu erabiltzaile izena:
+ Pasahitza
+ Sartu zure pasahitza:
+ CalDAV
+ Kudeatu egutegiaren koloreak
+ Sinkronizatu gertaeren koloreak
+ Kontaktuak
+
+ Sortu helbide liburua
+ Nire Helbide Liburua
+ Sortu egutegia
+ Gertaerak
+ Zereginak
+ Kolorea
+ Izenburua
+ Deskribapena
+ aukerazkoa
+ Biltegiratze kokapena
+ Sortu
+ Ziur zaude?
+ Propietateak
+ Kopiatu URL
+
+ Errore bat gertatu da.
+ HTTP errore bat gertatu da.
+ Erakutsi xehetasunak
+
+ Arazketa informazioa
+ Soilik irakurtzeko helbide liburua
+ Kontu-kudeatzailearen baimenak
+ OpenTasks zaharregia
+ Sare edo S/I errorea – %s
+ HTTP zerbitzari-errorea – %s
+ Saiatu berriro
+ Ikusi elementua
+
+ Kontu-kudeatzailea: Konexioaren segurtasuna
+ Kontu-kudeatzaileak ziurtagiri ezezagun bat aurkitu du. Fidagarritzat jo nahi duzu\?
+ Zereginak sinkronizatzeko, OpenTasks doako aplikazioa beharrezkoa da. (Ez da beharrezkoa kontaktuetarako/gertaeretarako.)
+ Denbora-mugak, konexio-arazoak, etab. (maiz aldi baterakoak)
+ Kredentzialak, sinkronizazio-frekuentzia, etab.
+ Google helbide-liburua
+ /e/ helbide-liburua
+ /e/
+ Google
+ WebDAV
+ Ez sinkronizatu gertaeren koloreak
+ Gehitu kontua
+ Ziurtagiri pertsonalizatu guztiak garbitu dira
+ Ziurtagiri pertsonalizatu guztien fidagarritasuna leheneratzen du
+ Leheneratu ziurtagiri (ez) fidagarriak
+ Sistemako eta erabiltzaileak gehitutako ziurtagiriak fidagarritzat joko dira (aholkatua)
+ Sistemako eta erabiltzaileak gehitutako ziurtagiriak ez dira fidagarritzat joko
+ Itxi nabigazio-panel lerrakorra
+ Ireki nabigazio-panel lerrakorra
+ ABISUA
+ Zure gailuak Kontu-kudeatzailearen sinkronizazioa kontrolatuko du. Kontu-kudeatzailearen sinkronizazio-tarte erregularrak betearazteko, itzali \"bateriaren optimizazioa\".
+ Egutegi/Kontaktu sinkronizazio moldagailua
+ Orain %s jarduera guztiak erregistratzen ari dira
+ Kontu-kudeatzailearen erregistroa
+ Programa honek ez du INOLAKO BERMERIK. Hau software librea da, eta birbanatu dezakezu zenbait baldintzarekin.
+ Bertsio hau soilik Google Play-n banatu daiteke.
+ OpenTasks instalatu ostean Kontu-kudeatzailea berrinstalatu eta kontaktu berriro gehitu behar dituzu (Androiden akatsa).
+ Pozik gaude zuk Kontu-kudeatzailea erabiltzeaz, software librea dena (GPLv3). Kontu-kudeatzailea garatzea lan gogorra denez eta milaka lanordu eman dizkigunez, mesedez, egin dohaintza bat.
+ %s firmwareak maiz sinkronizazio automatikoa blokeatzen du. Kasu horretan, baimendu sinkronizazio automatikoa Androiden ezarpenetan.
+ Sinkronizazioa arazo ez larriak, baliogabeko fitxategi batzuk kasu
+ Ikusi/Partekatu softwarearen eta konfigurazioaren xehetasunak
+ Ezin izan da freskatu bilduma zerrenda
+ Zerbitzua antzemateak huts egin du
+ Sistema mailako sinkronizazio automatikoa desgaituta dago
+ Ongi etorri Kontu-kudeatzailera!
+\n
+\nEgutegi/Kontaktu kontu bat gehitu dezakezu.
+ Interneterako sarbiderik ez. Androidek ez du sinkronizatuko.
+ Beta-rentzako iritzia
+
+ - Egun bat atzera baino lehenagoko gertaerak ezikusiko dira
+ - %d egun atzera baino lehenagoko gertaerak ezikusiko dira
+
+ Gertaera guztiak sinkronizatuko dira
+ Pasatako gertaeren denbora-muga
+ Bezero-ziurtagiriaren ezizena
+ Eguneratu pasahitza zure zerbitzariaren arabera.
+ Eguneratu erabiltzaile-izena eta pasahitza
+ Kredentzialak
+ Informazio gehiago (ohiko galderak)
+ WiFi izenak irakurtzeko, kokapenarentzako baimena eta kokapen-zerbitzuak etengabe aktibo egotea behar da.
+ Onartutako WiFI sareen komaz separatutako izenak (SSIDak), hutsik utzi denak onartzeko
+ WiFi konexio oro erabiliko da
+ %s bidez soilik sinkronizatuko da (kokapen-zerbitzu aktiboak behar ditu)
+ %s bidez soilik sinkronizatuko da
+ WiFi SSIDrako muga
+ Konexio-modua ez da kontuan hartzen
+ Sinkronizazio WiFi konexioetara mugatua dago
+ Zereginen sinkronizazio-tartea
+ Egutegien sinkronizazio-tartea
+ %d minuturo eta aldaketa lokalik egon bezain laster
+ Soilik eskuz
+ Kontaktuen sinkronizazio-tartea
+ Erabili zerbitzari zehazt bat
+ Baliozko zerbitzariaren URL helbidea behar da
+ Zerbitzariaren URLa (https://zerbitzariaren_url-a)
+ Erabili zerbitzari pertsonalizatua
+ Saioa hasteak huts egin du. Egiaztatu erabiltzaile-izena eta pasahitza.
+ Itxaron, kontua gehitzen…
+ Jada badago izen bereko kontu bat
+ Kontuaren izen hori jada erabili da
+ Kontuaren izena behar da
+ Kontaktu-taldeen metodoa:
+ Erabili zure eposta helbidea kontuaren izen gisa, Androidek kontuaren izena erabiliko baitu zuk sortutako gertaeretan \"antolatzaile\" atala betetzeko. Ezin dituzu eduki izen bereko bi kontu.
+ URLak https:// egiturarekin hasi behar du
+ URLak http(s):// egiturarekin hasi behar du
+ Baliozko eposta helbide bat behar da
+ Hasi saioa /e/ kontu batekin
+ Ez da aurkitu WebCal onartzen duen aplikaziorik
+ sinkronizatu bilduma hau
+ Helbide-liburu, egutegi eta zeregin-zerrenden kopia lokal guztiak ezabatuko dira.
+ Ziur kontua ezabatu nahi duzula\?
+ Gorde gabeko datu lokalak baztertu litezke. Berriz sinkronizatu behar da berrizendatu ostean. Kontuaren izen berria:
+ Arrastatu beheruntz zerbitzariko zerrenda freskatzeko.
+ Ez dago egutegietarako harpidetzarik (oraindik).
+ Ez dago egutegirik (oraindik).
+ Ez dago helbide-liburuik (oraindik).
+ Iradokizun guztiak erakutsiko dira berriro
+ Aurretik baztertuak izan diren iradokizunak gaitzen ditu berriro
+ Berrezarri iradokizunak
+ Kudeatu jakinarazpen kanalak eta euren ezarpenak
+ Ez fidatu sistemako ziurtagiriez
+ Erabili sistemak lehenetsitako proxy ezarpenak
+ Erabili proxy ezarpen pertsonalizatuak
+ Ezikusi proxy ezarpenak
+ Erregistratzea desgaituta dago
+ Erregistratzea aktibo dago
+ Erregistro xehatua
+ /e/-k zurea ez den gailu faltsu baten izena emango dio Google-i, zure pribatutasuna babesteko.
+\nSaioa hasi ondoren, zein gailuren izena eman zaion egiazta dezakezu Google-en Gailuaren Jarduera atalean.
+ Baliogabeko baliabide bat edo gehiago ezikusten
+ Baliogabeko zeregina jaso da zerbitzaritik
+ Baliogabeko gertaera jaso da zerbitzaritik
+ Baliogabeko kontaktua jaso da zerbitzaritik
+ Biltegiratze lokal errorea – %s
+ Autentifikazioak huts egin du (begiratu saio-haste kredentzialak)
+ Beharrezko bertsioa: %1$s (unekoa %2$s da)
+ Baimen gehiago behar dira
+ Erregistroak mezu honi erantsita daude (jasotzen duen aplikazioak eranskinentzako euskarria behar du).
+ S/I errore bat gertatu da.
+ Helbidea (URL):
+ Behartu irakurri-soilik
+ Bilduma ezabatzen
+ Datu hauek zerbitzarian ezabatu beharko ziren.
+ Bilduma hau (%s) eta bere datu guztiak betirako ezabatuko dira.
+ Ezabatu bilduma
+ Izenburua behar da
+ Bilduma sortzen
+ Konbinatua (gertaerak eta zereginak)
+ Oharrak / Egunerokoa
+ Egutegiko sarrera posibleak
+ Ordu-zona behar da
+ Ordu-zona
+ Aldatu taldeen metodoa
+ Kontaktu taldeen metodoa
+ Gertaerak koloreztatzeko euskarria
+ Egutegien koloreak ez ditu Kontu-kudeatzaileak ezartzen
+ Egutegien koloreak Kontu-kudeatzaileak ezartzen ditu
+ Abisurik gabeko gertaerentzat lehenetsitako abisuak sortu beharko balira: gertaera aurretiko minutu kopurua. Hutsik utzi lehenetsitako abisuak desgaitzeko.
+ Ez da sortzen lehenetsitako abisurik
+
+ - Lehenetsitako abisua gertaera baino minutu bat lehenago
+ - Lehenetsitako abisua gertaera baino %d minutu lehenago
+
+ Lehenetsitako abisua
+ Iraganean egun kopuru hau (0 izan daiteke) baino lehenagoko gertaerak ezikusiko dira. Hutsik utzi gertaera guztiak sinkronizatzeko.
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index 58d34a526ce0d34f33d1d3b7634f276f8fe507b5..0f4d31ef290ffe8a7bb6c221643781d5b1aafeb3 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -6,7 +6,6 @@
کتاب آدرس DAVx⁵
کتاب آدرس
راهنما
- مدیریت حسابها
اشتراک گذاری
خطایابی
پیام های مهم دیگر
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
index 0f8ef70117cf37242240c318654015a95ee3fa03..eea303afa2107c09bbf7af433dd6601c57b303c8 100644
--- a/app/src/main/res/values-fi/strings.xml
+++ b/app/src/main/res/values-fi/strings.xml
@@ -5,7 +5,6 @@
DAVx⁵ Osoitekirja
Osoitekirjat
Apua
- Hallitse tilejä
Debuggaus
Muut tärkeät viestit
Synkronointi
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 596f940407c38c91edad80941424f060e0d1f117..10f3c0075fede43f89e2c12bb511852e68297010 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -1,402 +1,285 @@
-
+
-
- DAVx⁵
- Le compte n’existe plus (désormais)
- Carnet d\'adresses DAVx⁵
- Carnets d\'adresses
- Ce champ est requis
- Aide
- Gestion des comptes
- Partager
- Base de données corrompue
- Tous les comptes ont été supprimés localement.
- Débogage
- Autres messages importants
- Messages d’état de faible priorité
- Synchronisation
- Erreurs de synchronisation
- Erreurs importantes qui bloquent la synchronisation, telles que des réponses inattendues du serveur
- Avertissements de synchronisation
- Problèmes de synchronisation non fatals tels que certains fichiers non valides
- Erreurs de réseau et d\'entrée / sortie
- Délais d\'attente, problèmes de connexion, etc. (souvent temporaires)
-
- Vos données, votre choix.
- Prenez le contrôle.
- Intervalles de synchronisation régulières
- Désactiver (non recommandé)
- Activé (recommandé)
- Pour une synchronisation à intervalles régulières, %s doit être autorisé à fonctionner en arrière-plan. Sinon, Android peut interrompre la synchronisation à tout moment.
- Je n\'ai pas besoin d\'intervalles de synchronisation régulières.*
- %s compatibilité
- Cet appareil bloque probablement la synchronisation. Si vous êtes affecté, vous ne pouvez résoudre ce problème que manuellement.
- J\'ai fait les réglages nécessaires. Ne me le rappelez plus.*
- * Laisser non coché pour un rappel ultérieur. Peut être réinitialisé dans les paramètres de l\'application / %s.
- Plus d\'informations
-
- Gestion des taches
- Si les tâches sont prises en charge par votre serveur, elles peuvent être synchronisées avec une application de tâches externe :
- OpenTasks
- d\'applications supplémentaires.]]>
- Taches
- ne sont pas (encore) prises en charge.]]>
- Pas de magasin d\'application disponible
- Je n\'ai pas besoin de support des tâches.*
- Logiciels open-source
- Nous sommes heureux que vous utilisiez %s, qui est un logiciel open-source. Le développement, la maintenance et l\'assistance sont un travail difficile. Veuillez envisager de contribuer (il y a plusieurs façons de le faire) ou de faire un don. Ce serait très apprécié !
- Comment contribuer/donner
- Ne plus afficher dans le futur
-
- Autorisations
- %s nécessite des autorisations pour fonctionner correctement.
- Tout autoriser
- A utiliser pour activer toutes les fonctionnalités (recommandé)
- Toutes les autorisations accordées
- Autorisations d\'accès aux contacts
- Pas de synchronisation du carnet d\'adresses (non recommandé)
- Synchronisation du carnet d\'adresses possible
- Autorisations du calendrier
- Pas de synchronisation du calendrier (non recommandé)
- Synchronisation du calendrier possible
- Autorisations d\'OpenTasks
- Autorisations de Tasks
- Pas de synchronisation des tâches (non installé)
- Aucune tâche de synchro
- Synchronisation des tâches possible
- Conserver les autorisations
- Les autorisations peuvent être réinitialisées automatiquement (non recommandé)
- Les autorisations ne seront pas réinitialisées automatiquement
- Cliquez sur Autorisations > décochez \"Supprimer les autorisations si l\'application n\'est pas utilisée\".
- Si un commutateur ne fonctionne pas, utiliser les paramètres de l\'application / Autorisations
- Paramètres de l\'application
-
- WiFi SSID autorisations
- Pour pouvoir accéder au nom du WiFi actuel (SSID), ces conditions doivent être remplies :
- Permission de localisation précise
- Autorisation de localisation accordée
- Autorisation de localisation refusée
- Autorisation de localisation en arrière-plan
- Autorisez tout le temps
- %s ]]>
- %s]]>
- %s utilise l\'autorisation de localisation uniquement pour déterminer le SSID du WiFi actuel pour les comptes à SSID restreint. Cela se produit même lorsque l\'application est en arrière-plan. Aucune donnée de localisation n\'est collectée, stockée, traitée ou envoyée nulle part.
- Localisation toujours activée
- Le service de localisation est activé
- Le service de localisation est désactivé
-
- Traductions
- Librairies
- Version %1$s (%2$d)
- Compilé sur %s
- © Ricki Hirner, Bernhard Stockmann (bitfire web engineering GmbH) et les contributeurs
- Cette version ne peut être distribuée que sur Google Play.
- Ce programme est fourni sans AUCUNE GARANTIE. C\'est un logiciel libre, et vous êtes en droit de le redistribuer sous certaines conditions.
- Merci à : %s]]>
-
- Impossible de créer le fichier journal
- Maintenant toutes les activités de %s seront enregistrées
- Voir/partager
- Désactiver
-
- Ouvrir le tiroir de navigation
- Fermer le tiroir de navigation
- Adaptateur de synchronisation CalDAV/CardDAV
- À propos / Licence
- Commentaire pour la version Beta
- Veuillez installer un client mail
- Veuillez installer un navigateur
- Paramètres
- Actualités & mises à jour
- Outils
- Liens externes
- Site Web
- Manuel
- Foire aux questions
- Communauté
- Faire un don
- Politique de confidentialité
- Pas de connectivité Internet. Android ne pourra pas exécuter la synchronisation.
- L\'espace de stockage est presque plein. Android ne lancera pas la synchronisation.
- Bienvenue sur DAVx⁵!\n\nVous pouvez maintenant ajouter un compte CalDAV ou CardDAV.
- La synchronisation automatique globale est désactivée
- Activer
- Synchroniser tous les comptes
-
- La détection du service a échoué
- Impossible d\'actualiser la liste de collection
-
-
- Fonctionne au premier plan
- Sur certains appareils, cela est nécessaire pour la synchronisation automatique.
-
- Paramètres
- Débogage
- Afficher les infos de débogage
- Voir/partager l\'application et les détails de configuration
- Journalisation verbeuse
- La journalisation est activée
- La journalisation est désactivée
- Optimisation de la batterie
- L\'App est dans la liste blanche (recommandé)
- L\'App n\'est pas dans la liste blanche (non recommandé)
- Garder au premier plan
- Peut aider si votre appareil empêche la synchronisation automatique
- Connexion
- Type de Proxy
- Nom de l\'hôte du proxy
- Port du proxy
- Sécurité
- Autorisations de l\'application
- Consulter les autorisations requises pour la synchronisation
- Révoquer les certificats du système
- Les certificats du système et ceux ajoutés par l\'utilisateur ne seront pas dignes de confiance
- Les certificats du système et ceux ajoutés par l\'utilisateur seront dignes de confiance (recommandé)
- Réinitialiser les certificats de (non)confiance
- Réinitialiser la confiance de tous les certificats personnalisés
- Tous les certificats personnalisés ont été effacés
- Interface utilisateur
- Paramètres de notification
- Gérer les canaux de notification et leurs paramètres
- Sélectionner un thème
-
- - Par défaut
- - Clair
- - Sombre
-
- Réinitialiser les astuces
- Réactiver les astuces qui ont été vues précédemment
- Toutes les astuces seront affichés à nouveau
- Intégration
- Applications de gestion de taches
- Synchronisation avec %s
- Aucune application de tâches compatibles trouvée
-
- Carnets d\'adresses
- Agendas
- WebCal
- Pas de synchronisation du carnet d\'adresses (autorisations manquantes)
- Pas de synchronisation du calendrier (autorisations manquantes)
- Pas de synchronisation des tâches (autorisations manquantes)
- Pas de synchronisation du calendrier et des tâches (autorisations manquantes)
- Impossible d\'accéder aux calendriers (autorisations manquantes)
- Autorisations
- Il n\'y a pas (encore) de carnet d\'adresses.
- Il n\'y a pas (encore) de calendriers.
- Il n\'y a pas (encore) d\'abonnement à des calendriers.
- Glisser vers le bas pour rafraîchir la liste à partir du serveur.
- Synchroniser maintenant
- Synchronisation en cours
- Paramètres du compte
- Renommer le compte
- Les données locales non enregistrées pourraient être perdues. Une re-synchronisation est nécessaire après avoir renommé le compte. Nouveau nom du compte :
- Renommer
- Impossible de renommer le compte
- Supprimer le compte
- Voulez-vous vraiment supprimer le compte?
- Toutes les copies locales des carnets d\'adresses, des calendriers et des listes de tâches seront supprimées.
- Synchronise cette collection
- En lecture seulement
- calendrier
- liste de tâche
- journal
- N\'afficher que les comptes perso.
- Actualiser la liste des carnets d\'adresses
- Créer un nouveau carnet d\'adresses
- Actualiser la liste des calendriers
- Créer un nouveau calendrier
- Aucune application compatible WebCal
- Installer ICSx⁵
-
- Ajouter un compte
- Connexion avec une adresse email
- Adresse mail
- Une adresse e-mail valide est requise
- Mot de passe
- Mot de passe requis
- Connexion avec une URL et un nom d\'utilisateur
- L\'URL doit commencer par http(s)://
- Nom d\'utilisateur
- Nom d\'utilisateur requis
- URL de base
- Se connecter avec l\'URL et le certificat client
- Choisir le certificat
- Se connecter
- Créer un compte
- Nom du compte
- L\'utilisation d\'apostrophes (\') est connue pour causer des problèmes sur certains appareils.
- Utilisez votre adresse e-mail comme nom de compte car Android utilisera ce nom en tant que champ ORGANISATEUR pour les événements que vous créerez. Vous ne pouvez pas avoir deux comptes avec le même nom.
- Méthode pour les contacts de type groupe :
- Nom du compte requis
- Le nom du compte est déjà pris
- Le compte n\'a pas pu être créé
- Connexion avancée (cas particuliers)
- Utiliser le nom d\'utilisateur/mot de passe
- Utiliser le certificat du client
- Aucun certificat trouvé
- Installer un certificat
- Détection de la configuration
- Veuillez patienter, nous interrogeons le serveur …
- Aucun accès possible au service CalDAV ou CardDAV.
- Nom d\'utilisateur (courriel) / mot de passe incorrect ?
- Afficher les détails
-
- Paramètres: %s
- Synchronisation
- Intervalle de synchronisation des carnets d\'adresses
- Manuellement
- Toutes les %d minutes et immédiatement après un changement local
- Intervalle de synchronisation des agendas
- Intervalle de synchronisation des tâches
-
- - Manuellement
- - Tous les quarts d\'heure
- - Toutes les demi-heures
- - Toutes les heures
- - Toutes les deux heures
- - Toutes les quatre heures
- - Une fois par jour
-
- Synchronisation en Wifi seulement
- La synchronisation est limitée aux connexions WiFi
- Le type de connexion n\'est pas pris en charge
- Restriction WiFi SSID
- Synchronisation possible seulement en %s
- Ne synchronise que sur %s (nécessite des services de localisation actifs)
- Toutes les connexions WiFi seront utilisées
- Liste des points d\'accès WiFi (SSID) autorisés, séparés par des virgules. (Laissez vide pour tous)
- La restriction du SSID WiFi nécessite des réglages supplémentaires
- Gérer
- Plus d\'informations (FAQ)
- Authentification
- Nom d\'utilisateur
- Saisissez votre nom d\'utilisateur :
- Mot de passe
- Mettre à jour le mot de passe
- Saisissez votre mot de passe :
- Alias du certificat client
- Aucun certificat sélectionné
- CalDAV
- Limite des événements passés
- Tous les événements seront synchronisés
-
- - Les événements de plus d’un jour passé seront ignorés
- - Les événements de plus de %d jours passés seront ignorés
- - Les événements de plus de %d jours passés seront ignorés
-
- Les événements antérieurs à ce nombre de jours seront ignorés (peut être 0). Laissez vide pour synchroniser tous les événements.
- Rappel par défaut
-
- - Rappel par défaut une minute avant l\'événement
- - Rappel par défaut %d minutes avant les événements
- - Rappel par défaut %d minutes avant les événements
-
- Aucun rappel par défaut
- Si des rappels par défaut doivent être créé pour des événements sans rappel: le nombre de minutes avant l\'événement. Laisser blanc pour désactiver les rappels par défaut.
- Choisir couleur du calendrier
- Les couleurs du calendrier sont réinitialisées à chaque synchronisation
- Les couleurs du calendrier peuvent être définies par d\'autres applications
- Couleur associée aux événements
- Les couleurs des événements sont synchronisées
- Les couleurs des événements sont pas synchronisées
- CardDAV
- Méthode pour les contacts de type groupe
-
- - Les groupes sont des VCards indépendantes
- - Les groupes sont des catégories pour chacun des contacts
-
- Changer la méthode de groupe
-
- Créer un carnet d\'adresses
- Mon carnet d\'adresses
- Créer un calendrier
- Fuseau horaire
- Entrées possibles de calendrier
- Événements
- Tâches
- Notes / journal
- Fusionner (événements et tâches)
- Couleur
- Création collection
- Titre
- Titre requis
- Description
- facultatif
- Emplacement de stockage
- Emplacement de stockage requis
- Créer
- Supprimer la collection
- Êtes-vous sur?
- Cette collection (%s) et toutes ses données seront supprimées définitivement.
- Ces données sont supprimées du serveur.
- Suppression de la collection
- Forcer la lecture seulement
- Propriétés
- Adresse (URL) :
- Copier l\'URL
- Propriétaire :
-
- Infos de débogage
- Archive ZIP
- Contient des informations de débogage et des journaux
- Partagez l’archive pour la transférer sur un ordinateur, pour l’envoyer par e-mail ou pour la joindre à un ticket de support.
- Partager l\'archive
- Informations de débogage jointes à ce message (nécessite une application compatible).
- Erreur HTTP
- Erreur Serveur
- Erreur WebDAV
- Erreur I/O
- La demande a été rejetée. Vérifiez les ressources impliquées et les informations de débogage pour plus de détails.
- La ressource demandée n\'existe pas (plus). Vérifiez les ressources concernées et les informations de débogage pour plus de détails.
- Un problème de serveur s\'est produit. Veuillez contacter le support de votre serveur.
- Une erreur inattendue s\'est produite. Voir les informations de débogage pour plus de détails.
- Voir les détails
- Les informations de débogage ont été collectées
- Ressources impliquées
- En rapport avec le problème
- Ressource à distance :
- Ressource local :
- Voir avec l\'application
- Journaux
- Des logs verbeux sont disponibles
- Voir les logs
-
- Une erreur est survenue.
- Une erreur HTTP est survenue.
- Une erreur I/O est survenue.
- Voir détails
-
- Synchronisation suspendue
- L\'espace de stockage est presque plein
-
- Quota utitlisé : %1$s / disponible : %2$s
- Partager le contenu
- Nom affiché
- URL WebDAV
- URL incorrecte
- Nom d\'utilisateur
- Mot de passe
- Ajouter un point de montage
- Aucun service WebDAV à cette URL
- Accès au fichier WebDAV
- Téléchargement du fichier WebDAV
- Téléversement du fichier WebDAV
-
- Autorisations DAVx⁵
- Autorisations supplémentaires demandées
- %s trop vieux
- Version minimale requise : %1$s
- Echec d\'authentification (contrôler vos identifiants de connexion)
- Erreur de réseau ou d\'entrée / sortie - %s
- Erreur de serveur HTTP - %s
- Erreur de stockage local - %s
- Essayez à nouveau
- Voir l\'élément
- Reçu un contact invalide du serveur
- Reçu un événement invalide du serveur
- Reçu une tâche invalide du serveur
- Ignorer une ou plusieurs ressources non valides
-
- DAVx⁵ : Sécurité de la connexion
- DAVx⁵ a rencontré un certificat inconnu. Voulez-vous lui faire confiance?
+
+ Gestionnaire de compte
+ Carnet d\'adresses Gestionnaire de compte
+ Carnets d\'adresses
+ Retirer
+ Annuler
+ Aide
+ Envoyer
+ Débogage
+ Autres messages importants
+ Syncronisation
+ Erreurs de synchronisation
+ Erreurs importantes qui bloquent la synchronisation, telles que des réponses inattendues du serveur
+ Avertissements de synchronisation
+ Problèmes de synchronisation non fatals tels que certains fichiers non valides
+ Erreurs de réseau et d\'entrée / sortie
+ Délais d\'attente, problèmes de connexion, etc. (souvent temporaires)
+
+ Synchronisation automatique
+ %s le matériel bloque souvent la synchronisation automatique. Dans ce cas, autorisez la synchronisation automatique dans vos paramètres d\'Android.
+ Synchronisation planifiée
+ Votre appareil va restreindre la synchronisation de Gestionnaire de compte. Pour forcer des intervalles de synchronisation Gestionnaire de compte plus réguliers, enlever l\'option \"optimisation de batterie\".
+ Désactiver pour Gestionnaire de compte
+ Ne plus afficher
+ Pas maintenant
+ Open-Source Information
+ Nous sommes heureux que vous utilisiez Gestionnaire de compte, qui est un logiciel open-source (GPLv3). Parce que développer Gestionnaire de compte est un travail difficile, qui nous a pris de nombreuses heures, nous vous invitons à faire un don.
+ Faire un don
+ Plus tard
+ Plus d\'informations
+ L\'application OpenTasks n\'est pas installée
+ Pour synchroniser les tâches, l\'application gratuite OpenTasks est nécessaire. (Elle ne l\'est pas pour les contacts et les événements.)
+ Après l\'installation d\'OpenTasks, vous devez RE-INSTALLER Gestionnaire de compte et ajouter vos comptes à nouveau (bug Android).
+ Installer OpenTasks
+
+ Librairies
+ Version %1$s (%2$d)
+ Compilé sur %s
+ Cette version ne peut être distribuée que sur Google Play.
+ Ce programme est fourni sans AUCUNE GARANTIE. C\'est un logiciel libre, et vous êtes en droit de le redistribuer sous certaines conditions.
+
+ Impossible de créer le fichier journal
+ Journalisation de Gestionnaire de compte
+ Envoyer le journal
+
+ Ouvrir le volet de navigation
+ Fermer le volet de navigation
+ Adaptateur de synchronisation CalDAV/CardDAV
+ À propos / Licence
+ Commentaire pour la version Beta
+ Paramètres
+ Actualités & mises à jour
+ Liens externes
+ Site Web
+ Manuel
+ Foire aux questions
+ Aide/Forum
+ Faire un don
+ Pas de connectivité Internet. Android ne pourra pas exécuter la synchronisation.
+ Bienvenue sur Gestionnaire de compte !
+\n
+\nVous pouvez maintenant ajouter un compte CalDAV ou CardDAV.
+ La synchronisation automatique globale est désactivée
+ Activer
+
+ La détection du service a échoué
+ Impossible d\'actualiser la liste de collection
+
+ Paramètres
+ Débogage
+ Afficher les infos de débogage
+ Voir/partager l\'application et les détails de configuration
+ Journalisation verbeuse
+ La journalisation est activée
+ La journalisation est désactivée
+ Connexion
+ Ignorer les paramètres proxy
+ Utiliser des paramètres proxy personnalisés
+ Utiliser les paramètres proxy du système
+ Nom de l\'hôte du proxy HTTP
+ Port du proxy HTTP
+ Sécurité
+ Révoquer les certificats du système
+ Les certificats du système et ceux ajoutés par l\'utilisateur ne seront pas dignes de confiance
+ Les certificats du système et ceux ajoutés par l\'utilisateur seront dignes de confiance (recommandé)
+ Réinitialiser les certificats de (non)confiance
+ Réinitialiser la confiance de tous les certificats personnalisés
+ Tous les certificats personnalisés ont été effacés
+ Interface utilisateur
+ Paramètres de notification
+ Gérer les canaux de notification et leurs paramètres
+ Réinitialiser les astuces
+ Réactiver les astuces qui ont été vues précédemment
+ Toutes les astuces seront affichés à nouveau
+
+ CardDAV (les carnets d\'adresse)
+ CalDAV (les agendas)
+ WebCal (les anciens agenda)
+ Il n\'y a pas (encore) de carnet d\'adresses.
+ Il n\'y a pas (encore) de calendriers.
+ Il n\'y a pas (encore) d\'abonnement à des calendriers.
+ Glisser vers le bas pour rafraîchir la liste à partir du serveur.
+ Synchroniser maintenant
+ Synchronisation en cours
+ Paramètres du compte
+ Renommer le compte
+ Les données locales non enregistrées pourraient être perdues. Une re-synchronisation est nécessaire après avoir renommé le compte. Nouveau nom du compte :
+ Renommer
+ Supprimer le compte
+ Voulez-vous vraiment supprimer le compte \?
+ Toutes les copies locales des carnets d\'adresses, des calendriers et des listes de tâches seront supprimées.
+ synchronise cette collection
+ En lecture seulement
+ calendrier
+ liste de tâche
+ Actualiser la liste des carnets d\'adresses
+ Créer un nouveau carnet d\'adresses
+ Actualiser la liste des calendriers
+ Créer un nouveau calendrier
+ Aucune application compatible WebCal
+ Installer ICSx⁵
+
+ Ajouter un compte
+ Connexion avec une adresse email
+ Adresse mail
+ Une adresse e-mail valide est requise
+ Mot de passe
+ Mot de passe requis
+ Connexion avec une URL et un nom d\'utilisateur
+ L\'URL doit commencer par http(s)://
+ L\'URL doit commencer par https://
+ Nom d\'hôte requis
+ Nom d\'utilisateur
+ Nom d\'utilisateur requis
+ URL de base
+ Se connecter avec l\'URL et le certificat client
+ Choisir le certificat
+ Se connecter
+ Retour
+ Ajouter un compte
+ Nom du compte
+ Utilisez votre adresse e-mail comme nom de compte car Android utilisera ce nom en tant que champ ORGANISATEUR pour les événements que vous créerez. Vous ne pouvez pas avoir deux comptes avec le même nom.
+ Méthode pour les contacts de type groupe :
+ Nom du compte requis
+ Le nom du compte est déjà pris
+ Le compte n\'a pas pu être créé
+ Détection de la configuration
+ Veuillez patienter, nous interrogeons le serveur …
+ Aucun accès possible au service CalDAV ou CardDAV.
+ Montrer les détails
+
+ Paramètres : %s
+ Synchronisation
+ Intervalle de synchronisation des carnets d\'adresses
+ Manuellement
+ Toutes les %d minutes et immédiatement après un changement local
+ Intervalle de synchronisation des agendas
+ Intervalle de synchronisation des tâches
+
+ - Manuellement
+ - Toutes les 2 minutes
+ - Tous les quarts d\'heure
+ - Toutes les demi-heures
+ - Toutes les heures
+ - Toutes les deux heures
+ - Toutes les quatre heures
+ - Une fois par jour
+
+ Synchronisation en Wifi seulement
+ La synchronisation est limitée aux connexions WiFi
+ Le type de connexion n\'est pas pris en charge
+ Restriction WiFi SSID
+ Synchronisation possible seulement en %s
+ Ne synchronise que sur %s (nécessite des services de localisation actifs)
+ Toutes les connexions WiFi seront utilisées
+ Liste des points d\'accès WiFi (SSID) autorisés, séparés par des virgules. (Laissez vide pour tous)
+ Pour lire les noms WiFi, l\'autorisation « Position » et les services de localisation activés en permanence sont nécessaires.
+ Plus d\'informations (FAQ)
+ Authentification
+ Nom d\'utilisateur
+ Saisissez votre nom d\'utilisateur :
+ Mot de passe
+ Mettez à jour le mot de passe en fonction de votre serveur.
+ Saisissez votre mot de passe :
+ Alias du certificat client
+ CalDAV
+ Limite des événements passés
+ Tous les événements seront synchronisés
+
+ - Les événements de plus d’un jour passé seront ignorés
+ - Les événements de plus de %d jours passés seront ignorés
+
+ Les événements antérieurs à ce nombre de jours seront ignorés (peut être 0). Laissez vide pour synchroniser tous les événements.
+ Choisir couleur du calendrier
+ Les couleurs de calendrier sont gérées par Gestionnaire de compte
+ Les couleurs de calendrier ne sont pas gérées par Gestionnaire de compte
+ Couleur associée aux événements
+ Synchroniser la couleur associée aux événements
+ Ne pas synchroniser la couleur associée aux événements
+ CardDAV
+ Méthode pour les contacts de type groupe
+ Changer la méthode de groupe
+
+ Créer un carnet d\'adresses
+ Mon carnet d\'adresses
+ Créer un calendrier
+ Fuseau horaire
+ Fuseau horaire requis
+ Entrées possibles de calendrier
+ Événements
+ Tâches
+ Notes / journal
+ Fusionner (événements et tâches)
+ Couleur
+ Création collection
+ Titre
+ Titre requis
+ Description
+ facultatif
+ Emplacement de stockage
+ Créer
+ Supprimer la collection
+ Êtes-vous sur \?
+ Cette collection (%s) et toutes ses données seront supprimées définitivement.
+ Ces données sont supprimées du serveur.
+ Suppression de la collection
+ Forcer la lecture seulement
+ Propriétés
+ Adresse (URL) :
+ Copier l\'URL
+
+ Une erreur est survenue.
+ Une erreur HTTP est survenue.
+ Une erreur I/O est survenue.
+ Voir détails
+
+ Infos de débogage
+ Les logs seront joints à ce message (nécessite la prise en charge de pièce jointe par l\'application destinataire).
+ Carnet d\'adresse en lecture seulement
+ Autorisations Gestionnaire de compte
+ Autorisations supplémentaires demandées
+ Version d\'OpenTask trop ancienne
+ Version requise %1$s (actuellement %2$s)
+ Echec d\'authentification (contrôler vos identifiants de connexion)
+ Erreur de réseau ou d\'entrée / sortie - %s
+ Erreur de serveur HTTP - %s
+ Erreur de stockage local - %s
+ Essayez à nouveau
+ Voir l\'élément
+ Reçu un contact invalide du serveur
+ Reçu un événement invalide du serveur
+ Reçu une tâche invalide du serveur
+ Ignorer une ou plusieurs ressources non valides
+
+ Gestionnaire de compte : Sécurité de la connexion
+ Gestionnaire de compte a rencontré un certificat inconnu. Voulez-vous lui faire confiance \?
+ /e/ déclarera un faux modèle d\'appareil à Google afin de protéger votre vie privée.
+\nVous pouvez vérifier lequel sur l\'Activité des appareils de Google après vous être connecté.
+ AVERTISSEMENT
+ Si des rappels par défaut sont créés pour les événements sans rappel : le nombre de minutes souhaité avant l\'événement. Laissez vide pour désactiver les rappels par défaut.
+ Aucun rappel par défaut n\'est créé
+
+ - Rappel par défaut une minute avant l\'événement
+ - Rappel par défaut %d minutes avant l\'événement
+
+ Rappel par défaut
+ Politique de confidentialité
+ Veuillez installer un navigateur Web
+ Veuillez installer un client de courriel
+ /e/
+ Mettre à jour le nom d\'utilisateur et le mot de passe
+ Informations d\'identification
+ Utiliser un serveur spécifique
+ Adresse URL de serveur valide requise
+ URL du serveur (https://url_serveur)
+ Utiliser un serveur personnalisé
+ Se connecter avec un compte /e/
+ Identifiants, fréquence de synchronisation, etc.
+ Carnet d\'adresses Google
+ Carnet d\'adresses /e/
+ Google
+ WebDAV
diff --git a/app/src/main/res/values-gd/strings.xml b/app/src/main/res/values-gd/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..583c8bc50c41e63c13e04642b66ca769ad81a448
--- /dev/null
+++ b/app/src/main/res/values-gd/strings.xml
@@ -0,0 +1,262 @@
+
+
+ Facal-faire
+ Tiotal
+ A’ cruthachadh cruinneachadh
+ Dath
+ Co-mheasgaichte (tachartasan is saothraichean)
+ Notaichean / leabhar-latha
+ Saothraichean
+ Tachartasan
+ Nithean a ghabhas cur ris a’ mhìosachan
+ Tha feum air roinn-tìde
+ Roinn-tìde
+ Cruthaich mìosachan
+ Leabhar nan seòladh agam
+ Cruthaich leabhar sheòlaidhean
+ Atharraich dòigh a’ bhuidhinn
+ Dòigh conaltradh a’ bhuidhinn
+ Luchd-aithne
+ Na sioncronaich dathan nan tachartasan
+ Sioncronaich dathan nan tachartasan
+ Taic ri dathan thachartasan
+ Chan eil dathan a’ mhìosachain ’gan suidheachadh le manaidsear nan cunntas
+ Tha dathan a’ mhìosachain ’gan stiùireadh le manaidsear nan cunntas
+ Stiùirich dathan a’ mhìosachain
+ Ma thèid cuimhneachain bhunaiteach a chruthachadh do thachartasan gun chuimhneachan: an àireamh de mhionaidean ron tachartas a thogras tu. Fàg bàn e airson na cuimhneachain bhunaiteach a chur à comas.
+ Cha dèid cuimhneachain bhunaiteach a chruthachadh
+
+ - Cuimhneachan bunaiteach %d mhionaid ron tachartas
+ - Cuimhneachan bunaiteach %d mhionaid ron tachartas
+ - Cuimhneachan bunaiteach %d mionaidean ron tachartas
+ - Cuimhneachan bunaiteach %d mionaid ron tachartas
+
+ Cuimhneachan bunaiteach
+ Thèid tachartasan a tha nas sine na an àireamh seo de làithean a leigeil seachad (faodaidh tu 0 a chleachdadh). Fàg bàn e airson a h-uile tachartas a shioncronachadh.
+
+ - Thèid tachartasan nas sine %d na latha a leigeil seachad
+ - Thèid tachartasan nas sine %d na latha a leigeil seachad
+ - Thèid tachartasan nas sine %d na làithean a leigeil seachad
+ - Thèid tachartasan nas sine %d na latha a leigeil seachad
+
+ Thèid gach tachartas a shioncronachadh
+ Crìoch-ama nan seann-tachartasan
+ Mìosachan
+ Alias teisteanas a’ chliant
+ Cuir a-steach am facal-faire agad:
+ Ùraich am facal-faire a-rèir an fhrithealaiche agad.
+ Cuir a-steach ainm-cleachdaiche:
+ Ùraich an t-ainm-cleachdaiche ’s am facal-faire
+ Teisteasan
+ Ainm-cleachdaiche
+ Dearbhadh
+ Barrachd fiosrachaidh (CÀBHA)
+ Airson na h-ainmean WiFi a leughadh, bidh feum air cead ionaid agus air seirbheisean ionaid a bhios air fad an t-siubhail.
+ Ainmean (SSIDs) sgaraichte le cromagan air na lìonraidhean WiFi a tha ceadaichte (fàg bàn airson ceangal sam bith a chleachdadh)
+ Thèid ceangal WiFi sam bith a chleachdadh
+ Cha dèid a shioncronachadh ach thar %s (bi feum air seirbheisean ionaid gnìomhach)
+ Cha dèid a shioncronachadh ach thar %s
+ Cuingeachadh SSID WiFi
+ Cha doirear an aire air seòrsa a’ cheangail
+ Tha an sioncronachadh cuingichte air ceanglaichean WiFi
+ Na sioncronaich ach thar WiFi
+ Tricead sioncronachadh nan saothraichean
+ Tricead sioncronachadh nam mìosachan
+ Gach %d mionaid ⁊ sa bhad às dèidh atharrachadh ionadail
+ A làimh a-mhàin
+ Tricead sioncronachadh an luchd-aithne
+ Sioncronachadh
+ Roghainnean: %s
+ Cleachd frithealaiche sònraichte
+ Tha feum air seòladh URL frithealaiche dligheach
+ URL an fhrithealaiche (https://url_an_fhrithealaiche)
+ Cleachd frithealaichte gnàthaichte
+ Seall mion-fhiosrachadh
+ Dh’fhàillig leis a’ chlàradh a-steach. Thoir sùil air an ainm-chleachdaiche is fhacal-fhaire agad.
+ Fuirich ort, a’ cur a’ chunntais ris…
+ Cuir cunntas ris
+ Tha cunntas air a bheil an t-ainm seo ann mu thràth
+ Tha ainm a’ chunntais ’ga chleachdadh mu thràth
+ Tha ainm cunntais riatanach
+ Dòigh conaltradh a’ bhuidhinn:
+ Cleachd an seòladh puist-d agad mar ainm a’ chunntais on a chleachdas Android ainm a’ chunntais dan raon an EAGRAICHE air na tachartasan a chruthaicheas tu. Chan fhaod dà chunntas leis an aon ainm a bhith agad.
+ Ainm a’ chunntais
+ Cuir cunntas ris
+ Air ais
+ Clàraich a-steach
+ Tagh teisteanas
+ Clàraich a-steach le URL is teisteanas cliant
+ URL bunaiteach
+ Tha feum air ainm-cleachdaiche
+ Ainm-cleachdaiche
+ Tha feum air ainm òstair
+ Feumaidh an URL a thòiseachadh le https://
+ Feumaidh an URL a thòiseachadh le http(s)://
+ Clàraich a-steach le URL is ainm-cleachdaiche
+ Tha feum air facal-faire
+ Facal-faire
+ Tha feum air seòladh puist-d dligheach
+ Seòladh puist-d
+ Clàraich a-steach le seòladh puist-d
+ Clàraich a-steach le cunntas /e/
+ Cuir cunntas ris
+ Stàlaich ICSx⁵
+ Cha deach aplacaid le comas Webcal a lorg
+ Cruthaich mìosachan ùr
+ Ath-nuadhaich liosta nam mìosachan
+ Cruthaich leabhar sheòlaidhean ùr
+ Ath-nuadhaich liosta nan leabhraichean sheòlaidhean
+ liosta shaothraichean
+ mìosachan
+ ri leughadh a-mhàin
+ sioncronaich an cruinneachadh seo
+ Thèid gach lethbhreac ionadail de leabhraichean sheòlaidhean, mìosachain is liostaichean de shaothraichean a sguabadh às.
+ A bheil thu cinnteach gu bheil thu airson an cunntas a sguabadh às\?
+ Sguab às an cunntas
+ Thoir ainm ùr air
+ Dh’fhaoidte gun dèid dàta ionadail nach deach a shàbhaladh a leigeil seachad. Bidh feum air ath-shioncronachadh ’na dhèidh. Ainm ùr a’ chunntais:
+ Thoir ainm ùr air a’ chunntas
+ Roghainnean a’ chunntais
+ ’Ga shioncronachadh
+ Sioncronaich an-dràsta
+ Grad-shlaighd sìos a dh’ath-nuadhachadh na liosta on fhrithealaiche.
+ Chan eil fo-sgrìobhadh air mìosachan ann (fhathast).
+ Chan eil mìosachan ann (fhathast).
+ Chan eil leabhar sheòlaidhean ann (fhathast).
+ Webcal
+ Mìosachan
+ Luchd-aithne
+ Thèid gach leth-fhacal a shealltainn a-rithist
+ Cuiridh seo na leth-fhaclan a chaidh a leigeil seachad an comas a-rithist
+ Ath-shuidhich na leth-fhaclan
+ Stiùirich seanailean nam brathan ’s na roghainnean aca
+ Roghainnean nam brathan
+ Eadar-aghaidh a’ chleachdaiche
+ Chaidh gach teisteanas gnàthaichte fhalamhachadh
+ Ath-shuidhich earbsa nan teisteanasan gnàthaichte uile
+ Ath-shuidhich (neo-)earbsachd nan teisteanasan
+ Cuir earbsa ann an ùghdarrasan theisteanasan an t-siostaim no a chaidh a chur ris le cleachdaiche (mholamaid seo)
+ Na cuir earbsa ann an ùghdarrasan theisteanasan an t-siostaim no a chaidh a chur ris le cleachdaiche
+ Na cuir earbsa ann an teisteanasan an t-siostaim
+ Tèarainteachd
+ Port progsaidh HTTP
+ Ainm òstair progsaidh HTTP
+ Cleachd roghainnean progsaidh bunaiteach an t-siostaim
+ Cleachd roghainnean progsaidh gnàthaichte
+ Tar-àithn roghainnean a’ phrogsaidh
+ Ceangal
+ Tha an logadh à comas
+ Tha an logadh gnìomhach
+ Logadh briathrach
+ Seall/Co-roinn fiosrachadh mun bhathar-bhog ’s mun rèiteachadh agad
+ Seall fiosrachadh dì-bhugachaidh
+ Dì-bhugachadh
+ Roghainnean
+ Cha b’ urrainn dhuinn liosta nan cruinneachaidhean ath-nuadhachadh
+ Cha do mhothaich sinn do sheirbheis
+ Cuir an comas
+ Chaidh an sioncronachadh fèin-obrachail air feadh an t-siostaim a chur à comas
+ Fàilte gu manaidsear nan cunntas!
+\n
+\n’S urrainn dhut cunntas airson miosachain/luchd-aithne a chur ris a-nis.
+ Chan eil ceangal ris an eadar-lìon. Cha ruith Android an sioncronachadh.
+ Poileasaidh prìobhaideachd
+ Thoir tabhartas dhuinn
+ Cobhair / Bòrd-brath
+ CÀBHA
+ Leabhar-mìneachaidh
+ Làrach-lìn
+ Ceanglaichean ris an taobh a-muigh
+ Naidheachdan ⁊ ùrachaidhean
+ Roghainnean
+ Stàlaich brabhsair-lìn
+ Stàlaich cliant puist-d
+ Beachan thugainn mun tionndadh beta
+ Mu dhèidhinn / Ceadachas
+ Adaptar sioncronachadh nam mìoachan/nan cunntasan
+ Dùin drathair na seòladaireachd
+ Fosgail drathair na seòladaireachd
+ Cuir loga
+ Logadh manaidsear nan cunntas
+ Cha b’ urrainn dhuinn faidhle an loga a chruthachadh
+ Fhuair thu am prògram seo GUN BHARANTAS SAM BITH. ’S e bathar-bog saor a th’ ann agus faodaidh tu ath-sgaoileadh ma thogras tu fo chumhan sònraichte.
+ Chan fhaodar an tionndadh seo dheth a sgaoileadh ach le Google Play.
+ Chaidh a thrusadh %s
+ Tionndadh %1$s (%2$d)
+ Leabhar-lannan
+ Stàlaich OpenTasks
+ Nuair a bhios tu air OpenTasks a stàladh, feumaidh tu manaidsear nan cunntas ATH-STÀLADH ’s na cunntasan agad a chur ris a-rithist (seo buga Android).
+ Airson saothraichean a shioncronachadh, feumaidh sinn aplacaid shaor OpenTasks. (Chan eil seo riatanach airson an luchd-aithne no na tachartasan.)
+ Cha deach OpenTasks a stàladh
+ Barrachd fiosrachaidh
+ Uaireigin eile ’s dòcha
+ Seall duilleag nan tabhartasan
+ Tha sinn toilichte gu bheil thu a’ cleachdadh manaidsear nan cunntas a tha ’na bhathar-bog le bun-tùs fosgailte (GPLv3). Air sgàth ’s gur e obair chruaidh a th’ ann an leasachadh manaidsear nan cunntas is gun dug e mìltean de dh’uairean-obrach, saoil an doir thu tabhartas dhuinn\?
+ Fiosrachadh mun bhun-tùs fhosgailte
+ Chan ann an-dràsta
+ Na seall seo a-rithist
+ Cuir dheth airson manaidsear nan cunntas
+ Cuingichidh an t-uidheam agad an sioncronachadh a nì manaidsear nan cunntas. Airson sioncronachadh cunbhalach le manaidsear nan cunntas a sparradh air, cuir dheth “Piseachadh a’ bhataraidh”.
+ Sioncronachadh sgeidealaichte
+ Bacaidh bathar-an-sàs %s an sioncronachadh fèin-obrachail u tric. Ma thachras seo, ceadaich sioncronachadh fèin-obrachail ann an roghainnean Android.
+ Sioncronachadh fèin-obrachail
+ Crìochan-ùine, duilgheadasan leis a’ cheangal is msaa. (sealach mar as trice)
+ Mearachdan lìonraidh is ion/às-chuir
+ Duilgheadasan leis an t-sioncronachadh nach eil èiginneach, can corra faidhle mì-dhligheach
+ Rabhaidhean sioncronachaidh
+ Mearachdan cudromach a chuireas stad air an t-sioncronachadh, can freagairt on fhrithealaiche ris nach robh dùil
+ Mearachdan sioncronachaidh
+ Sioncronachadh
+ Teachdaireachdan cudromach eile
+ Dì-bhugachadh
+ Cuir
+ Teisteas, tricead an t-sioncronachaidh is msaa.
+ Leabhraichean nan seòladh
+ Leabhar sheòlaidhean Google
+ Leabhar sheòlaidhean /e/
+ Leabhar sheòlaidhean WebDav
+ /e/
+ Google
+ WebDAV
+ Manaidsear nan cunntas
+ Nì /e/ aithriseadh le modail uidheim brèige gu Google airson do phrìobhaideachd a dhìon.
+\n’S urrainn dhut sùil a thoirt air dè th’ ann air “Gnìomhachd an uidheim” Google às dèidh do chlàradh a-steach.
+ RABHADH
+ Thachair manaidsear nan cunntas ri teisteanas nach aithne dhuinn. A bheil thu airson earbsa a chur ann\?
+ Manaidsear nan cunntas: Tèarainteachd a’ cheangail
+ A’ leigeil seachad goireas mì-dhligheach no dhà
+ Fhuair sinn saothair mhì-dhligheach on fhrithealaiche
+ Fhuair sinn tachartas mì-dhligheach on fhrithealaiche
+ Fhuair sinn neach-aithne mì-dhligheach on fhrithealaiche
+ Seall an nì
+ Feuch ris a-rithist
+ Mearachd an stòrais ionadail – %s
+ Mearachd an fhrithealaiche HTTP – %s
+ Mearachdan lìonraidh no ion/às-chuir – %s
+ Dh’fhàillig an dearbhadh (thoir sùil air an teisteas clàraidh a-steach)
+ An tionndadh riatanach: %1$s (tha %2$s agad)
+ Tha OpenTasks ro shean
+ Tha feum air ceadan a bharrachd
+ Ceadan manaidsear nan cunntas
+ Leabhar sheòlaidhean ri leughadh a-mhàin
+ Thèid logaichean a cheangal ris an teachdaireachd seo (bi feum air taic ri ceanglachain san aplacaid a gheibh iad).
+ Fiosrachadh dì-bhugachaidh
+ Seall mion-fhiosrachadh
+ Thachair mearachd ion/às-chur.
+ Thachair mearachd HTTP.
+ Thachair mearachd.
+ Dèan lethbhreac dhen URL
+ Seòladh (URL):
+ Roghainnean
+ Èignich gu bheil e ri leughadh a-mhàin
+ A’ sguabadh às a’ chruinneachaidh
+ Thèid an dàta seo a sguabadh às on fhrithealaiche.
+ Thèid an cruinneachadh seo (%s) agus an dàta gu lèir aige a sguabadh às.
+ A bheil thu cinnteach\?
+ Sguab an cruinneachadh às
+ Cruthaich
+ Ionad an stòrais
+ roghainneil
+ Tuairisgeul
+ Tha feum air tiotal
+
\ No newline at end of file
diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml
index 2b8556aa62ff90c5630d0a78830e0334956848d8..660d0289c4b3656b948689b594e15c1f4e95cac4 100644
--- a/app/src/main/res/values-gl/strings.xml
+++ b/app/src/main/res/values-gl/strings.xml
@@ -1,419 +1,283 @@
-
+
-
- DAVx⁵
- A conta non existe (definitivamente)
- DAVx⁵ libreta de enderezos
- Libretas de enderezos
- Este campo é requerido
- Axuda
- Xestionar contas
- Compartir
- Base de datos estragada
- Foron eliminadas tódalas contas locais
- Depurando
- Outras mensaxes importantes
- Mensaxes de estado de baixa prioridade
- Sincronización
- Fallos na sincronización
- Erros importantes como respostas non agardadas do servidor que deteñen a sincronización
- Avisos sobre a sincronización
- Problemas non-fatais de sincronización como certos ficheiros non válidos
- Fallos de rede e I/O
- Caducidades, problemas de conexión, etc. (soen ser temporais)
-
- Os teus datos. Ti elixes.
- Toma o control.
- Intervalos regulares de sincronización
- Desactivado (non recomendado)
- Activado (recomendado)
- Para sincronizar a intervalos regulares, %s debe ter permiso para executarse en segundo plano. Se non, Android podería deter a sincronización.
- Non preciso sincr. con regularidade.*
- Compatibilidade de %s
- Este dispositivo probablemente está a bloquear a sincronización. Esto só se pode solucionar de xeito manual.
- Xa fixen o que me pediades. Non mo lembres máis.*
- * Deixar sen marcar para lembrar máis tarde. Pode restablecerse nos axustes da app / %s.
- Máis información
- jtx Board
-
- Soporte para Tasks
- Se as tarefas están soportadas polo teu servidor, poden ser sincronizadas cunha app que soporte tarefas:
- OpenTasks
- apps adicionais.]]>
- Tarefas
- non están soportadas (aínda).]]>
- Sen tenda de apps dispoñible
- Non necesito soporte para tarefas.*
- Software de código aberto
- Encántanos que uses %s, que é software de código aberto. O desenvolvemento, mantemento e soporte son un traballo difícil. Considera colaborar (hai moitos xeitos) ou facer unha doazón. Sería de agradecer!
- Como contribuír/doar
- Non mostrar no futuro próximo
-
- Permisos
- %s require permisos para funcionar axeitadamente.
- Todos os de abaixo
- Usa isto para habilitar tódalas características (recomendado)
- Todos os permisos concedidos
- Permisos de contactos
- Sen sincronización de contactos (non recomendado)
- É posible sincronizar os contactos
- Permisos de calendario
- Sen sincronización de calendario (non se recomenda)
- É posible sincronizar o calendario
- permisos para jtx Board
- Sen sincr. de tarefas, diarios e notas (non instalado)
- Sen sincr. de tarefas, diarios, notas
- Dispoñible sincr. de tarefas, diarios e notas
- Permisos para OpenTasks
- Permisos para Tasks
- Sen sincronización de tarefas (non instalado)
- Tarefas non sincr.
- É posible sincronizar as tarefas
- Manter permisos
- Os permisos poden restablecerse automáticamente (non recomendado)
- Os permisos non se restablecerán automáticamente
- Preme en Permisos > desmarca \"Eliminar permisos se a app non se usa\"
- Se unha opción non funciona, usa axustes da aplicación / Permisos.
- Permisos da aplicación
-
- Permisos WiFi SSID
- Para poder acceder á WiFi (SSID) actual, deben darse estas condicións:
- Permiso para localización precisa
- Permiso de localización outorgado
- Permiso de localización denegado
- Permiso de localización en segundo plano
- Permitir en todo momento
- %s]]>
- %s]]>
- %s utiliza o permiso de Localización só para determinar o SSID da WiFi para contas restrinxidas a uns SSIDs. Esto acontecerá incluso cando a app está en segundo plano. Non se recollen datos de localización, nin se gardan, procesan ou envían a ningún sitio.
- Localización sempre activada
- Servizo de localización activado
- Servizo de localización desactivado
-
- Traducións
- Bibliotecas
- Versión %1$s (%2$d)
- Compilada en %s
- © Ricki Hirner, Bernhard Stockmann (bitfire web engineering GmbH) e colaboradoras
- Esta versión só está dispoñible para distribución en Google Play.
- Este programa non proporciona NINGUNHA GARANTÍA. É software libre, e convidámoste a redistribuílo baixo certas condicións.
- Grazas a: %s]]>
-
- Non se creou ficheiro de rexistro
- Rexistrando todas as %s actividades
- Ver/compartir
- Desactivar
-
- Abrir cadro de navegación
- Pechar cadro de navegación
- Adaptador de sincr. CalDAV/CardDAV
- Acerca de / Licenza
- Comenta sobre a Beta
- Instala un cliente de email
- Instala un navegador web
- Axustes
- Novas & actualizacións
- Ferramentas
- Ligazóns externas
- Sitio web
- Manual
- PMF
- Comunidade
- Doar
- Política de Privacidade
- Sen conexión a internet. Android non sincronizará.
- Queda pouco espazo, Android non executará a sincronización.
- Benvida a DAVx⁵!\n\nXa podes engadir unha conta CalDAV/CardDAV
- A sincronización global automática do sistema está desactivada
- Activar
- Sincroniza todas as contas
-
- Fallou a detección do servizo
- Non se actualizou a lista da colección
-
- Non pode executarse en segundo plano
- Require ter permiso para optimizacións de batería
-
- A funcionar en primeiro plano
- En algúns dispositivos esto é necesario para a sincronización automática.
-
- Axustes
- Depurando
- Mostrar info de depuración
- Ver/compartir detalles do software e configuración
- Rexistro polo miúdo
- O rexistro está activo
- O rexistro está desactivado
- Optimización da batería
- App está permitida (recomendado)
- App sen permiso (non recomendado)
- Manter en primeiro plano
- Podería ser útil se o dispositivo dificulta a sincronización automática
- Conexión
- Tipo de Proxy
-
- - Por defecto no sistema
- - Sen proxy
- - HTTP
- - SOCKS (para Orbot)
-
- Servidor do proxy
- Porto do proxy
- Seguridade
- Permisos da App
- Revisa os permisos requeridos para a sincronización
- Non confiar en certificados do sistema
- Non se confiará nos CAs do sistema ou engadidos por usuaria
- Confiarase nos CAs do sistema e engadidos por usuaria (recomendado)
- Restablecer certificados repudiados
- Restablece a confianza en todos os certificados personalizados
- Todos os certificados personalizados foron admitidos
- Interface de usuaria
- Axustes das notificacións
- Xestiona as canles de notificación e os seus axustes
- Elixe decorado
-
- - Por defecto no sistema
- - Claro
- - Escuro
-
- Restablecer consellos
- Restablece todos os consellos que foran desbotados anteriormente
- Mostraranse todos os consellos de novo
- Integración
- App Tarefas
- Sincronizando con %s
- Non se atopan app de tarefas compatible
-
- CardDAV
- CalDAV
- Webcal
- Sen sincronización de contactos (faltan permisos)
- Sen sincronización de calendario (faltan permisos)
- Sen sincronización de tarefas (faltan permisos)
- Sen sincronización de calendario e tarefas (faltan permisos)
- Non se pode acceder aos calendarios (faltan permisos)
- Permisos
- No existen libretas de enderezos (aínda).
- Non existen calendarios (aínda).
- Non tes subscricións a calendario (aínda).
- Arrastra hacia abaixo para actualizar a lista desde o servidor.
- Sincronizar agora
- Sincronizando
- Axustes da conta
- Renomear conta
- Os datos locais non gardados perderanse. A resincronización é precisa tras renomear. Novo nome da conta:
- Renomear
- Non cambiou o nome da conta
- Eliminar conta
- Desexas eliminar a conta?
- Todas as copias locais de libretas de enderezos, calendarios e tarefas eliminaranse.
- sincronizar esta colección
- só lectura
- calendario
- lista de tarefas
- diario
- Mostrar só personal
- Actualizar lista de libreta de enderezos
- Crear nova libreta de enderezos
- Actualizar lista de calendario
- Crear novo calendario
- Non se atopou app para Webcal
- Instalar ICSx⁵
-
- Engadir conta
- Conectar con enderezo de correo-e
- Enderezo de correo-e
- Requíre un enderezo de correo válido
- Contrasinal
- Require contrasinal
- Conectar con URL e nome de usuaria
- URL debe comezar con http(s)://
- Nome de usuaria
- Require nome de usuaria
- URL base
- Conectar con URL e certificado cliente
- Escoller certificado
- Conectar
- Crear conta
- Nome da conta
- O uso de apóstrofes (\') pode causar problemas nalgúns dispositivos, según nos informan.
- Utiliza o teu enderezo de correo electrónico como nome de conta xa que Android utilizará o nome da conta como campo ORGANIZADOR para os eventos que cree. Non poderás ter dúas contas co mesmo nome.
- Método para agrupar contacto:
- Nome de conta requerido
- O nome de conta xa está a ser utilizado
- Non se creou a conta
- Conexión avanzada (casos especiais)
- Usar nome de usuaria/contrasinal
- Usar certificado cliente
- Non se atopa certificado
- Instalar certificado
- Detección da configuración
- Agarda por favor, consultando o servidor…
- Non se atopou servizo CalDAV ou CardDAV.
- ¿Usuaria (enderezo email) / contrasinal incorrectos?
- Mostrar detalles
-
- Axustes: %s
- Sincronización
- Intervalo de sincr. contactos
- Só manual
- Cada %d minutos + tras cambios locais
- Intervalo de sincr. calendarios
- Intervalo sincr. de tarefas
-
- - Só manual
- - Cada 15 minutos
- - Cada 30 minutos
- - Cada hora
- - Cada 2 horas
- - Cada 4 horas
- - Unha vez ao día
-
- Sincronizar só con WiFi
- Sincronización restrinxida a conexións WiFi
- Non se terá en conta o tipo de conexión
- Restrición SSID WiFi
- Sincr. só en %s
- Só se sincronizará baixo %s (require servizos de localización activos)
- Utilizaranse todas as conexións WiFi
- Nome das rede WiFi permitidas (SSIDs) separados por vírgulas (en branco para todas)
- A restrición WiFi SSID precisa máis axustes
- Xestionar
- Máis información (PMF)
- Autenticación
- Nome de usuaria
- Escribe o nome de usuaria:
- Contrasinal
- Actualizar o contrasinal de acordo ao teu servidor.
- Escribir contrasinal:
- Alias do certificado cliente
- Non hai certificado seleccionado
- CalDAV
- Límite temporal para eventos pasados
- Sincronizaranse todos os eventos
-
- - Eventos anteriores a un día serán ignorados
- - Eventos anteriores a %d días serán ignorados
-
- Eventos anteriores a máis dos días indicados serán ignorados (podería ser 0). Deixar en branco para sincronizar todos os eventos.
- Alarma por omisión
-
- - Alarma por omisión un minuto antes do evento
- - Alarma por omisión %d minutos antes do evento
-
- Non se crearon alarmas por omisión
- Se deben ser creadas as alarmas por omisión para eventos sen alarma: o número de minutos desexado antes do evento. Deixar baleiro para desactivar alarmas por omisión.
- Xestionar cores dos calendarios
- As cores do calendario restablécense tras cada sincr.
- Outras apps poden establecer as cores do calendario
- Soporte para cor de eventos
- As cores dos eventos están sincronizadas
- As cores dos eventos non están sincronizadas
- CardDAV
- Método para agrupar contacto
-
- - Grupos son vCards separados
- - Grupos son categorías por contacto
-
- Cambiar método para agrupar
-
- Crear libreta de enderezos
- A miña libreta de enderezos
- Crear calendario
- Fuso horario
- Entradas posibles no calendario
- Eventos
- Tarefas
- Notas / diario
- Combinado (eventos e tarefas)
- Cor
- Creando colección
- Título
- Requírese o título
- Descrición
- optativo
- Localización do almacenamento
- Requírese a localización da almacenaxe
- Crear
- Eliminar colección
- Quere eliminar?
- Esta colección (%s) e todos os seus datos eliminaranse definitivamente.
- Estos datos vanse eliminar do servidor.
- Eliminando colección
- Forzar só lectura
- Propiedades
- Enderezo (URL):
- Copiar URL
- Propietaria:
-
- Info depuración
- Arquivo ZIP
- Contén info de depuración e rexistros
- Comparte o arquivo para pasalo á computadora, envialo por email ou anexalo a un tícket de axuda
- Compartir arquivo
- Info de depuración anexa a esta mensaxe (require soporte de anexos na app receptora).
- Erro HTTP
- Fallo no servidor
- Fallo WebDAV
- Fallo I/O
- A solicitude foi denegada. Comproba os recursos implicados e o rexistro de depuración para máis info.
- O recurso solicitado xa non existe. Comproba os recursos implicados e a información de depuración.
- Hai un fallo no lado do servidor. Contacta co soporte do servidor.
- Aconteceu un fallo non agardado. Mira a info de depuración para detalles.
- Ver detalles
- Recolleuse a info de depuración
- Recursos implicados
- Relacionado co problema
- Recurso remoto:
- Recurso local:
- Ver coa app
- Rexistros
- Están dispoñibles rexistros explicativos
- Ver rexistros
-
- Algo fallou.
- Houbo un fallo HTTP.
- Houbo un fallo I/O.
- Mostrar detalles
-
- Sincronización en pausa
- Case non queda espazo libre
-
- Montaxes WebDAV
- Cota utilizada: %1$s / dispoñible: %2$s
- Compartir contido
- Desmontar
- Engadir montaxe WebDAV
- Accede aos teus ficheiros na nube engadindo unha montaxe WebDAV!
- como funciona a montaxe WebDAV.]]>
- Nome mostrado
- URL WebDAV
- URL inválido
- Nome de usuaria
- Contrasinal
- Engadir montaxe
- Neste URL non hai ningún servizo WebDAV
- Accedendo ao ficheiro WebDAV
- Descargando ficheiro WebDAV
- Subindo ficheiro WebDAV
- Montaxe WebDAV
-
- Permisos DAVx⁵
- Precísanse permisos adicionais
- %s demasiado antigo
- Versión mínima requerida: %1$s
- Fallo na autenticación (verifique credenciais)
- Fallo de Rede ou I/O – %s
- Fallo servidor HTTP – %s
- Fallo almacenamento local – %s
- Reintentar
- Ver elemento
- Recibido contacto non válido desde o servidor
- Recibido evento non válido desde o servidor
- Recibida tarefa non válida desde o servidor
- Ignorando un ou varios recursos non válidos
-
- DAVx⁵: seguridade da conexión
- DAVx⁵ atopou un certificado descoñecido. Queres confiar nel?
+
+ Xestor da conta
+ Axenda de WebDav
+ Lista de contactos
+ Axuda
+ Enviar
+ Depurando
+ Outras mensaxes importantes
+ Sincronización
+ Fallos de sincronización
+ Fallos importantes que deteñen a sincronización como respostas non agardadas do servidor
+ Avisos sobre a sincronización
+ Problemas non-fatais de sincronización como certos ficheiros non válidos
+ Fallos de rede e de I/O
+ Tempos límite, problemas de conexión, etc. (adoitan ser temporais)
+
+ Sincronización automática
+ O firmware %s adoita bloquear a sincronización automática. Neste caso, permita a sincronización automática na configuración de Android.
+ Sincronización programada
+ O seu dispositivo restrinxirá a sincronización do Xestor de Conta. Para forzar un intervalo regular de sincronización do Xestor de Conta, desactive a \"optimización de batería\".
+ Desactivar para o Xestor de Conta
+ Non mostrar de novo
+ Non agora
+ Información sobre o Código Aberto
+ Alegrámonos de que utilice o Xestor de Conta, que é software de código aberto (GPLv3). Desenvolver o Xestor de Conta require un importante esforzo e toma miles de horas de traballo, por favor considere facer unha doazón.
+ Mostrar páxina de doazóns
+ Máis tarde
+ Máis información
+ OpenTasks non está instalado
+ Para sincronizar tarefas precisa o aplicativo gratuíto OpenTasks. (Non requerido para contactos/eventos.)
+ Tras instalar OpenTasks, debe REINSTALAR o Xestor de Conta e engadir as súas contas novamente (erro de Android).
+ Instalar OpenTasks
+
+ Bibliotecas
+ Versión %1$s (%2$d)
+ Compilada en %s
+ Esta versión só está dispoñible para distribuír en Google Play.
+ Este programa non proporciona NINGUNHA GARANTÍA. É software libre, e convidámolo a redistribuílo baixo certas condicións.
+
+ Non se creou ficheiro de rexistro
+ Rexistro do Xestor de Conta
+ Está a rexistrar todas as actividades do %s
+ Enviar rexistro
+
+ Abrir barra de navegación
+ Pechar barra de navegación
+ Adaptador para sincr. CalDAV/CardDAV
+ Sobre / Licenza
+ Comentarios sobre Beta
+ Configuración
+ Novas & actualizacións
+ Ligazóns externas
+ Sitio web
+ Manual
+ PMF
+ Axuda / Foros
+ Doar
+ Sen conexión a internet, Android non sincronizará.
+ Dámosche a benvida ao Xestor de Conta!
+\n
+\nXa pode engadir unha conta ao Calendario ou aos Contactos.
+ A sincronización global automática do sistema está desactivada
+ Activar
+
+ Fallou a detección do servizo
+ Non se actualizou a lista da colección
+
+ Configuración
+ Depurando
+ Mostrar info de depuración
+ Ver/compartir detalles do software e configuración
+ Rexistro polo miúdo
+ O rexistro está activo
+ O rexistro está desactivado
+ Conexión
+ Sobrescribir a configuración da proxy
+ Utilizar axustes de proxy personalizados
+ Utilizar axustes proxy por omisión do sistema
+ Nome servidor proxy HTTP
+ Porto proxy HTTP
+ Seguridade
+ Non confiar en certificados do sistema
+ Non se confiará nos CAs do sistema ou engadidos por usuario
+ Confiarase nos CAs do sistema e engadidos por usuario (recomendado)
+ Restablecer certificados (non) confiables
+ Restablece a confianza en todos os certificados personalizados
+ Todos os certificados personalizados foron admitidos
+ Interface de usuario
+ Configuración das notificacións
+ Xestione as canles de notificación e a súa configuración
+ Restablecer consellos
+ Restablece todos os consellos que foran desbotados anteriormente
+ Mostraranse todos os consellos de novo
+
+ Contactos
+ Calendario
+ Webcal
+ No existen listas de contactos (aínda).
+ Non existen calendarios (aínda).
+ Non ten subscricións a calendario (aínda).
+ Arrastre cara abaixo para actualizar a lista desde o servidor.
+ Sincronizar agora
+ Sincronizando
+ Configuración da conta
+ Renomear conta
+ Os datos locais non gardados perderanse. A resincronización é precisa tras renomear. Novo nome da conta:
+ Renomear
+ Eliminar conta
+ Desexa eliminar a conta?
+ Todas as copias locais de listas de contactos, calendarios e tarefas eliminaranse.
+ sincronizar esta colección
+ só lectura
+ calendario
+ lista de tarefas
+ Actualizar lista de contactos
+ Crear nova lista de contactos
+ Actualizar lista de calendario
+ Crear novo calendario
+ Non se atopou app para Webcal
+ Instalar ICSx⁵
+
+ Engadir conta
+ Conectar co enderezo de correo electrónico
+ Enderezo de correo electrónico
+ Require un enderezo de correo válido
+ Contrasinal
+ Require contrasinal
+ Conectar con URL e nome de usuario
+ A URL debe comezar con http(s)://
+ A URL debe comezar con https://
+ Require nome do servidor
+ Nome de usuario
+ Require nome de usuario
+ URL base
+ Conectar con URL e certificado cliente
+ Escoller certificado
+ Acceder
+ Atrás
+ Engadir conta
+ Nome da conta
+ Utilice o seu enderezo de correo electrónico como nome de conta xa que Android utilizará o nome da conta como campo ORGANIZADOR para os eventos que cre. Non poderá ter dúas contas co mesmo nome.
+ Método para agrupar contacto:
+ Nome de conta requirido
+ Este nome de conta xa está a ser utilizado
+ Non se creou a conta
+ Engadir conta
+ Agarde por favor, engadindo a conta…
+ Fallou o rexistro. Comprobe o seu nome de usuario e contrasinal.
+ Mostrar detalles
+
+ Configuración: %s
+ Sincronización
+ Intervalo de sincr. contactos
+ Só manual
+ Cada %d minutos + tras cambios locais
+ Intervalo de sincr. calendarios
+ Intervalo sincr. de tarefas
+
+ - Só manual
+ - Cada 15 minutos
+ - Cada 30 minutos
+ - Cada hora
+ - Cada 2 horas
+ - Cada 4 horas
+ - Unha vez ao día
+
+ Sincronizar só con WiFi
+ Sincronización restrinxida a conexións WiFi
+ Non se terá en conta o tipo de conexión
+ Restrición SSID WiFi
+ Sincr. só en %s
+ Só se sincronizará baixo %s (require servizos de localización activos)
+ Utilizaranse todas as conexións WiFi
+ Nome das rede WiFi permitidas (SSIDs) separados por comas (en branco para todas)
+ Para ler os nomes WiFi, requírese o permiso de Localización e que os servizos de localización estean sempre activados.
+ Máis información (PMF)
+ Autenticación
+ Nome de usuario
+ Introduza nome de usuario:
+ Contrasinal
+ Actualizar o contrasinal de acordo ao seu servidor.
+ Introducir contrasinal:
+ Alcume do certificado cliente
+ Calendario
+ Límite temporal para eventos pasados
+ Sincronizaranse todos os eventos
+
+ - Eventos anteriores a un día serán ignorados
+ - Eventos anteriores a %d días serán ignorados
+
+ Eventos anteriores a máis dos días indicados serán ignorados (podería ser 0). Deixar en branco para sincronizar todos os eventos.
+ Xestionar cores dos calendarios
+ As cores dos calendarios son xestionadas polo Xestor da Conta
+ As cores do calendario non son establecidas polo Xestor da Conta
+ Compatible para cor de eventos
+ Sincr. cores de eventos
+ Non sincr. cores de eventos
+ Contactos
+ Método para agrupar contacto
+ Cambiar método para agrupar
+
+ Crear listas de contactos
+ A miña lista de contactos
+ Crear calendario
+ Fuso horario
+ Requírese o fuso horario
+ Entradas posibles no calendario
+ Eventos
+ Tarefas
+ Notas / xornal
+ Combinado (eventos e tarefas)
+ Cor
+ Creando colección
+ Título
+ Requírese un título
+ Descrición
+ opción
+ Localización do almacenamento
+ Crear
+ Eliminar colección
+ Quere eliminar?
+ Esta colección (%s) e todos os seus datos eliminaranse definitivamente.
+ Estoes datos vanse eliminar do servidor.
+ Eliminando colección
+ Forzar só lectura
+ Propiedades
+ Enderezo (URL):
+ Copiar URL
+
+ Algo fallou.
+ Houbo un fallo HTTP.
+ Houbo un fallo I/O.
+ Mostrar detalles
+
+ Info depuración
+ Os rexistros están anexados a esta mensaxe (precisa soporte de anexos do aplicativo receptor).
+ Lista de contactos de só lectura
+ Permisos do Xestor de Conta
+ Precísanse permisos adicionais
+ OpenTask está demasiado antigo
+ Require versión: %1$s (actual %2$)
+ Fallo na autenticación (verifique credenciais)
+ Fallo de rede ou I/O – %s
+ Fallo servidor HTTP – %s
+ Fallo almacenamento local – %s
+ Reintentar
+ Ver elemento
+ Contacto non válido recibido desde o servidor
+ Evento non válido recibido desde o servidor
+ Tarefa non válida recibida desde o servidor
+ Ignorando un ou varios recursos non válidos
+
+ Xestor de Conta: seguridade da conexión
+ O Xestor da Conta atopou un certificado descoñecido. Quere confiar nel\?
+ Axenda de Google
+ WebDAV
+ /e/ informará sobre un modelo de dispositivo falso a Google para protexer a súa privacidade.
+\nPode comprobar cal en Actividade do dispositivo de Google despois de acceder.
+ Aviso
+ Se os recordatorios perdeterminados se deben crear para eventos sen recordatorio: a cantidade de minutos desexados antes do evento. Déixeo en branco para desactivar os recordatorios predeterminados.
+ Non se crean recordatorios predeterminados
+
+ - Recordario predeterminado dun minuto para antes dun evento
+ - Recordario predeterminado de %d minuto para antes dun evento
+
+ Recordartorio predeterminado
+ Actualizar nome de usuario e contrasinal
+ Credenciais
+ Use un servidor específico
+ É necesario un enderezo URL válido do servidor
+ URL do servidor (https://server_url)
+ Use un servidor personalizado
+ Acceda cunha conta de /e/
+ Política de privacidade
+ Instale un navegador web
+ Instale un cliente de correo electrónico
+ Credenciais, frecuencia de sincronización, etc.
+ /e/ Axenda
+ /e/
+ Google
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 378c665c4b66559590932e02be73cd6d69511aef..2f1b34fba7a010f9df9769b22a611709573fd24b 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -1,419 +1,281 @@
-
+
-
- DAVx⁵
- A felhasználói fiók (már) nem létezik
- DAVx⁵ címjegyzék
- Címjegyzékek
- Ennek e mezőnek a megadása kötelező
- Súgó
- Fiókok kezelése
- Megosztás
- Az adatbázis megsérült
- A fiókok törölve lettek az eszközön.
- Hibakeresés
- Egyéb fontos üzenetek
- Alacsony prioritású státuszüzenetek
- Szinkronizáció
- Szinkronizációs hibák
- Fontos hibák amelyek miatt a szinkronizáció megszakad, például váratlan szerverválaszok
- Szinkronizációs figyelmeztetések
- Nem kritikus szinkronizációs hibák, például bizonyos fajta hibás fájlok
- Hálózati és I/O hibák
- Időtúllépésék, kapcsolódási problémák, stb. (gyakran átmeneti problémák)
-
- Az Ön adatai. Az Ön döntése.
- Vegye kézbe az irányítást.
- Rendszeres ütemezett szinkronizálás
- Kikapcsolva (nem javasolt)
- Bekapcsolva (javasolt)
- A rendszeres ütemezett szinkronizáláshoz a %s számára engedélyezni kell a háttérben futást, különben az Android rendszer a szinkronizálást bármikor leállíthatja.
- Nincs szükségem rendszeres ütemezett szinkronizálásra.*
- %s kompatibilitás
- Ez az eszköz valószínűleg blokkolja a szinkronizálást. Ha valóban, ez manuálisan megoldható.
- Elvégeztem a szükséges beállításokat, nincs szükségem további figyelmeztetésre.*
- * Hagyja üresen, ha szeretné, ha legközelebb is kapjon emlékeztetést. Később felülírható az alkalmazásbeállításoknál (%s).
- További információk
- jtx Board
-
- Feladatok támogatása
- Ha a szerver támogatja a feladatokat, akkor a következő feladat alkalmazásokkal lehet szinkronizálni őket:
- OpenTasks
- további alkalmazásokra .]]>
- Feladatok
- nem támogatott (még).]]>
- Nincs elérhető alkalmazás-áruház
- Nincs szükségem a feladatok támogatására.*
- Nyílt forráskódú szoftver
- Nagyon örülünk, hogy a %s felhasználói közé tartozik, ami egy nyílt forráskódú szoftver. Ennek fejlesztése, karbantartása és támogatása ugyanakkor kemény munkát igényel. Kérjük, fontolja meg, hogy ezt pénzzel vagy valamilyen módon támogassa (több lehetőség közül is választhat). Nagyon megköszönnénk!
- A hozzájárulás lehetőségei
- Ne mutassa a közeljövőben
-
- Engedélyek
- A %s megfelelő működése bizonyos engedélyeket igényel.
- Az összes alább felsorolt
- Ezt választva valamennyi funkció bekapcsolható (javasolt)
- Az összes engedély megadva
- Névjegy-engedélyek
- A címtárak szinkronizálásának mellőzése (nem javasolt)
- A névjegyek szinkronizálása (javasolt)
- Naptár-engedélyek
- A naptárak szinkronizálásának mellőzése (nem javasolt)
- A naptárak szinkronizálása (javasolt)
- jtx Board engedélyek
- Nincs feladat, napló- és jegyzetszinkronizálás (nincs telepítve)
- Nincsenek szinkronizálandó feladatok, naplóbejegyzések és jegyzetek
- Van lehetőség a feladatok, naplóbejegyzések és jegyzetek szinkronizálására
- OpenTasks engedélyek
- Feladat engedélyek
- A feladatlisták szinkronizálása nem lehetséges (nincs telepítve)
- Nincs feladatszinkronizálás
- A feladatlisták szinkronizálása lehetséges
- Engedélyek megtartása
- Az engedélyek automatikusan visszaállhatnak az alapértelmezettre (nem ajánlott)
- Az engedélyek nem fognak visszaállni az alapértelmezettre automatikusan
- Kattints az Engedélyekre > vedd ki a pipát az \"Engedélyek eltávolítása, ha nem használja az alkalmazást\" mellől
- Ha a kapcsolók nem működnek, használja az alkalmazás-beállításokat
- Alkalmazásbeállítások
-
- WiFi SSID engedélyek
- A jelenlegi WiFi nevének (SSID) az eléréséhez a következő feltételeknek kell teljesülniük:
- Pontos helyadatok használatának engedélyezése
- Helyadat engedélyek megadva
- Helyadat engedélyek megtagadva
- Helyadatok engedélyezése a háttérben
- Mindig engedélyezze
- %sre]]>
- %sre]]>
- %s a Helyadat engedélyt csak arra használja, hogy a jelenlegi WiFi SSID-jét meghatározza SSID-korlátozott fiókokhoz. Ez a funkció akkor is működik, ha az alkalmazás háttérben van. Semmilyen helyadatot nem gyűjtünk, tárolunk, feldolgozunk vagy küldünk bárhová.
- Helyadatok mindig engedélyezve
- Hely szolgáltatás bekapcsolva
- Hely szolgáltatás kikapcsolva
-
- Fordítások
- Könyvtárak
- Verziószám:%1$s (%2$d)
- Fordítás ideje: %s
- © Ricki Hirner, Bernhard Stockmann (bitfire web engineering GmbH) és a közreműködők
- Ez a verzió csak a Google Play Áruházon keresztül terjeszthető
- Ehhez a program SEMMIFÉLE GARANCIA NEM JÁR. Ez a program szabad szoftver, ami a bizonyos feltételek mellett szabadon terjeszthető.
- Köszönet a következőknek: %s]]>
-
- A naplófájl létrehozása nem sikerült
- Mostantól %s minden művelete naplózásra kerül
- Nézet/megosztás
- Kikapcsol
-
- Navigációs fiók megnyitása
- Navigációs fiók lezárása
- CalDAV/CardDAV szinkronizációs adapter
- Névjegy / Licenc
- Tesztelői visszajelzés
- Kérjük, telepítsen egy levelező-klienst
- Kérjük, telepítsen egy böngészőt
- Beállítások
- Hírek és frissítések
- Eszközök
- Weblapok
- Honlap
- Kézikönyv
- GYIK
- Közösség
- Támogatás
- Adatvédelmi politika
- Nincs Internet-elérés. Az Android rendszer nem fogja elvégezni a szinkronizálst
- Kevés a rendelkezésre álló tárhely. A rendszer nem fog szinkronizálást végezni.
- Üdvözöljük a DAVx⁵ felhasználók között!\n\nMost már felvehet CalDAV/CardDav fiókokat.
- A rendszerszintű automatikus szinkronizálás ki van kapcsolva
- Bekapcsolás
- Az összes fiók szinkronizálása
-
- Szolgáltatások felderítése nem sikerült
- Gyűjteménylista frissítése nem sikerült
-
- Nem lehetséges az előtérben való futtatás
- Kivétel az akkumulátorhasználat optimalizálása alól
-
- Futás előtérben
- Egyes eszközökön erre szükség van az automatikus szinkronizáció működéséhez
-
- Beállítások
- Hibakeresés
- Hibakeresési információ megtekintése
- Szoftver- és konfigurációs részletek megtekintése/megosztása
- Részletes naplózás
- Naplózás bekapcsolva
- Naplózás kikapcsolva
- Akkumulátorhasználat optimalizálása
- Az optimalizálás kikapcsolva (ajánlott)
- Az optimalizálás bekapcsolva (nem ajánlott)
- Maradjon előtérben
- Segíthet, ha az eszköz akadályozza az automatikus szinkronizációt
- Kapcsolat
- A proxy típusa
-
- - Alapértelmezett
- - Kikapcsolva
- - HTTP
- - SOCKS (Orbot számára)
-
- A proxy szerver neve
- A proxy által használt port
- Biztonság
- Alkalmazásengedélyek
- Tekintse át a szinkronizáláshoz szükséges engedélyeket
- A rendszertanúsítványok elfogadása
- A rendszer által kezelt, előre vagy felhasználó által telepített tanúsítványok figyelmen kívül lesznek hagyva
- A rendszer által kezelt, előre vagy felhasználó által telepített tanúsítványok megbízhatóak (javasolt)
- A tanúsítványok megbízhatóságának törlésére
- A tanúsítványok megbízhatóságával kapcsolatos beállítások törlésére
- A tanúsítványok megbízhatóságával kapcsolatos beállítások törölve
- Felhasználói felület
- Értesítési beállíások
- Az értesítési csatornák és azok beállításának kezelése
- Stílus kiválasztása
-
- - Rendszerbeállítás szerinti
- - Világos
- - Sötét
-
- Tippek visszaállítása
- Újra jelenjen meg az összes tipp
- Az összes tipp újra meg fog jelenni
- Integráció
- Feladatok alkalmazás
- Szinkronizálás ezzel: %s
- Nem található kompatibilis feladat alkalmazás
-
- CardDAV
- CalDAV
- Webcal
- A névjegyek szinkronizálása nem működik (nincs engedélyezve)
- A naptárak szinkronizálása nem működik (nincs engedélyezve)
- A feladatok szinkronizálása nem működik (nincs engedélyezve)
- A naptárak és feladatok szinkronizálása nem működik (nincs engedélyezve)
- A naptárak elérése nem működik (nincs engedélyezve)
- Engedélyek
- Nincsenek címjegyzékek (még).
- Nincsenek naptárak (még).
- Nem iratkozott fel egyetlen naptárra sem (még).
- Lefelé húzással frissítse a listát a szerverről.
- Szinkronizálás most
- Szinkronizálás
- Fiókbeállítások
- Fiók átnevezése
- Az elmentetlen helyben tárolt adatok elvesznek. Az átnevezés után szinkronizálásra lesz szükség. Új fióknév:
- Átnevez
- A fiók átnevezése nem sikerült.
- Fiók törlése
- Valóban törölni akarja a fiókot?
- Az összes címjegyzék, naptár és feladatlista helyi példányai törölve lesznek.
- a gyűjtemény szinkronizálása
- csak olvasható
- naptár
- feladatlista
- napló
- Csak a személyesek megjelenítése
- Címjegyzék-lista frissítése
- Új címjegyzék létrehozása
- Naptárlista frissítése
- Új naptár létrehozása
- Nem található Webcal-képes alkalmazás
- ICSx⁵ telepítése
-
- Fiók hozzáadása
- Bejelentkezés email cím segítségével
- Email cím:
- Érvényes email cím megadása feltétlenül szükséges
- Jelszó
- A jelszó megadása szükséges
- Bejelentkezés URL és felhasználónév segítségével
- Az URL elején szerepeljen http(s)://
- Felhasználónév
- A felhasználónév megadása feltétlenül szükséges
- URL-törzs
- Bejelentkezés URL és tanúsítvány segítségével
- Tanúsítvány kiválasztása
- Bejelentkezés
- Fiók létrehozása
- A fiók neve
- Az aposztróf (\') használata a visszajelzések szerinte egyes eszközökön problémát okoz.
- Használja az email címet fióknévként, mert később a létrehozandó események szervezőjeként (ORGANIZER mező) az Android ezt fogja használni. Két fiókot nem lehet azonos néven létrehozni.
- A csoportok kezelésének módja:
- A fióknév megadása feltétlenül szükséges
- A fióknév már használatban van
- A fiók létrehozása nem sikerült
- Haladó bejelentkezés (speciális lehetőségek)
- Felhasználónév/jelszó használata
- Tanúsítvány használata
- Nem található tanúsítvány
- Tanúsítvány telepítése
- A konfiguráció felderítése
- Kérjük, várjon, a szerver lekérdezése…
- Nem található CalDAV vagy CardDAV szolgáltatás.
- Felhasználónév (e-mail cím) vagy jelszó hibás?
- Részletek mutatása
-
- Beállítások: %s
- Szinkronizálás
- Névjegyszinkronizálás sűrűsége
- Manuális
- Minden %d percben + az eszközön történt módosítás után
- Naptárszinkronizálás sűrűsége
- Feladatlisták szinkronizálásának sűrűsége
-
- - Manális
- - 15 percenként
- - 30 percenként
- - Óránként
- - Kétóránként
- - Négyóránként
- - Naponta
-
- Szinkronizálás csak WIFI-n
- Csak WIFI kapcsolat keresztül történjen szinkronizálás
- Szinkronizálás a kapcsolat típusától függetlenül
- WiFi SSID szűrés
- Az alábbi hálózatok használhatók: %s
- Szinkronizálás csak a megadott hálózaton (%s) keresztül (bekapcsolt helymeghatározási szolgáltatást igényel)
- Minden hálózat használható
- A használható WiFi hálózatok nevei (SSID), vesszővel elválasztva (hagyja üresen, ha nem akar szűrést beállítani)
- WiFi SSID szűréshez további beállítások szükségesek
- Beálítások
- További információk (GYIK)
- Authentikáció
- Felhasználónév
- Adja meg a felhasználónevet:
- Jelszó
- Adja meg a szerveren érvényes új jelszót.
- Adja meg a jelszót:
- Tanúsítvány alternatív megnevezése
- Nincs tanúsítvány kiválasztva
- CalDAV
- Múltbéli események időkorlátja
- Minden esemény szinkronizálása
-
- - Az egy napnál régebbi események figyelmen kívül hagyása
- - A %d napnál régebbi események figyelmen kívül hagyása
-
- Az ennyi napnál (lehet 0) régebbi események figyelmen kívül lesznek hagyva. Hagyja üresen, ha minden múltbéli eseményt szinkronizálni akar.
- Alapértelmezett emlékeztető
-
- - Az alapértelmezett emlékeztető egy perc az esemény kezdetet előtt
- - Az alapértelmezett emlékeztető %d perc az esemény kezdetet előtt
-
- Nem lesznek alapértelmezett emlékeztetők beállítva
- Ha szeretné, hogy az emlékeztető nélküli eseményekhez egy alapértelmezett emlékeztető legyen beállítva, akkor adja meg, hogy az hány perccel az esemény előtt legyen. Ha nem akar ilyet, hagyja üresen.
- Naptárszínek kezelése
- Naptárszínek visszaállnak az alapértelmezettre minden szinkronizáláskor
- Naptárszíneket más alkalmazásokban lehet beállítani
- Eseményszínek támogatása
- Eseményszínek szinkronizálva
- Eseményszínek nincsenek szinronizálva
- CardDAV
- A csoportok kezelésének módja
-
- - A csoportok különálló vCard objektumok
- - A csoportok névjegy-kategóriák
-
- A csoportok kezelésének megváltoztatása
-
- Címjegyzék létrehozása
- Új címjegyzék
- Naptár létrehozása
- Időzóna
- Lehetséges naptárbejegyzések
- Események
- Feladatok
- Jegyzetek/napló
- Kombinált (események és feladatok)
- Szín
- Gyűjtemény létrehozása
- Cím
- A cím megadása feltétlenül szükséges
- Leírás
- opcionális
- Tárhely
- A tárhely megadása feltétlenül szükséges
- Létrehozás
- Gyűjtemény törlése
- Biztos?
- A gyűjtemény (%s) és a hozzá tartozó adatok véglegesen törölve lesznek a szerverről.
- Az adatok törölve lesznek a szerverről.
- Gyűjtemény törlése
- Csak olvashatóvá tétel
- Tulajdonságok
- Cím (URL):
- URL másolása
- Tulajdonos:
-
- Hibakeresési információ
- ZIP archívum
- Hibakeresési információkat tartalmaz
- Az archívum megosztásával lehetőség van egy másik számítógépre áthelyezni, e-mail formájában elküldeni vagy egy hibabejelentéshez becsatolni.
- Archívum megosztása
- Hibakeresési információ csatolása ehhez az üzenethez (ha a fogadó alkalmazás támogatja a csatolmányokat).
- HTTP hiba
- Szerverhiba
- WebDAV hiba
- I/O hiba
- A kérés megtagadva. Ellenőrizze az érintett erőforrásokat és a hibakeresési információkat a további részletekért.
- Az igényelt erőforrás nem létezik (már). Ellenőrizze az érintett erőforrásokat és a hibakeresési információkat a további részletekért.
- Szerveroldali hiba történt. Vegye fel a kapcsolatot a szerver üzemeltetőjével.
- Váratlan hiba történt. Hibakereséshez használja a hibakeresési információkat.
- Részletek megtekintése
- A hibakeresési információ összegyűjtése befejeződött
- Érintett erőforrások
- A probléma kapcsán érintett erőforrások
- Távoli erőforrás:
- Helyi erőforrás:
- Megtekintés alkalmazásban
- Naplóbejegyzések
- Rendelkezésre állnak részletes naplóbejegyzések
- Naplóbejegyzések megtekintése
-
- Hiba történt.
- HTTP hiba történt.
- I/O hiba történt.
- Részletek megjelenítése
-
- A szinkronizáció felfüggesztve
- A tárhely majdnem teljesen betelt
-
- WebDAV kötetek
- Kvóta: felhasználva %1$s, keret %2$s
- Tartalom megosztása
- Lecsatolás
- WebDAV kötet hozzáadása
- Közvetlenül hozzáférhet felhőben tárolt fájlokhoz WebDAV kötet hozzáadásával!
- hogyan lehet WebDAV köteteket használni.]]>
- Megjelenítendő név
- WebDAV URL
- Érvénytelen URL
- Felhasználónév
- Jelszó
- WebDAV kötet hozzáadása
- Ezen a címen nincs WebDAV szolgáltatás
- Hozzáférés WebDAV fájlhoz
- WebDAV fájl letöltése
- WebDAV fájl feltöltése
- WebDAV kötetek
-
- DAVx⁵ engedélyek
- További engedélyek szükségesek
- %s túl régi
- Legalacsonyabb szükséges verzió: %1$s
- Authentikáció nem sikerült (ellenőrizze a hitelesítéshez megadott adatokat)
- Hálózati vagy I/O hiba – %s
- HTTP kiszolgálóhiba - %s
- Tárhelyhiba - %s
- Újbóli próbálkozás
- Elem megtekintése
- A szerver érvénytelen névjegyet küldött
- A szerver érvénytelen eseményt küldött
- A szerver érvénytelen feladatot küldött
- Egy vagy több érvénytelen erőforrás kihagyva
-
- DAVx⁵: kapcsolatbiztonság
- Egy eddig ismeretlen tanúsítvány érkezett. Megbízhatónak kívánja elfogadni?
+
+ Fiókkezelő
+ WebDav címjegyzék
+ Címjegyzékek
+ Súgó
+ Küldés
+ Hibakeresés
+ Egyéb fontos üzenetek
+ Szinkronizáció
+ Szinkronizációs hibák
+ Fontos hibák amelyek miatt a szinkronizáció megszakad, például váratlan szerverválaszok
+ Szinkronizációs figyelmeztetések
+ Nem kritikus szinkronizációs hibák, például bizonyos fajta hibás fájlok
+ Hálózati és I/O hibák
+ Időtúllépésék, kapcsolódási problémák, stb. (gyakran átmeneti problémák)
+
+ Automatikus szinkronizálás
+ A(z) %s gyári szoftvere gyakran blokkolja az automatikus szinkronizálást. Ebben az esetben engedélyezze a szinkronizálást az Android beállítások között.
+ Időzített szinkronizálás
+ Az eszköz korlátozni fogja a Fiókkezelő szinkronizálást. A szokásos DAVadroid szinkronizációs ciklus biztosítása érdekében vonja ki a Fiókkezelő-ot az „akkumulátorfigyelés” alól.
+ A fiókkezelőhöz kapcsoljuk ki
+ Ne jelenjen meg többet
+ Ne most
+ Nyílt forráskód információ
+ Örülünk, hogy használja a Fiókkezelőt. A Fiókkezelő nyílt forráskódú (GPLv3) szoftver, ennek fejlesztése több ezer kemény munkaórát jelentett eddig. Kérjük gondolja át és adományokkal támogassa munkánkat!
+ Adományozó oldal mutatása
+ Talán később
+ További információk
+ Az OpenTasks nincs telepítve
+ A feladatok szinkronizálásához az ingyenes OpenTasks alkalmazásra van szükség. A névjegyek és események szinkronizálásához erre nincs szükség.
+ Az OpenTasks telepítését követően újra kell telepíteni a DAVdroit alkalmazást és újra fel kell venni a fiókokat (Android hiba).
+ Az OpenTasks telepítése
+
+ Könyvtárak
+ Verziószám:%1$s (%2$d)
+ Teljesítés ideje: %s
+ Ez a verzió csak a Google Play Áruházon keresztül terjeszthető
+ Ehhez a programhoz SEMMIFÉLE GARANCIA NEM JÁR. Ez a program szabad szoftver, ami a bizonyos feltételek mellett szabadon terjeszthető.
+
+ A naplófájl létrehozása nem sikerült
+ Fiókkezelő naplózás
+ Mostantól %s minden művelete naplózásra kerül
+ Naplófájl küldése
+
+ Navigációs fiók megnyitása
+ Navigációs fiók bezárása
+ Naptár, névjegyzék szinkronizáló adapter
+ Névjegy / Engedély
+ Tesztelői visszajelzés
+ Beállítások
+ Hírek és frissítések
+ Külsős linkek
+ Honlap
+ Kézikönyv
+ GYIK
+ Segítség / Fórumok
+ Támogatás
+ Üdvözlünk a fiókkezelőben!
+\n
+\nMostantól hozzáadhatsz naptárt és névjegyzéket.
+ A rendszerszintű automatikus szinkronizálás ki van kapcsolva
+ Bekapcsolás
+
+ Szolgáltatások felderítése nem sikerült
+ Gyűjteménylista frissítése nem sikerült
+
+ Beállítások
+ Hibakeresés
+ Hibakeresési információ megtekintése
+ Szoftver- és konfigurációs részletek megtekintése/megosztása
+ Részletes naplózás
+ Naplózás bekapcsolva
+ Naplózás kikapcsolva
+ Kapcsolat
+ Proxybeállítások felülírása
+ Egyedi proxybeállítások
+ Az alapértelmezett proxybeállítás használata
+ HTTP proxyállomás neve
+ HTTP proxy port
+ Biztonság
+ A rendszertanúsítványok elfogadása
+ A rendszer által kezelt, előre vagy felhasználó által telepített tanúsítványok figyelmen kívül lesznek hagyva
+ A rendszer által kezelt, előre vagy felhasználó által telepített tanúsítványok megbízhatóak (javasolt)
+ A tanúsítványok visszaállítása
+ A tanúsítványok megbízhatóságával kapcsolatos beállítások törlésére
+ A tanúsítványok megbízhatóságával kapcsolatos beállítások törölve
+ Felhasználói felület
+ Értesítési beállítások
+ Az értesítési csatornák és azok beállításának kezelése
+ Tippek visszaállítása
+ Újra jelenjen meg az összes tipp
+ Az összes tipp újra meg fog jelenni
+
+ Névjegyek
+ Naptár
+ Webcal
+ Szinkronizálás most
+ Szinkronizálás most
+ Fiókbeállítások
+ Fiók átnevezése
+ Az elmentetlen helyben tárolt adatok elvesznek. Az átnevezés után szinkronizálásra lesz szükség. Új fióknév:
+ Átnevez
+ Fiók törlése
+ Valóban törölni akarja a fiókot\?
+ Az összes címjegyzék, naptár és feladatlista helyi példányai törölve lesznek.
+ a gyűjtemény szinkronizálása
+ csak olvasható
+ naptár
+ feladatlista
+ Címjegyzék-lista frissítése
+ Új címjegyzék létrehozása
+ Naptárlista frissítése
+ Új naptár létrehozása
+ Nem található Webcal-képes alkalmazás
+ ICSx⁵ telepítése
+
+ Fiók hozzáadása
+ Bejelentkezés email cím segítségével
+ E-mail cím:
+ Érvényes email cím megadása feltétlenül szükséges
+ Jelszó
+ A jelszó szükséges
+ Bejelentkezés URL és felhasználónév segítségével
+ Az URL elején kötelezően szerepeljen http(s)://
+ Az URL elején kötelezően szerepeljen https://
+ A szervernév megadása feltétlenül szükséges
+ Felhasználónév
+ A felhasználónév megadása feltétlenül szükséges
+ URL-törzs
+ Bejelentkezés URL és tanúsítvány segítségével
+ Tanúsítvány kiválasztása
+ Bejelentkezés
+ Vissza
+ Fiók hozzáadása
+ A fiók neve
+ Használja az email címet fióknévként, mert később a létrehozandó események szervezőjeként (ORGANIZER mező) az Android ezt fogja használni. Két fiókot nem lehet azonos néven létrehozni.
+ A csoportok kezelésének módja:
+ A fióknév megadása feltétlenül szükséges
+ A fióknév már használatban van
+ Ugyanezen a néven már létezik egy fiók
+ Fiók hozzáadása
+ Kérjük várjon! Fiók hozzáadása folyamatban…
+ Bejelentkezés sikertelen. Kérjük ellenőrizze a felhasználónevét és jelszavát!
+ Részletek mutatása
+
+ Beállítások: %s
+ Szinkronizálás
+ Névjegyszinkronizálás sűrűsége
+ Csak kézileg
+ Minden %d percben + az eszközön történt módosítás után
+ Naptárszinkronizálás sűrűsége
+ Feladatlisták szinkronizálásának sűrűsége
+
+ - Manális
+ - 2 perc
+ - 15 percenként
+ - 30 percenként
+ - Óránként
+ - Kétóránként
+ - Négyóránként
+ - Naponta
+
+ Szinkronizálás csak WiFi-n
+ Csak WiFi kapcsolaton keresztül történjen szinkronizálás
+ Szinkronizálás a kapcsolat típusától függetlenül
+ WiFi SSID korlátozás
+ Az alábbi hálózatok használhatók: %s
+ Szinkroniázálás csak a megadott hálózaton (%s) keresztül (bekapcsolt helymeghatározási szolgáltatást igényel)
+ Minden WiFi hálózatot használjuk
+ A használható WiFi hálózatok nevei (SSID), vesszővel elválasztva (hagyja üresen, ha nem akar szűrést beállítani)
+ A WiFi hálózatok nevének elérése, helyadatokat alkalmazásengedélyt és folyamatosan bekapcsolt helymeghatározási szolgáltatást igényel.
+ További információk (GYIK)
+ Hitelesítés
+ Felhasználónév
+ Adja meg a felhasználónevet:
+ Jelszó
+ Frissítse a jelszót a szerverének megfelelően.
+ Adja meg a jelszót:
+ Tanúsítvány alternatív megnevezése
+ Naptár
+ Múltbéli események időkorlátja
+ Minden esemény szinkronizálása
+
+ - Az egy napnál régebbi események figyelmen kívül hagyása
+ - A %d napnál régebbi események figyelmen kívül hagyása
+
+ A megadott számú napnál régebbi események figyelmen kívül lesznek hagyva, ez a szám lehet nulla is. Hagyja üresen, ha minden múltbéli eseményt szinkronizálni szeretne.
+ Naptárszínek kezelése
+ A naptárszíneket a Fiókkezelő kezeli
+ A naptárszíneket nem a Fiókkezelő kezeli
+ Eseményszínek támogatása
+ Eseményszínek szinkronlzálása
+ Az eseményszínek szinkronizálásának elhagyása
+ Címjegyzék
+ A csoportok kezelésének módja
+ A csoportok kezelésének megváltoztatása
+
+ Címjegyzék létrehozása
+ Az én címjegyzékem
+ Naptár létrehozása
+ Időzóna
+ Az időzóna megadása kötelező
+ Lehetséges naptárbejegyzések
+ Események
+ Feladatok
+ Jegyzetek/napló
+ Kombinált (események és feladatok)
+ Szín
+ Gyűjtemény létrehozása
+ Cím
+ A cím megadása feltétlenül szükséges
+ Leírás
+ választható
+ Tárhely
+ Létrehozás
+ Gyűjtemény törlése
+ Biztos vagy benne\?
+ A gyűjtemény (%s) és a hozzá tartozó adatok véglegesen törölve lesznek.
+ Ezek az adatok törölve lesznek a szerverről.
+ Gyűjtemény törlése
+ Legyen csak olvasható
+ Tulajdonságok
+ Cím (URL):
+ URL másolása
+
+ Hiba történt.
+ HTTP hiba történt.
+ I/O hiba történt.
+ Részletek megjelenítése
+
+ Hibakeresési információ
+ Csak olvasható címjegyzék
+ Fiókkezelő engedélyek
+ További engedélyek szükségesek
+ Az OpenTask túl régi
+ Szükséges verzió: %1$s (jelenlegi verzió: %2$s)
+ A hitelesítés nem sikerült. Kérjük ellenőrizze a bejelenkezési adatait!
+ Hálózati vagy I/O hiba – %s
+ HTTP szerverhiba - %s
+ Tárhelyhiba - %s
+ Újrapróbálás
+ Elem megtekintése
+ A szerver érvénytelen névjegyet küldött
+ A szerver érvénytelen eseményt küldött
+ A szerver érvénytelen feladatot küldött
+ Egy vagy több érvénytelen erőforrás kihagyása
+
+ Fiókkezelő: kapcsolatbiztonság
+ A fiókkezelő egy eddig ismeretlen tanúsítvánnyal találkozott. Minősítük megbízhatónak\?
+ Google címjegyzék
+ Google
+ Hitelesítők, szinkronizálás sűrűsége stb.
+ Kérlek telepíts egy e-mail klienst
+ WebDAV
+ /e/
+ /e/ címjegyzék
+ Kérlek telepíts egy web böngészőt
+ Adatvédelmi irányelvek
+ Nincs internetcsatlakozás. Az android nem futtatja a szinkronizációt.
+ Egyelőre még nincs címjegyzék a készüléken.
+ Egyelőre még nincs naptár a készüléken.
+ Húzz egyet lefelé és akkor frissül a lista a szerverről.
+ Bejelentkezés /e/ fiókkal
+ Egyedi szerver használata
+ Szerver URL (https://szerver_url)
+ Érvényes szerver URL cím szükséges
+ Hitelesítő adatok
+ Felhasználónév és jelszó frissítése
+ Alapértelmezett emlékeztető
+
+ - Alapértelmezett emlékeztető 1 perccel az esemény előtt
+ - Alapértelmezett emlékeztető %d perccel az esemény előtt
+
+ Nem készült alapértelmezett értesítő
+ Naplókat csatoltak ehhez az üzenethez. A fogadó alkalmazás részéről szükséges a csatolmányok támogatása.
+ FIGYELMEZTETÉS
+ Az /e/ egy hamis készülékmodellt for jelenteni a Google számára, az adatvédelmed érdekében.
+\nEllenőrizheted, hogy melyik modell van a Google készülékaktivitásban, miután beléptél.
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 67d536005b7b8b63c8e05e53af3ca163fdacba7e..b084e8ea9a76ddea6f2869d80f0722ce02eb8a43 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -1,396 +1,315 @@
-
+
-
- DAVx⁵
- Account inesistente (o cancellato)
- Rubrica DAVx⁵
- Rubriche
- Questo campo è necessario
- Aiuto
- Gestione account
- Condividi
- Database danneggiato
- Tutti gli account sono stati rimossi localmente.
- Debugging
- Altri messaggi importanti
- Messaggi di stato a bassa priorità
- Sincronizzazione
- Errori di sincronizzazione
- Errori importanti che bloccano la sincronizzazione, come risposte inattese del server
- Avvisi di sincronizzazione
- Problemi di sincronizzazione non gravi come alcuni file non validi
- Errori di Rete e di I/O
- Timeouts, problemi di connessione, ecc. (spesso temporanei)
-
- Tuoi i dati. Tua la scelta.
- Riprendi il controllo.
- Intervalli di sincronizzazione regolari.
- Disabilitato (sconsigliato)
- Abilitato (scelta consigliata)
- Per sincronizzare i dati a intervalli regolari, %s deve essere autorizzato a girare in background. Altrimenti Android può mettere in pausa gli aggiornamenti in qualunque momento.
- Non ho bisogno di sincronizzare a intervalli di tempo regolari.*
- %s compatibilità
- Questo dispositivo probabilmente impedisce la sincronizzazione. In questo caso puoi risolvere solo manualmente.
- Ho settato le impostazioni richieste. Non ricordarmelo più.
- * Lascia smarcato per fartelo ricordare dopo. Può essere reimpostato nelle impostazione dell\'app %s.
- Maggiori informazioni
- Supporto per le attività
- Se le attività sono supportate dal tuo server, possono essere sincronizzate con una app per attività supportata:
- OpenTasks
- app addizionali .]]>
- Attività
- non sono (ancora) supportate .]]>
- Nessun app store disponibile
- Non ho bisogno del supporto alle attività.*
- Software open-source
- Siamo felici che tu usi %s, che è un software open source. Lo sviluppo, la manutenzione e il supporto sono compiti duri. Per piacere prendi in considerazione di dare una mano (puoi farlo in molti modi) o una donazione. Sarebbe davvero apprezzato!
- Come aiutare/donare
- Non mostrare nell\'immediato futuro
-
- Autorizzazioni
- %s richiede autorizzazioni per funzionare correttamente.
- Tutti i seguenti
- Usare questo per abilitare tutte le funzioni (consigliato)
- Concedi tutte le autorizzazioni
- Autorizzazioni per i contatti
- Non sincronizzare i contatti (sconsigliato)
- Possibilità di sincronizzare i contatti
- Autorizzazioni per il calendario
- Non sincronizzare il calendario (sconsigliato)
- Permette di sincronizzare il calendario
- Autorizzazioni di OpenTasks
- Autorizzazioni delle attività
- Attività non sincronizzate (app non installata)
- Permette di sincronizzare le attività
- Mantieni autorizzazioni
- Le autorizzazioni possono essere reimpostate automaticamente (sconsigliato)
- Le autorizzazioni non si reimposteranno automaticamente
- Fai click su Autorizzazioni > deseleziona \"Rimuovi autorizzazioni se l\'app non è in uso\"
- Se uno slider non funziona, vai a impostazioni app/ autorizzazioni.
- Impostazioni app
-
- Autorizzazioni per WiFi SSID
- Per poter accedere al nome dell\'attuale nome del WIFI (SSID), devono essere soddfsfatte queste condizioni:
- Autorizzazione precisa della localizzazione
- Garantire l\'autorizzazione della posizione
- Negare l\'autorizzazione della posizione
- Autorizzazione della posizione in background
- Permettere sempre
- %s]]>
- 1%s]]>
- 1%s utilizza l\'autorizzazione della posizione solo per determinare l\'SSID del WIFI attuale per gli account SSID-limitati. Questo accade anche quando l\'applicazione è in modalità background. Nessun dato sulla posizione è raccolto, salvato, processato o mandato da qualche parte.
- Posizione sempre disabilitata
- Servizio di posizione abiltato
- Servizio di posizione disabilitato
-
- Traduzioni
- Librerie
- Versione %1$s (%2$d)
- Compilato su %s
- © Ricki Hirner, Bernhard Stockmann (bitfire web engineering GmbH) e contibutori
- Questa versione è idonea solo per la distribuzione tramite Google Play
- Il programma è distribuito SENZA ALCUNA GARANZIA. È software libero e può essere redistribuito sotto alcune condizioni.
- Grazie a: %s]]>
-
- Non riesco a creare il file di log
- Adesso l\'accesso all\' %s delle attività
- Visualizza/condividi
- Disabilita
-
- Apri barra di navigazione
- Chiudi barra di navigazione
- CalDAV/CardDAV adattatore di sincronizzazione
- Informazioni / Licenza
- Feedback sulla beta
- Installare un client email
- Installare un browser Web
- Impostazioni
- Notizie & aggiornamenti
- Strumenti
- Link esterni
- Sito web
- Manuale
- Domande Frequenti
- Donazione
- Politica sulla riservatezza
- Nessuna connessione Internet. Android non eseguirà la sincronizzazione.
- Benvenuto a DAVx⁵!\n\nÈ ora possibile aggiungere account CalDAV/CardDAV.
- La sincronizzazione automatica dell\'intero sistema è disabilitata
- Attiva
- Sincronizzazione di tutti gli account
-
- Fallita l\'individuazione dei servizi
- Impossibile aggiornare la lista delle raccolte
-
-
- Esecuzione in primo piano
- Su alcuni dispositivi, questo è necessario per la sincronizzazione automatica.
-
- Impostazioni
- Debug
- Mostra informazioni di debug
- Mostra e condividi i dettagli del programma e della configurazione
- Log completo
- Log attivo
- Log disabilitato
- Tenere in primo piano
- Può aiutare se il dispositivo impedisce la sincronizzazione automatica
- Connessione
- Sicurezza
- Autorizzazioni app
- Controlla le autorizzazioni per la sincronizzazione
- Non ti fidare dei certificati di sistema
- Le CA di sistema e quelle aggiunte dall\'utente non sono affidabili
- Le CA di sistema e quelle aggiunte dall\'utente sono affidabili (raccomandato)
- Reimposta la fiducia in tutti i certificati
- Reimposta la fiducia nei certificati aggiunti
- Sono stati cancellati tutti i certificati aggiunti
- Interfaccia utente
- Impostazioni di notifica
- Gestisci i canali di notifica e le loro impostazioni
- Seleziona il tema
-
- - Sistema predefinito
- - Luce
- - Buio
-
- Reimposta i suggerimenti
- Riabilita i suggerimenti precedentemente disabilitati
- I suggerimenti verranno mostrati
- Integrazione
- Funzioni dell\'applicazione
- Sincronizzazione con %s
- Nessuna applicazione compatibile con e funzionalità trovata
-
- CardDAV
- CalDAV
- Webcal
- I contatti non sono sincronizzati (autorizzazioni mancanti)
- Il calendario non è sincronizzato (autorizzazioni mancanti)
- Le attività non sono sincronizzate (autorizzazioni mancanti)
- Il calendario e le attività non sono sincronizzati (autorizzazioni mancanti)
- Impossibile leggere i calendari (autorizzazioni mancanti)
- Autorizzazioni
- Non ci sono rubriche indirizzi (ancora)
- Non ci sono calendari (ancora)
- Non ci sono sottoscrizioni a calendari (ancora)
- Scorri in basso per aggiornare la lista dal server
- Sincronizza adesso
- Sincronizzazione in corso
- Impostazioni account
- Rinomina account
- I dati locali non salvati potrebbero essere rimossi. È necessario effettuare la risincronizzazione dopo la rinomina. Nuovo nome dell\'account:
- Rinomina
- Impossibile rinominare l\'account
- Elimina account
- Cancellare l\'account?
- Tutte le copie locali delle rubriche, dei calendari e degli elenchi attività verranno eliminate.
- Sincronizza questa raccolta
- sola lettura
- calendario
- elenco attività
- Mostra solo personale
- Aggiorna elenco degli indirizzari
- Crea un nuovo indirizzario
- Aggiorna lista calendari
- Crea nuovo calendario
- Non ho trovato nessuna applicazione abilitata per Webcal
- Installa ICSx⁵
-
- Aggiungi account
- Accedi con indirizzo email
- Indirizzo email
- È necessario un indirizzo email valido
- Password
- Password richiesta
- Accedi con URL e nome utente
- L\'URL deve iniziare con http(s)://
- Nome utente
- Nome utente richiesto
- Base URL
- Accedi con URL e certificato client
- Seleziona certificato
- Login
- Crea account
- Nome account
- L\'utilizzo di apostrofi (\') potrebbe causare problemi su alcuni dispositivi.
- Inserisci il tuo indirizzo email come nome dell\'account in quanto Android userà il nome dell\'account nel campo ORGANIZER degli eventi creati. Non è possibile avere due account con nome uguale.
- Metodo del contact group:
- Richiesto il nome dell\'account
- Nome account già usato
- L\'account non può essere creato
- Login avanzato (utilizzo per casi speciali)
- Utilizza il nome utente/password
- Usa il certificato cliente
- Nessun certificato trovato
- Installa il certificato
- Rilevazione configurazione
- Attendere, invio richiesta al server…
- Impossibile trovare servizi CalDAV o CardDAV.
- Nome utente (indirizzo email) / password sbagliata?
- Visualizza dettagli
-
- Impostazioni: %s
- Sincronizzazione
- Intervallo sincr. Contatti
- Solo manualmente
- Ogni %d minuti e a seguito di ogni cambiamento locale
- Intervallo sincr. calendari
- Intervallo sincr. attività
-
- - Solo manualmente
- - Ogni 15 minuti
- - Ogni 30 minuti
- - Ogni ora
- - Ogni 2 ore
- - Ogni 4 ore
- - Una volta al giorno
-
- Sincr. solo tramite WiFi
- La sincronizzazione è limitata alle connessioni WiFi
- Il tipo di connessione non è preso in considerazione
- Restrizione SSID WiFi
- Sincronizzeremo solo oltre %s
- Sincronizzeremo solo oltre %s (richiede che i servizi di localizzazione siano attivi)
- Verranno utilizzate tutte le connessioni WIFI
- Nomi (SSID) delle reti WiFi autorizzate separati da virgola (lascia vuoto per autorizzarle tutte)
- Le restrizioni del SSID WIFI richiedono ulteriori impostazioni
- Riuscire
- Maggiori informazioni (FAQ)
- Autenticazione
- Nome utente
- Inserisci nome utente:
- Password
- Aggiorna la password come sul tuo server.
- Inserisci la tua password:
- Alias certificato cliente
- Nessun certificato selezionato
- CalDAV
- Limite di tempo per gli eventi trascorsi
- Verranno sincronizzati tutti gli eventi
-
- - Eventi più vecchi di un giorno saranno ignorati
- - Eventi più vecchi di %d giorni saranno ignorati
- - Eventi più vecchi di %d giorni saranno ignorati
-
- Eventi più vecchi di questo numero di giorni verranno ignorati(può anche essere 0). Lasciare in bianco per sincronizzare tutti gli eventi.
- Promemoria predefinito
-
- - Promemoria predefinito un minuto prima dell\'evento
- - Promemoria predefinito %d minuti prima dell\'evento
- - Promemoria predefinito %d minuti prima dell\'evento
-
- Nessun promemoria di default creato
- Indicare il numero di minuti che si desidera per il promemoria predefinito.
-Lasciare vuoto per non creare un promemoria predefinito.
- Cambia il colore del calendario
- I colori del calendario sono resettati ad ogni sincronizzazione
- I colori del calendario possono essere scelti da altre applicazioni
- Supporto colore dell\'evento
- I colori degli eventi sono sincronizzati
- I colori degli eventi non sono sicnronizzati
- CardDAV
- Organizzazione dei gruppi di contatto
-
- - I gruppi sono vCards separate
- - I gruppi sono categorie per ogni contatto
-
- Cambia il metodo del gruppo
-
- Crea rubrica
- La mia rubrica
- Crea calendario
- Fuso orario
- Possibili voci del calendario
- Eventi
- Attività
- Note / diario
- Combinato (eventi e attività)
- Colore
- Crea una raccolta
- Titolo
- Il titolo è richiesto
- Descrizione
- opzionale
- Percorso di archiviazione
- É richiesta una memoria di stoccaggio
- Crea
- Elimina raccolta
- Sei sicuro?
- Questa raccolta (%s) e tutti i suoi dati saranno rimossi permanentemente.
- Questi dati saranno cancellati dal server.
- Cancellazione della raccolta
- Forza sola lettura
- Proprietà
- Indirizzo (URL):
- Copia URL
- Possessore:
-
- Informazioni di debug
- Archivio ZIP
- Contiene informazioni sui debug e sugli accessi
- Condividi l\'archivio per trasferirlo ad un computer, per inviarlo tramite email o per fissarlo ad un ticket di supporto.
- Condividi l\'archivio
- Informazioni sul debug fissate a questo messaggio (richiede un supporto di fissaggio dell\'applicazione di supporto).
- Errore HTTP
- Errore del Server
- Errore WebDAV
- Errore I/O
- La richiesta è stata negata. Controlla le fonti coinvolte e le informazioni debug per dettagli.
- La fonte richiesta non esiste (più). Controlla le fonti coinvolte e le informazioni debug per dettagli.
- Si è verificato un problema del server. Per favore contatta il tuo server di supporto.
- Si è verificato un errore inaspettato. Vedi le informazioni di debug per maggiori dettagli.
- Vedi dettagli
- Sono state raccolte informazioni di debug
- Fonti coinvolte
- Collegate con il problema
- Fonti remote:
- Fonti locali:
- Vedi con l\'applicazione
- Registri
- Sono disponibili registri verbali
- Vedi i registri
-
- Si è verificato un errore.
- Si è verificato un errore HTTP.
- Si è verificato un errore di I/O.
- Mostra dettagli
-
-
- Installazioni WebDAV
- Quantità utilizzata: %1$s / disponibile: %2$s
- Condividi i contenuti
- Disinstallazioni
- Aggiungi installazioni WedDAV
- Accedi direttamente ai tuoi file nel cloud aggiungendo un supporto WebDAV!
- come funzionano i supporti WebDAV.]]>
- Nome del display
- URL WebDVA
- URL non valido
- Nome utente
- Password
- Aggiungi installazioni
- Nessun servizio WebDAV a questo URL
- File di accesso WebDAV
- File di download WebDAV
- Caricare file WebDAV
- Installazione WebDAV
-
- Autorizzazioni DAVx⁵
- Autorizzazioni addizionali richieste
- %s troppo vecchio
- Versione minima richiesta %1$s
- Autenticazione fallita (controlla credenziali login)
- Errore di rete o di I/O – %s
- Errore server HTTP – %s
- Errore di archiviazione locale – %s
- Riprova
- Visualizza oggetto
- Contatto non valido ricevuto dal server
- Evento non valido ricevuto dal server
- Attività non valida ricevuta dal server
- Una o più risorse non valide ignorate
-
- DAVx⁵: sicurezza della connessione
- DAVx⁵ ha trovato un certificato sconosciuto. Ritenerlo affidabile?
+
+ Gestore Account
+ Rubrica WebDav
+ Rubriche
+ Aiuto
+ Invia
+ Debug
+ Altri messaggi importanti
+ Sincronizzazione
+ Errori di sincronizzazione
+ Errori importanti che bloccano la sincronizzazione come le risposte inattese del server
+ Avvisi di sincronizzazione
+ Problemi di sincronizzazione non gravi come alcuni file non validi
+ Errori di Rete e di I/O
+ Timeout, problemi di connessione, ecc. (spesso temporanei)
+
+ Sincronizzazione automatica
+ Il firmware %s spesso blocca la sincronizzazione automatica. Nel caso, attiva la sincronizzazione automatica nelle impostazioni Android.
+ Sincronizzazione programmata
+ Il dispositivo bloccherà la sincronizzazione del Gestore Account. Per forzare intervalli di sincronizzazione regolari del Gestore Account, disabilita \"ottimizzazione batteria\".
+ Disabilita per il Gestore Account
+ Non mostrare più
+ Non adesso
+ Informazioni Open-Source
+ Siamo lieti che abbia scelto di utilizzare Gestore Account, un programma open-source (GPLv3). Dato che sviluppare Gestore Account è un impegno pesante che comporta migliaia di ore di lavoro, ti invitiamo a fare una donazione.
+ Mostra la pagina per donare
+ Forse più tardi
+ Più informazioni
+ OpenTasks non installata
+ Per sincronizzare le attività, occorre l\'app gratuita OpenTasks. (Non richiesta per contatti/eventi.)
+ Dopo l\'installazione di OpenTasks è necessario INSTALLARE NUOVAMENTE Account Manager e aggiungere di nuovo gli account (bug di Android).
+ Installa OpenTasks
+
+ Librerie
+ Versione %1$s (%2$d)
+ Compilato su %s
+ Questa versione può essere distribuita solo tramite Google Play.
+ Il programma è distribuito SENZA ALCUNA GARANZIA. È software libero e può essere redistribuito a certe condizioni.
+
+ Non riesco a creare il file di log
+ Log Account Manager
+ Ora sto registrando tutte le attività di %s
+ Invia log
+
+ Apri barra di navigazione
+ Chiudi barra di navigazione
+ Sync Adapter Calendario/Contatti
+ Informazioni / Licenza
+ Feedback sulla beta
+ Impostazioni
+ Notizie & aggiornamenti
+ Link esterni
+ Sito web
+ Manuale
+ FAQ
+ Aiuto / Forum
+ Dona
+ Benvenuto su Account Manager!
+\n
+\nOra è possibile aggiungere Calendari/Contatti.
+ La sincronizzazione automatica dell\'intero sistema è disabilitata
+ Attiva
+
+ Individuazione servizi non riuscita
+ Impossibile aggiornare l\'elenco delle raccolte
+
+ Impostazioni
+ Debug
+ Mostra informazioni di debug
+ Mostra/condividi i dettagli del software e della configurazione
+ Log dettagliato
+ Log attivo
+ Log disabilitato
+ Connessione
+ Sovrascrivi le impostazioni del proxy
+ Utilizza impostazioni personalizzate del proxy
+ Utilizza le impostazioni predefinite di sistema del proxy
+ Nome host del proxy HTTP
+ Porta del proxy HTTP
+ Sicurezza
+ Non ti fidare dei certificati di sistema
+ Le CA di sistema e quelle aggiunte dall\'utente non saranno ritenute affidabili
+ Le CA di sistema e quelle aggiunte dall\'utente saranno ritenute affidabili (raccomandato)
+ Reimposta la fiducia di tutti i certificati
+ Reimposta la fiducia dei certificati personali aggiunti
+ Sono stati cancellati tutti i certificati personali aggiunti
+ Interfaccia utente
+ Impostazioni di notifica
+ Gestisci i canali di notifica e le loro impostazioni
+ Reimposta i suggerimenti
+ Riabilita i suggerimenti precedentemente disabilitati
+ I suggerimenti verranno mostrati di nuovo
+
+ Contatti
+ Calendario
+ Webcal
+ Nessuna rubrica presente (per ora).
+ Nessun calendario presente (per ora).
+ Nessuna sottoscrizione a calendari presente (per ora).
+ Scorri verso il basso per aggiornare l\'elenco dal server.
+ Sincronizza adesso
+ Sincronizzazione in corso
+ Impostazioni account
+ Rinomina account
+ I dati locali non salvati potrebbero essere rimossi. È necessario ri-sincronizzare dopo la rinomina. Nuovo nome account:
+ Rinomina
+ Elimina account
+ Vuoi davvero eliminare l\'account\?
+ Verranno eliminate tutte le copie locali di rubriche, calendari e elenchi attività.
+ Sincronizza questa raccolta
+ sola lettura
+ calendario
+ elenco attività
+ Aggiorna elenco rubriche
+ Crea una nuova rubrica
+ Aggiorna l\'elenco dei calendari
+ Crea un nuovo calendario
+ Non ho trovato nessuna app valida per Webcal
+ Installa ICSx⁵
+
+ Aggiungi account
+ Accedi con un indirizzo email
+ Indirizzo email
+ E\' richiesto un indirizzo email valido
+ Password
+ Password richiesta
+ Accedi con URL e nome utente
+ L\'URL deve iniziare con http(s)://
+ L\'URL deve iniziare con https://
+ E\' richiesto un nome host
+ Nome utente
+ E\' richiesto un nome utente
+ Base URL
+ Accedi con URL e certificato client
+ Seleziona certificato
+ Accedi
+ Indietro
+ Aggiungi account
+ Nome account
+ Inserisci il tuo indirizzo email come nome account dato che Android utilizzerà il nome account per il campo ORGANIZER degli eventi che andrai a creare. Non è possibile avere due account con lo stesso nome.
+ Metodo del contact group:
+ E\' richiesto un nome account
+ Nome account già utilizzato
+ Esiste già un account con lo stesso nome
+ Aggiungi Account
+ Attendi, sto aggiungendo l\'account…
+ Accesso fallito. Verifica nome utente e password.
+ Visualizza dettagli
+
+ Impostazioni: %s
+ Sincronizzazione
+ Intervallo sincronizzazione Contatti
+ Solo manualmente
+ Ogni %d minuti e a seguito di ogni cambiamento locale
+ Intervallo sincronizzazione calendari
+ Intervallo sincronizzazione attività
+
+ - Solo manualmente
+ - Ogni 2 minuti
+ - Ogni 15 minuti
+ - Ogni 30 minuti
+ - Ogni ora
+ - Ogni 2 ore
+ - Ogni 4 ore
+ - Una volta al giorno
+
+ Sincronizza solo tramite WiFi
+ La sincronizzazione è limitata alle connessioni WiFi
+ Il tipo di connessione non è preso in considerazione
+ Restrizione SSID WiFi
+ Sincronizzerò solo con %s
+ Sincronizzerò solo con %s (richiede che siano attivi i servizi di geolocalizzazione)
+ Verranno utilizzate tutte le connessioni WIFI
+ Nomi (SSID) delle reti WiFi autorizzate separati da virgola (lascia vuoto per autorizzarle tutte)
+ Per leggere i nomi WiFi, sono richiesti permessi di Localizzazione e servizi di Localizzazione permanentemente attivi.
+ Maggiori informazioni (FAQ)
+ Autenticazione
+ Nome utente
+ Inserisci nome utente:
+ Password
+ Aggiorna la password come sul tuo server.
+ Inserisci la tua password:
+ Alias del certificato client
+ Calendario
+ Limite di tempo per gli eventi trascorsi
+ Verranno sincronizzati tutti gli eventi
+
+ - Eventi più vecchi di un giorno saranno ignorati
+ - Eventi più vecchi di %d giorni saranno ignorati
+
+ Gli eventi antecedenti a questo numero di giorni saranno ignorati (può anche essere 0). Lasciare vuoto per sincronizzare tutti gli eventi.
+ Gestisce i colori del calendario
+ I colori dei calendari sono gestiti da Account Manager
+ I colori del calendario non sono impostati da Gestore Account
+ Supporto colore dell\'evento
+ Sincronizza i colori dell\'evento
+ Non sincronizzare i colori dell\'evento
+ Contatti
+ Metodo di raggruppamento dei contatti
+ Cambia metodo di raggruppamento
+
+ Crea rubrica
+ La mia rubrica
+ Combinato (eventi e attività)
+ Crea una raccolta
+ E\' richiesto un titolo
+ Crea
+ Elimina raccolta
+ Sei sicuro?
+ Cancello la raccolta
+ Forza sola lettura
+
+ Si è verificato un errore.
+ Si è verificato un errore HTTP.
+ Si è verificato un errore di I/O.
+ Mostra dettagli
+
+ Informazioni di debug
+ Rubrica in sola lettura
+ Autorizzazioni Account Manager
+ Sono richiesti ulteriori permessi
+ OpenTasks troppo vecchio
+ Versione richiesta: %1$s (attualmente %2$s)
+ Autenticazione fallita (controlla le credenziali di accesso)
+
+ Account Manager: Sicurezza connessione
+ Account Manager ha rilevato un certificato sconosciuto. Vuoi ritenerlo affidabile\?
+ Informativa sulla privacy
+ /e/ invierà un modello di dispositivo fasullo a Google per proteggere la tua privacy.
+\nPuoi vedere quale su Attività Dispositivi di Google dopo aver effettuato l\'accesso.
+ ATTENZIONE
+ Sto ignorando una o più risorse non valide
+ Ricevuta attività non valida dal server
+ Ricevuto evento non valido dal server
+ Ricevuta chiamata non valida dal server
+ I Log sono allegati al messaggio (è necessario che l\'app ricevente supporti gli allegati).
+ Questi dati saranno eliminati dal server.
+ facoltativo
+ Note / vjournal
+ Attività
+ Eventi
+ E\' necessario un Fuso Orario
+ Nel caso in cui vengano creati dei promemoria predefiniti per gli eventi che ne sono senza: il numero di minuti prima dell\'evento. Lascia vuoto per disabilitare i promemoria predefiniti.
+ Non è stato creato alcun promemoria predefinito
+
+ - Promemoria predefinito un minuto prima dell\'evento
+ - Promemoria predefinito %d minuti prima dell\'evento
+
+ Promemoria predefinito
+ Nessuna connessione Internet. Android non avvierà la sincronizzazione.
+ Installa un Web Browser
+ Installa un client email
+ Vedi voce
+ Ritenta
+ Errore disco locale – %s
+ Errore server HTTP – %s
+ Errore di rete o di I/O – %s
+ Copia URL
+ Indirizzo (URL):
+ Proprietà
+ La raccolta (%s) e tutti i suoi dati saranno rimossi definitivamente.
+ Dove salvare
+ Descrizione
+ Titolo
+ Colore
+ Tipologie di calendario possibili
+ Fuso orario
+ Crea calendario
+ Aggiorna nome utente e password
+ Credenziali
+ Utilizza un server determinato
+ E\' richiesto un indirizzo URL del server valido
+ URL del server (https://server_url)
+ Utilizza un server personalizzato
+ Usa l\'ID e.email o murena.io per accedere:
+ Credenziali, frequenza di sincronizzazione, etc.
+ Rubrica Google
+ Rubrica /e/
+ /e/
+ Google
+ WebDAV
+ Accedi
+ Controlla la tua connessione a Internet
+ Inserisci l\'e-mail per ricevere l\'invito
+ L\'invito non è stato recapitato al tuo indirizzo e-mail a causa di un errore online.
+\n
+\nRiprova più tardi.
+\n
+\nNota: è anche possibile saltare questa procedura e aggiungere un account in un secondo momento nelle Impostazioni. In caso di difficoltà, contatta l\'assistenza.
+ Errore
+ Inserisci una email valida
+ Ritenta
+ Accedi
+ Salta
+ È già stato creato un account cloud con questo indirizzo e-mail. È possibile accedere con le tue credenziali.
+ Utente già attivo
+ Invia
+ Inserisci il tuo indirizzo e-mail per ricevere un invito a creare un ID murena.io gratuito con un account e-mail unico e personalizzato e uno spazio cloud individuale.
+ Imposta in seguito
+ Autenticati sul dispositivo
+ 1 - Adesso, da un altro dispositivo o computer, apri l\'e-mail di invito e completa la creazione dell\'account.
+\n
+\n2 - Quindi, torna in questa schermata e accedi con il tuo nuovo account murena.io.
+\n
+\nNote: Puoi anche saltare questo passaggio e aggiungere il tuo account in un secondo momento nelle Impostazioni.
+ Istruzioni
+ Invito inviato al tuo indirizzo e-mail. Se non lo hai ricevuto, controlla la cartella spam.
+ Puoi configurare un solo account ecloud sul tuo dispositivo
+ Panoramica dell\'Account /e/
+ Il mio Account
+ URL del Server (%s)
+ Crea Account
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 09c31e81e2185efffe73e81142832d523180a812..9fa98697837b188de6db4ff89c68b06cb362e814 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -1,12 +1,11 @@
- DAVx⁵
+ アカウントマネージャー
アカウントがありません
- DAVx⁵ アドレス帳
+ アカウントマネージャー アドレス帳
アドレス帳
ヘルプ
- アカウントの管理
デバッグ中
他の重要なメッセージ
同期
@@ -46,7 +45,7 @@
FAQ
寄付
インターネット接続がありません。 Android は同期を実行しません。
- DAVx⁵ にようこそ!\n\nCalDAV/CardDAV アカウントを追加できるようになりました。
+ アカウントマネージャー にようこそ!\n\nCalDAV/CardDAV アカウントを追加できるようになりました。
システム全体の自動同期が無効です
有効
@@ -118,7 +117,7 @@
URL とクライアント証明書でログイン
証明書を選択
ログイン
- アカウントを作成
+ アカウントを追加する
アカウント名
Android はあなたが作成した予定の ORGANIZER フィールドとしてアカウント名を使用するので、アカウント名としてメールアドレスを使用してください。同じ名前のアカウントを 2 つ持つことはできません。
連絡先グループ方法:
@@ -139,6 +138,7 @@
タスク同期間隔
- 手動のみ
+ - 2 分ごと
- 15 分ごと
- 30 分ごと
- 1 時間ごと
@@ -170,6 +170,8 @@
この日数より過去のイベントは無視されます (0 も可)。すべてのイベントを同期させるには、空白のままにしてください。
カレンダーの色を管理
+ カレンダーの色は アカウントマネージャー が管理します
+ カレンダーの色を アカウントマネージャー が設定しません
イベントカラーサポート
CardDAV
連絡先グループ方法
@@ -214,7 +216,7 @@
ユーザー名
パスワード
- DAVx⁵ アクセス許可
+ アカウントマネージャー アクセス許可
追加のアクセス許可が必要です
認証に失敗しました (ログイン情報を確認してください)
ネットワークまたは I/O エラー – %s
@@ -227,6 +229,6 @@
サーバーから無効なタスクを受信しました
1 または複数の無効なリソースを無視します
- DAVx⁵: 接続セキュリティ
- DAVx⁵は、未知の証明書を検出しました。それを信頼しますか?
+ アカウントマネージャー: 接続セキュリティ
+ アカウントマネージャーは、未知の証明書を検出しました。それを信頼しますか?
diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml
index ce2fe91179f23ed6eadbb2cf009af6bb3bb2c80e..13d325d134e7351d824ef3ba57334af9142dfa34 100644
--- a/app/src/main/res/values-nb-rNO/strings.xml
+++ b/app/src/main/res/values-nb-rNO/strings.xml
@@ -1,11 +1,10 @@
- DAVx⁵
- DAVx⁵-adressebok
+ Kontoadministrator
+ Kontoadministrator-adressebok
Adressebøker
Hjelp
- Behandle kontoer
Feilsøking
Andre viktige beskjeder
Synkronisering
@@ -38,7 +37,7 @@
O-S-S
Hjelp / Forum
Doner
- Velkommen til DAVx⁵.\n\nDu kan legge til en CalDAV/CardDAV-konto nå.
+ Velkommen til Kontoadministrator.\n\nDu kan legge til en CalDAV/CardDAV-konto nå.
Systemomspennende automatisk synkronisering avskrudd
Skru på
@@ -111,7 +110,7 @@
Brukernavn påkrevd
Landings-nettadresse
Logg inn
- Opprett konto
+ Legg til konto
Kontonavn
Bruk din e-postadresse som kontonavn fordi Android vil bruke kontonavnet som ORGANISATOR-felt for hendelser du oppretter. Du kan ikke ha to kontoer med samme navn.
Kontaktgruppemetode:
@@ -132,6 +131,7 @@
Gjøremålssynkroniseringsintervall
- Bare manuelt
+ - Hvert 2 minutter
- Hvert kvarter
- Hver halvtime
- Hver time
@@ -163,6 +163,8 @@
Hendelser som er mer enn dette antallet dager i fortid vil bli ignorert (kan være 0). La stå tomt for å synkronisere alle hendelser.
Velg kalenderfarger
+ Kalenderfarger behandles av Kontoadministrator
+ Kalenderfarger settes ikke av Kontoadministrator
Støtte for fargelegging av hendelser
CardDAV
Kontaktgruppemetode
@@ -201,7 +203,7 @@
En I/O-feil har inntruffet.
Vis detaljer
- DAVx⁵-tilganger
+ Kontoadministrator-tilganger
Ytterligere tilganger kreves
Nettverk- og I/O-feil - %s
HTTP-tjenerfeil - %s
@@ -209,6 +211,6 @@
Forsøk igjen
Fikk ugyldig kontakt fra server
- DAVx⁵: Tilkoblingssikkerhet
- DAVx⁵ har støtt på et ukjent sertifikat. Har du tiltro til det?
+ Kontoadministrator: Tilkoblingssikkerhet
+ Kontoadministrator har støtt på et ukjent sertifikat. Har du tiltro til det?
diff --git a/app/src/main/res/values-night-v27/styles.xml b/app/src/main/res/values-night-v27/styles.xml
new file mode 100644
index 0000000000000000000000000000000000000000..69e85b0e8105a4e829361482a7c52effe2d671f4
--- /dev/null
+++ b/app/src/main/res/values-night-v27/styles.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3eecf201626fa7cab371acb56d7f31a567662163
--- /dev/null
+++ b/app/src/main/res/values-night/colors.xml
@@ -0,0 +1,5 @@
+
+
+ #61ffffff
+ #BDFFFFFF
+
\ No newline at end of file
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 2714f02714eb198d69906d1e7c7750488ce3c9cc..1bbdd014befb4e22fbe4c905f2301af6e31493a6 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -1,419 +1,314 @@
-
+
-
- DAVx⁵
- Account bestaat niet (of niet meer)
- DAVx⁵ Adresboek
- Adresboeken
- Dit veld is verplicht
- Hulp
- Accounts beheren
- Delen
- Database beschadigd
- Alle accounts zijn lokaal verwijderd.
- Debuggen
- Andere belangrijke berichten
- Statusberichten met lage prioriteit
- Synchroniseren
- Synchronisatiefouten
- Belangrijke fouten die het synchroniseren stoppen, zoals onverwachte server antwoorden
- Synchronisatie waarschuwingen
- Niet-fatale problemen bij het synchroniseren zoals bepaalde ongeldige bestanden
- Netwerk en I/O fouten
- Timeouts, connectie problemen, etc. (vaak tijdelijk).
-
- Jouw gegevens, Jouw keuze
- Houd zelf de controle
- regelmatige sync-intervallen
- Uitgeschakeld (niet aanbevolen)
- Ingeschakeld (aanbevolen)
- Om op gezette tijden te synchroniseren moet %s zonder beperking op de achtergrond kunnen draaien. Anders kan Android het synchroniseren op elk moment onderbreken.
- Synchroniseren op gezette tijden is niet nodig.*
- %s compatibiliteit
- Waarschijnlijk blokkeert dit toestel het synchroniseren. In dat geval is dit alleen handmatig op te lossen.
- De vereiste instellingen zijn verricht. Er aan herinneren is niet meer nodig.*
- * Niet aanvinken om later herinnerd te worden. Kan teruggezet in app instellingen / %s.
- Meer informatie
- jtx Board
-
- Ondersteunt taken
- Als de server taken ondersteunt, synchroniseert een geschikte taken-app ze:
- OpenTasks
- extra apps nodig.]]>
- Taken
- worden (nog) niet ondersteund.]]>
- Geen app-store beschikbaar
- Er is geen taakondersteuning nodig.*
- Open-source software
- We zijn blij dat de keuze valt op open source software %s. Ontwikkelen, onderhouden en ondersteunen is veel werk. Overweeg daarom bij te dragen (kan op vele manieren) of een donatie. Wij waarderen het zeer!
- Hoe bijdragen/doneren
- In de nabije toekomst niet weergeven
-
- Rechten toestaan
- %s heeft rechten nodig om goed te werken.
- Alle onderstaande
- Gebruik dit om alle functies in te schakelen (aanbevolen)
- Alle rechten toegekend
- Contacten toestaan
- Geen contacten synchroniseren (niet aanbevolen)
- Contacten synchroniseren mogelijk
- Kalender machtigingen
- Geen kalenders synchroniseren (niet aanbevolen)
- Kalenders synchroniseren mogelijk
- jtx Board-rechten
- Geen taak-, kalender- en notitiesync (niet geïnstalleerd)
- Geen taak-, kalender- en notitiesync
- Taak-, kalender- en notitiesync mogelijk
- OpenTasks rechten
- Rechten voor taken
- Geen taak-sync (niet geïnstalleerd)
- Geen taak-sync
- Taak-sync mogelijk
- Rechten behouden
- Rechten kunnen automatisch worden teruggezet (niet aanbevolen)
- Rechten worden niet automatisch teruggezet
- Klik op App Rechten > vinkje uit bij \"Rechten intrekken\"
- Als een schakeloptie niet werkt, gebruik dan App-info / Rechten.
- App instellingen
-
- WiFi SSID rechten
- Voor toegang tot de huidige WiFi-naam (SSID), moet aan deze voorwaarden worden voldaan:
- Recht van toegang tot exacte locatie
- Toegang tot locatie verleend
- Toegang tot locatie geweigerd
- Toegang tot locatie op de achtergrond
- Onbeperkt toestaan
- %s]]>
- %s]]>
- %sgebruikt het locatie recht alleen om de huidige WiFi-SSID voor SSID-beperkte accounts te bepalen. Dit gebeurt zelfs als de app zich op de achtergrond bevindt. Locatiegegevens worden niet verzameld, opgeslagen, verwerkt of verzonden.
- Toegang tot locatie altijd ingeschakeld
- Toegang tot locatie is ingeschakeld
- Toegang tot locatie is uitgeschakeld
-
- Vertalingen
- Bibliotheken
- Versie%1$s (%2$d)
- Gecompileerd op %s
- © Ricki Hirner, Bernhard Stockmann (bitfire web engineering GmbH) en bijdragers
- Deze versie is enkel beschikbaar in Google Play
- Dit programma wordt geleverd met ABSOLUUT GEEN GARANTIE. Het is gratis software, en mag opnieuw worden verspreid onder bepaalde voorwaarden.
- Dank aan: %s]]>
-
- Kon geen logbestand aanmaken
- Logt nu alle %s activiteiten
- Bekijken/delen
- Uitschakelen
-
- Navigatiemenu openen
- Navigatielmenu sluiten
- CalDAV/CardDAV Sync adapter
- Over / Licentie
- Beta terugkoppeling
- E-mailprogramma is vereist
- Webbrowser is vereist
- Instellingen
- Nieuws & updates
- Gereedschap
- Externe links
- Website
- Handleiding
- FAQ
- Community
- Doneren
- Privacybeleid
- Geen internetverbinding. Android synchroniseert niet.
- Er is te weinig opslagruimte. Android zal niet synchroniseren.
- Welkom bij DAVx⁵!\n\nJe kunt nu een CalDAV/CardDAV account toevoegen.
- Automatisch synchroniseren is voor alle accounts uitgeschakeld
- Inschakelen
- Alle accounts synchroniseren
-
- Service herkenning is mislukt
- De collectielijst is niet bijgewerkt
-
- Kan niet op de voorgrond draaien
- Toestemming tot onbeperkt batterijgebruik is vereist
-
- Draait op de voorgrond
- Op sommige toestellen is dit nodig voor automatische synchronisatie.
-
- Instellingen
- Debuggen
- Debug-info
- Details over software en configuratie bekijken en delen
- Uitgebreid loggen
- Loggen is actief
- Loggen is niet actief
- Batterijoptimalisatie
- Onbeperkt batterijgebruik toestaan (aanbevolen)
- Beperkt batterijgebruik toestaan (niet aanbevolen)
- Op de voorgrond houden
- Kan helpen als automatische synchronisatie niet plaatsvindt
- Verbinding
- Proxy type
-
- - Systeem standaard
- - Geen proxy
- - HTTP
- - SOCKS (voor Orbot)
-
- Proxy host naam
- Proxy poort
- Beveiliging
- App rechten
- De vereiste rechten om te synchroniseren controleren
- Wantrouw systeemcertificaten
- Door systeem en gebruiker toegevoegde CA certificaten niet vertrouwen
- Door systeem en gebruiker toegevoegde CA certificaten vertrouwen (aanbevolen)
- (Niet-)vertrouwde certificaten terugzetten
- Herstelt het vertrouwen van alle aangepaste certificaten
- Alle aangepaste certificaten zijn gewist
- Gebruikersinterface
- App-meldingen
- Meldingskanalen en hun instellingen beheren
- Thema selecteren
-
- - Systeem standaard
- - Licht
- - Donker
-
- Hints opnieuw instellen
- Hints die al gezien zijn opnieuw weergeven
- Alle hints opnieuw weergeven
- Integratie
- Taken app
- Synchroniseren met %s
- Geen compatibele taken app gevonden
-
- CardDAV
- CalDAV
- Webcal
- Geen contacten synchronisatie (ontbrekende rechten)
- Geen kalender synchronisatie (ontbrekende rechten)
- Geen taken synchronisatie (ontbrekende rechten)
- Geen synchronisatie van kalender en taken (ontbrekende rechten)
- Geen toegang tot kalenders (ontbrekende rechten)
- Rechten
- Er zijn (nog) geen adresboeken.
- Er zijn (nog) geen kalenders.
- Er zijn (nog) geen kalender abonnementen.
- Omlaag vegen om de lijst van de server te actualiseren.
- Nu synchroniseren
- Synchroniseert…
- Account instellingen
- Naam account wijzigen
- Niet opgeslagen lokale gegevens kunnen verloren gaan. Synchroniseren is vereist na verandering van naam. Nieuwe accountnaam:
- Naam wijzigen
- Naam account is niet gewijzigd
- Account verwijderen
- Account echt verwijderen?
- Alle lokale kopieën van adresboeken, kalenders en takenlijsten worden verwijderd.
- deze collectie synchroniseren
- alleen-lezen
- kalender
- takenlijst
- logboek
- Alleen persoonlijk tonen
- Adresboeken vernieuwen
- Nieuw adresboek maken
- Kalenders bijwerken
- Nieuwe kalender maken
- Geen Webcal-app gevonden
- ICSx⁵ installeren
-
- Account toevoegen
- Inloggen met e-mailadres
- E-mailadres
- Geldig e-mailadres vereist
- Wachtwoord
- Wachtwoord vereist
- Inloggen met URL en gebruikersnaam
- URL moet met http(s):// beginnen
- Gebruikersnaam
- Gebruikersnaam vereist
- Basis-URL
- Login met URL en client certificaat
- Certificaat selecteren
- Login
- Account aanmaken
- Accountnaam
- Het gebruik van apostrofs (\') heeft op sommige apparaten problemen veroorzaakt.
- Gebruik het eigen e-mailadres als accountnaam, want Android gebruikt het als ORGANIZER veld voor gebeurtenissen. Twee accounts met hetzelfde adres kan niet.
- Methode voor contact-groepen:
- Accountnaam verplicht
- Accountnaam is al in gebruik
- Account aanmaken lukt niet.
- Geavanceerde login (speciale gevallen)
- Gebruikersnaam/wachtwoord gebruiken
- Cliëntcertificaat gebruiken
- Geen certificaat gevonden
- Certificaat installeren
- Configuratie detecteren
- Even geduld, verzoek naar server…
- Geen CalDAV- of CardDAV-service gevonden.
- Is gebruikersnaam (e-mailadres) / wachtwoord verkeerd?
- Details weergeven
-
- Instellingen: %s
- Synchronisatie
- Contacten synchronisatie interval
- Alleen handmatig
- Elke %d minuten + direct bij lokale veranderingen
- Kalenders bijwerken
- Taken synchronisatie-interval
-
- - Handmatig
- - Elke 15 minuten
- - Elke 30 minuten
- - Elk uur
- - Elke 2 uur
- - Elke 4 uur
- - Eenmaal daags
-
- Synchronisatie beperken tot WiFi
- Alleen verbinden via WiFi
- Type verbinding is niet relevant
- Tot bepaalde WiFi-SSID beperken
- Synchronisatie alleen via %s
- Alleen via %s (Altijd toegang tot locatie toestaan)
- Elke WiFI-SSID toestaan
- Door komma\'s gescheiden namen (SSID\'s) van toegestane WiFi-netwerken (laat leeg voor alle)
- Beperking WiFi-SSID vereist verdere instellingen
- Beheren
- Meer informatie (FAQ)
- Verificatie
- Gebruikersnaam
- Gebruikersnaam invoeren:
- Wachtwoord
- Gebruik het zelfde wachtwoord als op de server.
- Wachtwoord invoeren:
- Cliënt-certificaat alias
- Geen certificaat geselecteerd
- CalDAV
- Gebeurtenissen in verleden tijd
- Worden alle gesynchroniseerd
-
- - Afspraken ouder dan een dag worden genegeerd
- - Ouder dan %d dagen worden genegeerd
-
- Gebeurtenissen ouder dan ingevuld aantal dagen worden genegeerd (mag 0 zijn). Veld leeg laten om alle te synchroniseren.
- Standaardherinnering
-
- - Standaardherinnering één minut voor het evenement
- - %d minuten voor aanvang gebeurtenis
-
- Wordt niet aangemaakt
- Vul het gewenste aantal minuten in. Leeg laten om herinneringen uit te schakelen.
- Kalender kleuren beheren
- Worden bij elke sync teruggezet
- Kunnen door andere apps worden ingesteld
- Gebeurtenis kleuren ondersteunen
- Worden gesynchroniseerd
- Worden niet gesynchroniseerd
- CardDAV
- Methode voor contact-groepen:
-
- - Groepen zijn afzonderlijke vCards
- - Groepen zijn categorieën per contact
-
- Verander de methode voor contact-groepen
-
- Adresboek aanmaken
- Mijn adresboek
- Kalender aanmaken
- Tijdzone
- Mogelijke kalender-items
- Gebeurtenissen
- Taken
- Notities / Dagboek
- Gecombineerd (afspraken en taken)
- Kleur
- Maakt collectie aan
- Titel
- Titel is verplicht
- Beschrijving
- optioneel
- Opslaglocatie
- Opslaglocatie is verplicht
- Aanmaken
- Collectie verwijderen
- Inderdaad verwijderen?
- Deze collectie (%s) wordt met alle gegevens blijvend verwijderd.
- Deze gegevens worden verwijderd van de server
- Verwijdert collectie
- Forceer alleen-lezen
- Eigenschappen
- Adres (URL):
- URL kopiëren
- Eigenaar:
-
- Debug informatie
- ZIP archief
- Bevat debuginformatie en logbestanden
- Deel het archief om over te zetten naar een computer, per e-mail te verzenden of als bijlage bij een supportticket te voegen..
- Archief delen
- Debug info als bijlage bij dit bericht (vereist ondersteuning voor bijlagen van de ontvangende app).
- HTTP-fout
- Serverfout
- WebDAV fout
- I/O-fout
- Het verzoek is afgewezen. Controleer de betrokken bronnen en debug-info voor details.
- De gevraagde bron bestaat niet (meer). Controleer de betrokken bronnen en debug-info voor details.
- Er is bij de server een probleem opgetreden. Neem contact op met de server-ondersteuning.
- Er is een onverwachte fout opgetreden. Bekijk debug-info voor details.
- Details bekijken
- Debug-info is verzameld
- Betrokken bronnen
- Gerelateerd aan het probleem
- Externe bron:
- Lokale bron:
- Met app bekijken
- Logboeken
- Uitgebreide logboeken zijn beschikbaar
- Details bekijken
-
- Er is een fout opgetreden.
- Een HTTP-fout is opgetreden.
- Een I/O fout is opgetreden.
- Details weergeven
-
- Synchroniseren is onderbroken
- Bijna geen vrije ruimte meer
-
- WebDAV-koppelingen
- Quotum gebruikt: %1$s / Beschikbaar: %2$s
- Inhoud delen
- Ontkoppelen
- WebDAV-koppeling toevoegen
- Verkrijg directe toegang tot cloudbestanden met een WebDAV-koppeling!
- het koppelen van WebDAV.]]>
- Weergavenaam
- WebDAV-URL
- Ongeldige URL
- Gebruikersnaam
- Wachtwoord
- Koppeling toevoegen
- Geen WebDAV-service op deze URL
- WebDAV-bestand openen
- WebDAV-bestand downloaden
- WebDAV-bestand uploaden
- WebDAV-koppeling
-
- DAVx⁵ rechten
- Aanvullende rechten vereist
- %ste oud
- Minimaal vereiste versie: %1$s
- Verificatie mislukt (controleer aanmeldingsgegevens)
- Netwerk of I/O error - %s
- HTTP-server fout - %s
- Lokale opslag fout - %s
- Opnieuw
- Item bekijken
- Ongeldig contact ontvangen van server
- Ongeldige gebeurtenis ontvangen van server
- Ongeldige taak ontvangen van server
- Een of meer ongeldige bronnen negeren
-
- DAVx⁵: Beveiliging van de verbinding
- DAVx⁵ is een onbekend certificaat tegengekomen. Moet het vertrouwd worden?
+
+ Account Manager
+ WebDav Adresboek
+ Adresboeken
+ Help
+ Verzenden
+ Debuggen
+ Andere belangrijke berichten
+ Synchronisatie
+ Synchronisatie fouten
+ Belangrijke fouten die de synchronisatie stoppen zoals onverwachte server antwoorden
+ Synchronisatie waarschuwingen
+ Niet-fatale synchronisatie problemen zoals bepaalde ongeldige bestanden
+ Netwerk en I/O fouten
+ Time-outs, connectie problemen, etc. (vaak tijdelijk)
+
+ Automatische synchronisatie
+ %s firmware blokkeert vaak automatische synchronisatie. In dit geval, sta automatische synchronisatie toe in jouw Android instellingen.
+ Geplande synchronisatie
+ Jouw apparaat zal Account Manager synchronisatie beperken. Om voor Account Manager een regelmatig sync interval af te dwingen, schakel \"batterij optimalisatie\" uit.
+ Zet deze optie uit voor Account Manager
+ Niet opnieuw weergeven
+ Niet nu
+ Open source informatie
+ We zijn blij dat je Account Manager gebruikt, wat open source software (GPLv3) is. Omdat de ontwikkeling van Account Manager hard werk is en duizenden uren in beslag neemt, overweeg alstublieft een donatie.
+ Toon donatie pagina
+ Misschien later
+ Meer informatie
+ OpenTasks niet geinstalleerd
+ De gratis app OpenTasks is vereist om taken te kunnen synchroniseren. (Niet nodig voor contacten/evenementen)
+ Na installatie van OpenTasks dient u Account Manager opnieuw te installeren en de accounts toe te voegen (Android bug).
+ OpenTasks installeren
+
+ Bibliotheken
+ Versie %1$s (%2$d)
+ Gecompileerd op %s
+ Deze versie is enkel beschikbaar via Google Play.
+ Dit programma kom met ABSOLUUT GEEN GARANTIE. Het is gratis software, en je bent welkom dit te her-distribueren onder bepaalde voorwaarden.
+
+ Kon de log file niet creëren
+ Account Manager log
+ Op dit moment worden alle %s activiteiten gelogd
+ Verstuur het log
+
+ Open navigatie menu
+ Sluit navigatie menu
+ Contacten/Kalender Sync adapter
+ Over / Licentie
+ Beta feedback
+ Instellingen
+ Nieuws & updates
+ Externe links
+ Website
+ Manueel
+ FAQ
+ Hulp / Forums
+ Doneren
+ Welkom bij Account Manager!
+\n
+\nJe kunt nu een contacten/kalender account toevoegen.
+ Globale automatische synchronisatie is uitgeschakeld
+ Inschakelen
+
+ Service herkenning is mislukt
+ Kon de collectie lijst niet vernieuwen
+
+ Instellingen
+ Debuggen
+ Debug info tonen
+ Bekijk/deel software en configuratie details
+ Uitvoerig/expliciet loggen
+ Loggen is actief
+ Loggen is geactiveerd
+ Verbinding
+ Proxy instellingen overschrijven
+ Eigen proxy instellingen gebruiken
+ Systeem proxy instellingen gebruiken
+ HTTP proxy beheerder naam
+ HTTP proxy poort
+ Beveiliging
+ Systeem certificaten niet vertrouwen
+ Systeem en CA\'s van toegevoegde gebruiker wordt niet vertrouwd
+ Systeem en door gebruiker toegevoegde CA\'s worden vertrouwd (aanbevolen)
+ Reset (niet) vertrouwde certificaten
+ Reset alle vertrouwde zelf aangemaakte certificaten
+ Alle zelf aangemaakte certificaten zijn verwijderd
+ Gebruikers interface
+ Notificatie instellingen
+ Beheer de notificatie kanalen en hun instellingen
+ Hints resetten
+ Hints die al bekeken zijn opnieuw weergeven
+ Alle hints worden opnieuw weergegeven
+
+ Contacten
+ Kalender
+ Webcal
+ Er zijn (nog) geen adresboeken.
+ Er zijn (nog) geen kalenders.
+ Er zijn (nog) geen kalender inschrijvingen.
+ Swipe naar beneden om de lijst van servers te vernieuwen.
+ Nu synchroniseren
+ Aan het synchroniseren
+ Account instellingen
+ Account hernoemen
+ Niet opgeslagen lokale informatie mag verloren gaan. Synchronisatie is noodzakelijk na hernoemen. Nieuw account naam:
+ Hernoemen
+ Account verwijderen
+ Account echt verwijderen?
+ Alle lokale kopieën van adresboeken, agenda\'s en taken worden verwijderd.
+ synchroniseer deze collectie
+ alleen-lezen
+ kalender
+ taken lijst
+ Vernieuw lijst adresboeken
+ Maak een nieuw adresboek
+ Kalenders vernieuwen
+ Maak een nieuwe kalender
+ Geen Webcal ondersteunende app gevonden
+ Installeer ICSx⁵
+
+ Account toevoegen
+ Inloggen met e-mailadres
+ Email adres
+ Geldig e-mailadres vereist
+ Wachtwoord
+ Wachtwoord vereist
+ Inloggen met URL en gebruikersnaam
+ URL moet met http(s):// beginnen
+ URL moet beginnen met https://
+ Host naam vereist
+ Gebruikersnaam
+ Gebruikersnaam vereist
+ Basis URL
+ Inloggen met URL en cliënt certificaat
+ Selecteer certificaat
+ Inloggen
+ Terug
+ Account toevoegen
+ Accountnaam
+ Gebruik je email adres als account naam want Android zal je account naam gebruiken als ORGANIZER veld voor gemaakte afspraken. Je kunt geen 2 accounts met dezelfde naam hebben.
+ Contact groep methode:
+ Accountnaam vereist
+ Account naam is al in gebruik
+ Er bestaat al een account met deze naam
+ Voeg account toe
+ Even geduld, account aan het toevoegen…
+ Inloggen mislukt. Controleer uw gebruikersnaam en wachtwoord.
+ Toon details
+
+ Instellingen: %s
+ Synchronisatie
+ Contacten synchronisatie interval
+ Alleen handmatig
+ Elke %d minuten + meteen na lokale wijzigingen
+ Kalenders verversen
+ Taak synchronisatie interval
+
+ - Enkel handmatig
+ - Iedere 15 minuten
+ - Iedere 30 minuten
+ - Ieder uur
+ - Iedere 2 uur
+ - Iedere 4 uur
+ - Eenmaal daags
+
+ Sync alleen tijdens WiFi
+ Synchronisatie gebeurd enkel tijdens WiFi verbindingen
+ Verbinding type is niet overwogen
+ WiFi SSID restrictie
+ Zal alleen synchroniseren over %s
+ Sync alleen over %s (vereist actieve locatie services)
+ Alle WiFI verbindingen zullen worden gebruikt
+ komma gescheiden namen (SSID\'s) van toegestane WiFi netwerken (leeg laten voor alles)
+ Om WIFI namen te lezen, zijn de locatie toestemming en permanent toegestane locatie services vereist.
+ Meer informatie (Veel gestelde vragen)
+ Authenticatie
+ Gebruikersnaam
+ Gebruikersnaam invoeren:
+ Wachtwoord
+ Gebruik hetzelfde wachtwoord als op de server.
+ Wachtwoord invoeren:
+ Cliënt certificaat alias
+ Kalender
+ Tijdslimiet voor evenementen in het verleden
+ Alle afspraken worden gesynchroniseerd
+
+ - Afspraken ouder dan een dag worden genegeerd
+ - Afspraken ouder dan %d dagen worden genegeerd
+
+ Afspraken ouder dan dit aantal dagen worden genegeerd (mag 0 zijn). Laat leeg om alle afspraken te synchroniseren.
+ Kalender kleuren beheren
+ Kalender kleuren worden door Account Manager beheerd
+ Kalender kleuren worden niet door Account Manager ingesteld
+ Evenement kleur ondersteuning
+ Evenement kleuren synchroniseren
+ Evenement kleuren niet synchroniseren
+ Contacten
+ Contact groep methode
+ Verander de groepering methode
+
+ Maak adresboek
+ Mijn adresboek
+ Creëer kalender
+ Tijdzone
+ Tijdzone benodigd
+ Mogelijke kalender items
+ Evenementen
+ Taken
+ Notities/Dagboek
+ Gecombineerd (afspraken en taken)
+ Kleur
+ Collectie aan het maken
+ Titel
+ Titel is vereist
+ Omschrijving
+ Optioneel
+ Opslag locatie
+ Maak
+ Verwijder collectie
+ Weet je het zeker?
+ Deze collectie (%s) en alle bijbehorende data zal permanent verwijderd worden.
+ Deze data zal verwijderd worden van de server.
+ Collectie aan het verwijderen
+ Alleen-lezen afdwingen
+ Eigenschappen
+ Adres (URL):
+ Kopieer URL
+
+ Er is een fout opgetreden.
+ Er is een HTTP fout opgetreden.
+ Er is een I/O fout opgetreden.
+ Toon details
+
+ Debug informatie
+ Logs worden toegevoegd aan dit bericht (vereist bijlage support van de ontvangende app).
+ Alleen-lezen adresboek
+ Account Manager machtigingen
+ Aanvullende machtigingen vereist
+ OpenTasks te oud
+ Vereiste versie: %1$s (momenteel %2$s)
+ Authenticatie mislukt (controleer Inloggegevens)
+ Netwerk of I/O fout – %s
+ HTTP server fout – %s
+ Lokale opslag fout – %s
+ Probeer opnieuw
+ Bekijk item
+ Ongeldig contact ontvangen van server
+ Ongeldig evenement ontvangen van server
+ Ongeldige taak ontvangen van server
+ Een of meerdere ongeldige bronnen worden genegeerd
+
+ Account Manager: Verbinding beveiliging
+ Account Manager heeft een onbekend certificaat aangetroffen. Wilt u deze vertrouwen\?
+ Geen internet verbinding, Android zal geen synchronisatie uitvoeren.
+ Privacybeleid
+ Gelieve een Web browser te installeren
+ Gelieve een e-mail toepassing te installeren
+ Inloggegevens, sync frequentie enz...
+ Google Adresboek
+ /e/ Adresboek
+ /e/
+ Google
+ Wanneer er een standaard herinnering moet gemaakt worden voor elementen zonder herinnering: Het gewenste aantal minuten voor aanvang van het evenement. Leeg laten om standaard herinnering uit te schakelen.
+ WebDAV
+ /e/ zal een nep apparaat model aan Google rapporteren om jouw privacy te beschermen.
+\nJe kan bekijken welk model op Toestel Activiteit van Google nadat je bent ingelogd.
+ WAARSCHUWING
+ Geen standaard herinneringen aangemaakt
+
+ - Standaard herinnering één minuut voor het evenement
+ - Standaard herinnering %d minuten voor het evenement
+
+ Standaard herinnering
+ Update gebruikersnaam en wachtwoord
+ Inloggegevens
+ Gebruik een specifieke server
+ Een geldig server URL adres is vereist
+ Server URL (https://server_url)
+ Gebruik eigen server
+ Gebruik je e.email of murena.io ID om in te loggen:
+ Account aanmaken
+ Je kan enkel één ecloud account configureren op je toestel
+ Mijn Account
+ /e/ Account overzicht
+ Instructies
+ Uitnodiging is verstuurd naar je email. Indien je niets hebt ontvangen, kijk dan a.u.b. in je spam map.
+ Aanmelden op dit toestel
+ later instellen
+ 1 - Open nu op een ander toestel of computer de uitnodigingsmail om de aanmaak van je account te voltooien.
+\n
+\n2 - Daarna, kom terug naar dit scherm en log in met je nieuwe murena.io account.
+\n
+\nOpmerking: Je kan deze stap overslaan en later een account toevoegen in de Instellingen.
+ Vul uw email adres in om een uitnodiging to ontvangen voor je gratis murena.io ID met een uniek en persoonlijk email account en cloud opslagruimte.
+ Verzenden
+ Gebruiker bestaat al
+ Er is al een cloud account aangemaakt met dit email adres. Je kan nu inloggen met je inloggegevens.
+ Overslaan
+ Inloggen
+ Opnieuw proberen
+ Geef a.u.b. een geldige email
+ Fout
+ Kijk a.u.b. je internet verbinding na
+ Vul email in om een uitnodiging te ontvangen
+ Inloggen
+ De uitnodiging kon niet verstuurd worden door een interne systeem fout.
+\n
+\nProbeer het a.u.b. later opnieuw.
+\n
+\nOpmerking: je kan deze stap ook overslaan en later een account toevoegen in de Instellingen. Contacteer support in geval van problemen.
+ Server URL (%s)
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index de5e86fed9a071fdcedc6c589ad08ce21e0e618d..bf448198ae6829ab29995489a957d18e591a105b 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -1,13 +1,14 @@
- DAVx⁵
+ Menadżer konta
Konto (już) nie istnieje
- Książka adresowa DAVx⁵
+ Książka adresowa Menadżer konta
Książka adresowa
+ Usuń
+ Anuluj
To pole jest wymagane
Pomoc
- Zadządzaj kontami
Udostępnij
Uszkodzona baza danych
Wszystkie konta zostały usunięte lokalnie.
@@ -123,7 +124,7 @@
Polityka prywatności
Brak połączenia z Internetem. Android nie wykona synchronizacji.
Za mało miejsca do przechowywania. Android nie uruchomi synchronizacji.
- Witamy w DAVx⁵!\n\nMożesz teraz dodać konto CalDAV/CardDAV.
+ Witamy w Menadżer konta!\n\nMożesz teraz dodać konto CalDAV/CardDAV.
Automatyczna synchronizacja dla całego systemu jest wyłączona
Włącz
Synchronizuj wszystkie konta
@@ -235,7 +236,7 @@
Logowanie za pomocą adresu URL i certyfikatu klienta
Wybierz certyfikat
Zaloguj
- Stwórz konto
+ Dodaj konto
Nazwa konta
Zgłoszono, że użycie apostrofów (\') powoduje problemy na niektórych urządzeniach.
Użyj swojego adresu e‑mail jako nazwy konta, ponieważ Android będzie używał nazwy konta jako pola ORGANIZATOR dla wydarzeń, które stworzysz. Nie możesz posiadać dwóch kont o takiej samej nazwie.
@@ -263,6 +264,7 @@
Częstotliwość synchronizacji list zadań
- Tylko ręcznie
+ - Co 2 minuty
- Co 15 minut
- Co 30 minut
- Co godzinę
@@ -309,8 +311,8 @@
Nie utworzono przypomnień domyślnych
Jeżeli domyślne przypomnienia mają być utworzone dla zdarzeń bez przypomnienia: pożądana liczba minut przed zdarzeniem. Pozostaw puste aby wyłączyć domyślne przypomnienia.
Zarządzaj kolorami kalendarza
- Kolory kalendarza są resetowane przy każdej synchronizacji
- Kolory kalendarza mogą być ustawiane przez inne aplikacje
+ Kolory kalendarza są zarządzane przez Menadżer konta
+ Kolory kalendarze nie są ustawiane przez Menadżer konta
Obsługa kolorów wydarzeń
Kolory wydarzeń są zsynchronizowane
Kolory wydarzeń nie są zsynchronizowane
@@ -398,12 +400,14 @@
Hasło
Dodaj link
Brak usługi WebDAV pod tym URL
+ Usuń punkt montowania
+ Szczegóły połączenia zostaną utracone, ale żadne pliki nie będą usunięte.
Uzyskiwanie dostępu do pliku WebDAV
Pobieranie pliku WebDAV
Wgrywanie pliku WebDAV
Punkt linkowania WebDAV
- Uprawnienia DAVx⁵
+ Uprawnienia Menadżer konta
Wymagane dodatkowe uprawnienia
%s zbyt stary/a
Minimalna wymagana wersja: %1$s
@@ -418,6 +422,6 @@
Otrzymano błędne zadanie z serwera
Zignorowano jeden lub więcej nieważnych zasobów
- DAVx⁵: Bezpieczeństwo połączenia
- DAVx⁵ napotkał nieznany certyfikat. Czy chcesz go dodać?
+ Menadżer konta: Bezpieczeństwo połączenia
+ Menadżer konta napotkał nieznany certyfikat. Czy chcesz go dodać?
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..712a1b25dfe960f593c9f40b22209f743d7e24c6
--- /dev/null
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,269 @@
+
+
+
+ Gerente de contas
+ Livro de endereços Gerente de contas
+ Livros de endereços
+ Ajuda
+ Enviar
+ Depuração
+ Outras mensagens importantes
+ Sincronização
+ Erros de sincronização
+ Erros importantes que interrompem a sincronização, como respostas inesperadas do servidor
+ Avisos de sincronização
+ Problemas de sincronização não graves, como determinados arquivos inválidos
+ Erros de rede e E/S
+ Tempos de espera, problemas de conexão, etc. (geralmente temporários)
+
+ Sincronização automática
+ O firmware%s frequentemente bloqueia a sincronização automática. Nesse caso, ative a sincronização automática nas configurações do seu Android.
+ Sincronização agendada
+ Seu aparelho irá restringir a sincronização do Gerente de contas. Para forçar a sincronização do Gerente de contas em intervalos regulares, desligue a \"otimização da bateria\".
+ Desligar para o Gerente de contas
+ Não mostrar novamente
+ Não agora
+ Informação sobre Código Aberto
+ Estamos felizes que você usa o Gerente de contas, um software de código aberto (GPLv3). O desenvolvimento do Gerente de contas é trabalhoso e consome muitas horas de trabalho. Por esse motivo, considere fazer uma doação.
+ Mostrar a página de doações
+ Talvez depois
+ Mais informações
+ O OpenTasks não está instalado
+ Para sincronizar tarefas é necessário instalar o aplicativo livre OpenTasks. (Não é necessário para contatos/eventos)
+ Depois da instalação do OpenTasks, torna-se necessário REINSTALAR o Gerente de contas e adicionar suas contas novamente (erro do Android).
+ Instalar o OpenTasks
+
+ Bibliotecas
+ Versão %1$s (%2$d)
+ Compilado em %s
+ Esta versão só é elegível para distribuição na Google Play.
+ Este programa é distribuído SEM NENHUMA GARANTIA. Ele é software livre e pode ser redistribuído sob algumas condições.
+
+ Não foi possível criar o arquivo de log
+ Log do Gerente de contas
+ Enviar log
+
+ Abrir a gaveta de navegação
+ Fechar gaveta de navegação
+ Sincronização de CalDAV/CardDAV
+ Sobre / Licença
+ Comentários sobre a versão beta
+ Instale um cliente de e-mail
+ Instale um navegador Web
+ Configurações
+ Novidades e atualizações
+ Links externos
+ Site na Web
+ Manual
+ Perguntas fequentes
+ Ajuda / Fóruns
+ Doações
+ Política de privacidade
+ Sem conexão com a Internet. O Android não executará a sincronização.
+ Bem-vindo ao Gerente de contas!\n\nVocê pode adicionar uma conta CalDAV/CardDAV agora.
+ A sincronização automática pelo sistema está desativada
+ Ativar
+
+ Falha na detecção do serviço
+ Não foi possível atualizar a lista da coleção
+
+ Configurações
+ Depuração
+ Mostrar informações de depuração
+ Exibe/compartilha o software e os detalhes da configuração
+ Registro de atividades detalhado
+ Registro de atividades ativo
+ Registro de atividades desativado
+ Conexão
+ Substituir as configurações de proxy
+ Usar configurações de proxy personalizadas
+ Usar configurações de proxy padrão do sistema
+ Nome do servidor proxy HTTP
+ Porta do proxy HTTP
+ Segurança
+ Desconfiar dos certificados de sistema
+ ACs adicionadas pelo usuário e pelo sistema não serão confiáveis
+ ACs adicionadas pelo usuário e pelo sistema serão confiáveis (recomendado)
+ Restaurar certificados não-confiáveis
+ Restaura a confiança de todos os certificados personalizados
+ Todos os certificados personalizados foram restaurados
+ Interface de usuário
+ Configurações das notificações
+ Gerenciar os canais de notificação e suas configurações
+ Restaurar sugestões
+ Restaura as sugestões que foram descartadas anteriormente
+ Todas as sugestões serão exibidas novamente
+
+ CardDAV
+ CalDAV
+ Webcal
+ Não há livros de endereços (ainda).
+ Não há calendários (ainda).
+ Não há assinaturas de calendário (ainda).
+ Deslize para baixo para atualizar a lista do servidor.
+ Sincronizar agora
+ Sincronizando
+ Configurações da conta
+ Renomear conta
+ Dados locais que não foram salvos podem ser descartados. É necessário efetuar uma nova sincronização após renomear. Novo nome da conta:
+ Renomear
+ Excluir conta
+ Deseja excluir a conta?
+ Todas as cópias locais dos livros de endereços, calendários e listas de tarefas serão excluídas.
+ sincronizar esta coleção
+ Somente leitura
+ calendário
+ lista de tarefas
+ Atualizar lista de livros de endereços
+ Criar novo livro de endereços
+ Atualizar lista de calendários
+ Criar novo calendário
+ Não foi encontrado um aplicativo capaz de lidar com Webcal
+ Instalar ICSx⁵
+
+ Adicionar conta
+ Autenticação com endereço de e-mail
+ Endereço de e-mail
+ É necessário um e-mail válido
+ Senha
+ É necessário uma senha
+ Autenticação com usuário e URL
+ A URL deve começar com http(s)://
+ A URL deve começar com https://
+ É necessário um nome de máquina
+ Usuário
+ É necessário um nome de usuário
+ URL base
+ Autenticação com URL e certificado do cliente
+ Selecionar certificado
+ Autenticar
+ Voltar
+ Adicionar conta
+ Nome da conta
+ Use seu endereço de e-mail como nome da conta porque o Android irá usar esse nome como campo AGENDA nos eventos que você criar. Não é possível ter duas contas com o mesmo nome.
+ Método do grupo Contato:
+ É necessário um nome de conta
+ O nome da conta já foi utilizado
+ A conta não pôde ser criada
+ Detecção de configuração
+ Aguarde, procurando servidor…
+ Não foi possível encontrar o serviço CalDAV ou CardDAV.
+ Mostrar detalhes
+
+ Configurações: %s
+ Sincronização
+ Intervalo sinc. de contatos
+ Apenas manualmente
+ A cada %d minutos + imediatamente nas alterações locais
+ Intervalo sinc. de calendários
+ Intervalo sinc. de tarefas
+
+ - Apenas manualmente
+ - A cada 2 minutos
+ - A cada 15 minutos
+ - A cada 30 minutos
+ - A cada hora
+ - A cada 2 horas
+ - A cada 4 horas
+ - Uma vez por dia
+
+ Sincronizar apenas por Wi-Fi
+ Sincronização restrita a conexões Wi-Fi
+ O tipo de conexão não é considerado
+ Restrição de WiFi SSID
+ Sincronizar apenas com %s
+ Só será sincronizado %s (requer serviços de localização ativos)
+ Todas as conexões WiFi serão usadas
+ Nomes separados por vírgula (SSIDs) das redes WiFi (deixe em branco para todas)
+ Para ler nomes de Wi-Fi, a permissão de localização e os serviços de localização permanentemente ativados são obrigatórios.
+ Mais informações
+ Autenticação
+ Nome do usuário
+ Digite o nome do usuário:
+ Senha
+ Atualize a senha de acordo com seu servidor
+ Digite sua senha:
+ Nome do certificado do cliente
+ CalDAV
+ Limite de tempo para eventos passados
+ Todos os eventos serão sincronizados
+
+ - Os eventos que ocorreram a mais de um dia serão ignorados
+ - Eventos que ocorreram a mais de %d dias serão ignorados
+
+ Os eventos que ocorreram antes desse número de dias serão ignorados (pode ser 0). Deixe em branco para sincronizar todos os eventos.
+ Lembrete padrão
+
+ - Lembrete padrão um minuto antes do evento
+ - Lembrete padrão %d minutos antes do evento
+
+ Nenhum lembrete padrão está criado
+ Se lembretes padrão devem ser criados para eventos sem lembrete: o número desejado de minutos antes do evento. Deixe em branco para desativar os lembretes padrão.
+ Gerenciar cores dos calendários
+ Cores dos calendários definidas pelo Gerente de contas
+ Cores dos calendários não definidas pelo Gerente de contas
+ Suporte para cor de evento
+ Sincronizar cores de eventos
+ Não sincronizar cores de eventos
+ CardDAV
+ Método do grupo Contato
+
+ - Grupos são vCards separados
+ - Grupos são categorias por contato
+
+ Alterar a forma de agrupamento
+
+ Criar livro de endereços
+ Meu livro de endereços
+ Criar calendário
+ Fuso horário
+ Fuso horário necessário
+ Possíveis itens de calendário
+ Eventos
+ Tarefas
+ Notas / Diário
+ Combinado (eventos e tarefas)
+ Cor
+ Criando a coleção
+ Título
+ É necessário um título
+ Descrição
+ opcional
+ Local de armazenamento
+ Criar
+ Excluir coleção
+ Tem certeza?
+ Esta coleção (%s) e todos os dados dela serão removidos permanentemente.
+ Estes dados devem ser excluídos do servidor.
+ Excluindo coleção
+ Forçar somente leitura
+ Propriedades
+ Endereço (URL):
+ Copiar URL
+
+ Ocorreu um erro.
+ Ocorreu um erro de HTTP.
+ Ocorreu um erro de leitura/gravação.
+ Mostrar detalhes
+
+ Informações de depuração
+ Os registros são anexados a esta mensagem (requer que o aplicativo de recebimento tenha suporte a anexos).
+ Livro de endereços somente leitura
+ Permissões do Gerente de contas
+ É necessário permissões adicionais
+ A versão do OpenTasks é muito antiga
+ Versão necessária: %1$s (atual %2$s)
+ Falha de autenticação (verifique as credenciais)
+ Erro de rede ou E/S – %s
+ Erro no servidor HTTP – %s
+ Erro de armazenamento local – %s
+ Repetir
+ Ver item
+ Contato inválido recebido do servidor
+ Evento inválido recebido do servidor
+ Tarefa inválida recebida do servidor
+ Ignorando um ou mais recursos inválidos
+
+ Gerente de contas: Segurança da conexão
+ O Gerente de contas encontrou um certificado desconhecido. Deseja torná-lo confiável?
+
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index 8b66834ebce7b4937898213838734baacfe5e606..eb83f889b35e599a545887254479a8baa174d952 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -1,12 +1,11 @@
- DAVx⁵
+ Gerente de contas
A conta não existe mais
Livro de endereços DAVx⁵
Livros de endereços
Ajuda
- Gerenciar contas
Partilhar
Base de dados corrompida
Todas as contas foram removidas localmente.
@@ -180,7 +179,7 @@
Autenticação com URL e certificado do cliente
Selecionar certificado
Autenticar
- Criar conta
+ Adicionar Conta
Nome da conta
Use seu endereço de e-mail como nome da conta porque o Android irá usar esse nome como campo AGENDA nos eventos que você criar. Não é possível ter duas contas com o mesmo nome.
Método do grupo Contato:
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a6b3daec9354f9ae75cdf8d94a67446c6227dd96
--- /dev/null
+++ b/app/src/main/res/values-ro/strings.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 6940f3b017fc61a4adad55cb6903c3cf0de7ed4f..cc4493cf32d4699f1e5df506db62476ebf73ea0c 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -1,423 +1,292 @@
-
+
-
- DAVx⁵
- Аккаунт не существует (больше)
- Адресная книга DAVx⁵
- Адресные книги
- Это поле является обязательным
- Помощь
- Управление аккаунтами
- Поделиться
- База данных повреждена
- Все учетные записи были удалены локально.
- Отладка
- Другие важные сообщения
- Низкоприоритетные сообщения о состоянии
- Синхронизация
- Ошибки синхронизации
- Важные ошибки, которые останавливают синхронизацию, например, неожиданные ответы сервера.
- Предупреждения синхронизации
- Некритичные проблемы с синхронизацией, такие как некоторые неверные файлы
- Ошибки сети и ввода/вывода
- Таймауты, проблемы с подключением и т. д. (часто временные)
-
- Ваши данные. Ваш выбор.
- Возьмите под контроль.
- Регулярные интервалы синхронизации
- Отключено (не рекомендуется)
- Включено (рекомендуется)
- Для обеспечения синхронизации с регулярными интервалами необходимо разрешить работу %s в фоновом режиме. В противном случае, Android может приостановить синхронизацию в любое время.
- Мне не нужна синхронизация с регулярными интервалами.*
- Совместимость %s
- Скорее всего, это устройство блокирует синхронизацию. В этом случае, вы можете решить проблему только самостоятельно.
- Я выполнил необходимые настройки. Больше не напоминать.*
- * Чтобы получить предупреждение позже, снимите флажок. Можно сбросить в настройках приложения / %s.
- Дополнительная информация
- Панель jtx
-
- Поддержка задач
- Если задачи поддерживаются вашим сервером, их можно синхронизировать при помощи соответствующего приложения:
- OpenTasks
- дополнительные приложения.]]>
- Tasks
- не поддерживаются (пока).]]>
- Магазин приложений недоступен
- Мне не нужна поддержка задач.*
- ПО с открытым исходным кодом
- Мы рады, что вы используете %s, программное обеспечение с открытым исходным кодом. Разработка, сопровождение и поддержка - это тяжелая работа. Пожалуйста, подумайте о том, чтобы внести свой вклад (существует множество способов) или сделать пожертвование. Будем очень признательны!
- Как внести свой вклад/пожертвовать
- Не показывать в ближайшем будущем
-
- Разрешения
- %s необходимы разрешения для корректной работы.
- Все нижеперечисленное
- Используйте для включения всех опций (рекомендуется)
- Все разрешения предоставлены
- Разрешения для контактов
- Контакты не синхронизируются (не рекомендуется)
- Синхронизация контактов возможна
- Разрешения для календаря
- Календарь не синхронизируется (не рекомендуется)
- Синхронизация календаря возможна
- Разрешения панели jtx
- Не синхронизируются задачи, журналы и заметки (не установлено)
- Не синхронизируются задачи, журналы, заметки
- Возможна синхронизация задач, журналов и заметок
- Разрешения OpenTasks
- Разрешения Tasks
- Задачи не синхронизируются (не установлены)
- Не синхронизируются задачи
- Синхронизация задач возможна
- Сохранить разрешения
- Разрешения могут быть сброшены автоматически (не рекомендуется)
- Разрешения не будут сброшены автоматически
- Выберите Разрешения > снимите флажок \"Удалить разрешения, если приложение не используется\".
- Если переключатель не работает, используйте Настройки приложения / Разрешения.
- Настройки приложения
-
- Разрешения WiFi SSID
- Для получения доступа к названию текущей сети WiFi (SSID), должны быть выполнены следующие условия:
- Разрешение на точное местоположение
- Разрешение на определение местоположения предоставлено
- Разрешение на определение местоположения не предоставлено
- Разрешение на фоновое определение местоположения
- Разрешать всегда
- %s]]>
- %s]]>
- %s использует разрешение на доступ к местоположению только для определения текущего SSID WiFi для аккацнтов с ограничениями SSID. Это будет происходить даже когда приложение находится в фоновом режиме. Никакие данные о местоположении не собираются, не хранятся, не обрабатываются и не отправляются куда-либо.
- Определение местоположения всегда включено
- Служба определения местоположения включена
- Служба определения местоположения отключена
-
- Переводы
- Библиотеки
- Версия %1$s (%2$d)
- Скомпилировано %s
- © Рикки Хирнер (Ricki Hirner), Бернхард Штокманн (Bernhard Stockmann) (bitfire web engineering GmbH) и контрибьюторы
- Эта версия может распространяться только через Google Play.
- Эта программа поставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. Это свободное программное обеспечение и вы можете распространять его при соблюдении определенных условий.
- Благодарность: %s]]>
-
- Не удалось создать файл лога
- Сейчас логируется вся активность %s
- Просмотр/обмен
- Отключить
-
- Открыть панель навигации
- Закрыть панель навигации
- Адаптер синхронизации CalDAV/CardDAV
- О программе / Лицензия
- Отзыв о бета-тестировании
- Пожалуйста, установите почтовый клиент
- Пожалуйста, установите веб-браузер
- Настройки
- Новости и обновления
- Инструменты
- Внешние ссылки
- Веб-сайт
- Руководство
- FAQ
- Сообщество
- Пожертвовать
- Политика конфиденциальности
- Нет подключения к интернету. Android не будет выполнять синхронизацию.
- Место для хранения мало. Android не будет выполнять синхронизацию.
- Добро пожаловать в DAVx⁵!\n\nТеперь вы можете добавить аккаунт CalDAV/CardDAV.
- Синхронизация отключена на уровне устройства
- Включить
- Синхронизировать все аккаунты
-
- Не удалось обнаружить службу
- Не удалось обновить список коллекций
-
- Невозможно запустить в приоритетном режиме
- Необходимо добавить в белый список оптимизации батареи
-
- Запущен в приоритетном режиме
- Для автоматической синхронизации на некоторых устройствах.
-
- Настройки
- Отладка
- Показать отладочную информацию
- Просмотреть/поделиться сведениями о ПО и конфигурации
- Подробное логирование
- Логирование активно
- Логирование отключено
- Оптимизация батареи
- Приложение внесено в белый список (рекомендуется)
- Приложение не внесено в белый список (рекомендуется)
- Приоритетный режим
- Может помочь, если ваше устройство препятствует автоматической синхронизации
- Соединение
- Тип прокси
-
- - Определен системой
- - Нет прокси
- - HTTP
- - SOCKS (для Orbot)
-
- Имя хоста прокси
- Порт прокси
- Безопасность
- Разрешения приложения
- Проверка разрешений, необходимых для синхронизации
- Недоверие к сертификатам системы
- Не доверять системным и пользовательским CA
- Доверять системным и пользовательским CA (рекомендуется)
- Сброс (не)доверенных сертификатов
- Отменить доверие ко всем пользовательским сертификатам
- Все пользовательские сертификаты были удалены
- Интерфейс пользователя
- Настройки уведомлений
- Управление каналами уведомлений и их настройками
- Выбор темы
-
- - Системная
- - Светлая
- - Темная
-
- Включить подсказки
- Включить подсказки, которые были отключены ранее
- Все подсказки будут показаны снова
- Интеграция
- Приложение Tasks
- Синхронизация с %s
- Не найдено совместимое приложение для задач
-
- CardDAV
- CalDAV
- WebСal
- Контакты не синхронизируются (отсутствуют разрешения)
- Календарь не синхронизируется (отсутствуют разрешения)
- Задачи не синхронизируются (отсутствуют разрешения)
- Календарь и задачи не синхронизируются (отсутствуют разрешения)
- Нет доступа к календарям (отсутствуют разрешения)
- Разрешения
- Нет адресных книг (пока).
- Нет календарей (пока).
- Нет подписок на календарь (пока).
- Потяните вниз, чтобы обновить список с сервера.
- Синхронизировать
- Синхронизация
- Настройки аккаунта
- Переименовать аккаунт
- Несохраненные локальные данные могут быть потеряны. Необходима повторная синхронизация после переименования. Новое имя аккаунта:
- Переименовать
- Не удалось переименовать аккаунт
- Удалить аккаунт
- Вы действительно хотите удалить аккаунт?
- Все локальные копии адресных книг, календарей и задач будут удалены.
- синхронизировать эту коллекцию
- только для чтения
- календарь
- список задач
- журнал
- Показать только личные
- Обновить список адресных книг
- Создать новую адресную книгу
- Обновить список календарей
- Создать новый календарь
- Не найдено приложение, поддерживающее WebCal
- Установить ICSx⁵
-
- Добавить аккаунт
- Войти c адресом email
- Адрес email
- Требуется действительный адрес email
- Пароль
- Требуется пароль
- Войти с URL и именем пользователя
- URL должен начинаться с http(s)://
- Имя пользователя
- Имя пользователя обязательно
- Базовый URL
- Войти с URL и сертификатом клиента
- Выберите сертификат
- Войти
- Создать аккаунт
- Название аккаунта
- По имеющимся данным, использование апострофов (\') вызывает проблемы на некоторых устройствах.
- Укажите ваш адрес email в качестве названия аккаунта, поскольку Android будет его использовать в поле ORGANIZER для создаваемых событий. У вас не может быть двух аккаунтов с тем же именем.
- Метод группировки контактов:
- Название аккаунта обязательно
- Название аккаунта уже используется
- Аккаунт не может быть создан
- Расширенная авторизация (особые случаи использования)
- Использовать имя пользователя/пароль
- Использовать сертификат клиента
- Сертификат не найден
- Установить сертификат
- Обнаружение конфигурации
- Ожидайте, выполняется запрос к серверу…
- Не удалось найти службу CalDAV или CardDAV.
- Имя пользователя (адрес email) / пароль неверны?
- Показать детали
-
- Настройки: %s
- Синхронизация
- Интервал синхронизации контактов
- Вручную
- Каждые %d минут и немедленно при локальных изменениях
- Интервал синхронизации календарей
- Интервал синхронизации задач
-
- - Только вручную
- - Каждые 15 минут
- - Каждые 30 минут
- - Каждый час
- - Каждые 2 часа
- - Каждые 4 часа
- - Раз в день
-
- Синхронизировать только через WiFi
- Разрешить синхронизацию только через WiFi
- Не учитывать тип соединения
- Ограничение WiFi SSID
- Будет синхронизироваться только %s
- Будет синхронизироваться только через %s (требуются активированные службы определения местоположения)
- Будут использоваться все WiFi-подключения
- Имена (SSID) разрешенных сетей WiFi, разделенные запятыми (оставьте пустым для всех)
- Ограничение WiFi SSID требует дополнительных настроек
- Управлять
- Дополнительная информация (FAQ)
- Аутентификация
- Имя пользователя
- Введите имя пользователя:
- Пароль
- Обновить пароль
- Введите свой пароль:
- Привязка сертификата клиента
- Сертификат не выбран
- CalDAV
- Ограничение по времени для прошедших событий
- Будут синхронизироваться все события
-
- - События старше одного дня будут игнорироваться
- - События старше %d дней будут игнорироваться
- - События старше %d дней будут игнорироваться
- - События старше %d дней будут игнорироваться
-
- События, произошедшие ранее указанного количества дней, будут игнорироваться (может быть 0). Оставьте пустым, если хотите синхронизировать все события.
- Напоминание по умолчанию
-
- - Напоминание по умолчанию за 1 минуту до события
- - Напоминание по умолчанию за %d минуты до события
- - Напоминание по умолчанию за %d минут до события
- - Напоминание по умолчанию за %d минут до события
-
- Напоминания по умолчанию не создаются
- Для событий без напоминания введите желаемое количество минут для получения уведомления. Оставьте пустым, чтобы не использовать напоминания по умолчанию.
- Управление цветами календаря
- Цвета календаря сбрасываются после каждой синхронизации
- Цвета календаря могут быть установлены другими приложениями.
- Поддержка цвета событий
- Цвета событий синхронизируются
- Цвета событий не синхронизируются
- CardDAV
- Метод группировки контактов
-
- - Группы являются отдельными vCards
- - Группы являются категориями контактов
-
- Изменить метод группировки
-
- Создать адресную книгу
- Моя адресная книга
- Создать календарь
- Часовой пояс
- Возможные записи календаря
- События
- Задачи
- Заметки / журнал
- Совмещенный (события и задачи)
- Цвет
- Создание коллекции
- Название
- Название обязательно
- Описание
- опционально
- Место хранения
- Место хранения обязательно
- Создать
- Удалить коллекцию
- Вы уверены?
- Эта коллекция (%s) и все ее данные будут удалены навсегда.
- Эти данные должны быть удалены с сервера.
- Удаление коллекции
- Только для чтения
- Свойства
- Адрес (URL):
- Скопировать URL
- Владелец:
-
- Отладочная информация
- ZIP-архив
- Содержит отладочную информацию и логи
- Поделитесь архивом, чтобы перенести его на компьютер, отправить по электронной почте или прикрепить к запросу в службу поддержки.
- Поделиться архивом
- Отладочная информация, прикреплена к данному сообщению (требует поддержки вложений со стороны принимающего приложения).
- Ошибка HTTP
- Ошибка сервера
- Ошибка WebDAV
- Ошибка ввода/вывода
- Запрос был отклонен. Для получения подробной информации проверьте задействованные ресурсы и отладочную информацию.
- Запрошенного ресурса не существует (больше не существует). Проверьте задействованные ресурсы и отладочную информацию для получения подробной информации.
- Возникла проблема на стороне сервера. Пожалуйста, свяжитесь со службой поддержки вашего сервера.
- Произошла неожиданная ошибка. Просмотрите отладочную информацию для получения подробностей.
- Просмотреть информацию
- Собрана отладочная информация
- Вовлеченные ресурсы
- Связанная с этим проблема
- Удаленный ресурс:
- Локальный ресурс:
- Просмотр с помощью приложения
- Логи
- Доступны подробные логи
- Просмотр логов
-
- Произошла ошибка.
- Произошла ошибка HTTP
- Произошла ошибка ввода/вывода.
- Показать детали
-
- Синхронизация приостановлена
- Почти не осталось свободного места
-
- Точки монтирования WebDAV
- Использованная квота: %1$s / доступно: %2$s
- Поделиться контентом
- Отмонтировать
- Добавление точки монтирования WebDAV
- Прямой доступ к вашим облачным файлам с помощью точки монтирования WebDAV!
- как работают точки монтирования WebDAV.]]>
- Отображаемое имя
- WebDAV URL
- Некорректный URL
- Имя пользователя
- Пароль
- Добавить точку монтирования
- Служба WebDAV отсутствует на данном URL
- Доступ к файлу WebDAV
- Загрузка файла WebDAV
- Выгрузка файла WebDAV
- Точка монтирования WebDAV
-
- Разрешения DAVx⁵
- Требуются дополнительные разрешения
- Приложение %s устарело
- Минимально необходимая версия: %1$s
- Ошибка аутентификации (проверьте учетные данные)
- Ошибка сети или ввода/вывода – %s
- Ошибка HTTP-сервера – %s
- Ошибка локального хранилища – %s
- Повторить
- Просмотр элемента
- Получен неверный контакт с сервера
- Получено недействительное событие от сервера
- Получена недействительная задача от сервера
- Игнорирование одного или нескольких недействительных ресурсов
-
- DAVx⁵: безопасность подключения
- DAVx⁵ обнаружил неизвестный сертификат. Вы согласны ему доверять?
+
+ Менеджер учётных записей
+ Адресная книга WebDav
+ Адресные книги
+ Удалить
+ Отмена
+ Помощь
+ Отправить
+ Отладка
+ Другие важные сообщения
+ Синхронизация
+ Ошибки синхронизации
+ Важные ошибки, которые останавливают синхронизацию, например, неожиданные ответы сервера
+ Предупреждения синхронизации
+ Некритичные проблемы с синхронизацией, такие как некоторые неверные файлы
+ Ошибки сети и ввода/вывода
+ Таймауты, проблемы с подключением и т. д. (часто временные)
+
+ Автоматическая синхронизация
+ %s ПО устройства часто блокирует автоматическую синхронизацию. В этом случае разрешите автоматическую синхронизацию в настройках Android.
+ Синхронизация по расписанию
+ Ваше устройство будет блокировать синхронизацию менеджера учётных записей. Чтобы обеспечить регулярные интервалы синхронизации менеджера учётных записей, отключите оптимизацию энергопотребления.
+ Отключить для менеджера учётных записей
+ Не показывать снова
+ Не сейчас
+ Open-Source информация
+ Мы гордимся, что вы используете менеджер учётных записей - приложение с открытым исходным кодом. Его разработка и поддержка отнимает очень много сил и времени. Мы будем счастливы, если вы поддержите наш проект.
+ Поддержать проект
+ Возможно, позже
+ Дополнительная информация
+ OpenTasks не установлен
+ Для синхронизации задач требуется бесплатное приложение OpenTasks. (Не требуется для контактов/событий.)
+ После установки OpenTasks необходимо ПЕРЕУСТАНОВИТЬ менеджер учётных записей и повторно добавить ваши аккаунты (проблема Android).
+ Установить OpenTasks
+
+ Библиотеки
+ Версия %1$s (%2$d)
+ Скомпилировано %s
+ Эта версия может распространяться только через Google Play.
+ Эта программа поставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. Это свободное программное обеспечение и вы можете распространять его при соблюдении определенных условий.
+
+ Не удалось создать файл журнала
+ Журналирование менеджера учетных записей
+ Отправить журнал
+
+ Открыть панель навигации
+ Закрыть панель навигации
+ Адаптер синхронизации Календаря/Контактов
+ О программе / Лицензия
+ Отзыв о бета-тестировании
+ Пожалуйста, установите почтовый клиент
+ Пожалуйста, установите веб-браузер
+ Настройки
+ Новости & обновления
+ Внешние ссылки
+ Веб-сайт
+ Руководство
+ FAQ
+ Помощь / Форумы
+ Пожертвовать
+ Политика конфиденциальности
+ Нет подключения к интернету. Android не будет запускать синхронизацию.
+ Добро пожаловать в Менеджер учётных записей!
+\n
+\nТеперь вы можете добавить аккаунты Календаря/Контактов прямо сейчас.
+ Синхронизация отключена на уровне устройства
+ Включить
+
+ Сбой при обнаружении службы
+ Не удалось обновить список коллекций
+
+ Настройки
+ Отладка
+ Показать отладочную информацию
+ Просмотреть/поделиться сведениями о ПО и конфигурации
+ Детальное журналирование
+ Журналирование активно
+ Журналирование отключено
+ Подключение
+ Переопределить настройки прокси
+ Использовать пользовательские настройки прокси
+ Использовать системные настройки прокси
+ Имя хоста HTTP прокси
+ Порт HTTP прокси
+ Безопасность
+ Доверие системным сертификатам
+ Не доверять системным и пользовательским CA
+ Доверять системным и пользовательским CA (рекомендуется)
+ Сброс (не)доверенных сертификатов
+ Отменить доверие ко всем пользовательским сертификатам
+ Все пользовательские сертификаты были удалены
+ Интерфейс пользователя
+ Настройки уведомлений
+ Управление каналами уведомлений и их настройками
+ Включить подсказки
+ Включить подсказки, которые были отключены ранее
+ Все подсказки будут показаны снова
+
+ Контакты
+ Календарь
+ WebСal
+ Нет адресных книг (пока).
+ Нет календарей (пока).
+ Нет подписок на календарь (пока).
+ Проведите вниз, чтобы обновить список с сервера.
+ Синхронизировать
+ Синхронизация
+ Настройки учётной записи
+ Переименовать учётную запись
+ Несохраненные локальные данные могут быть потеряны. Необходима повторная синхронизация после переименования. Новое имя учётной записи:
+ Переименовать
+ Удалить учётную запись
+ Вы действительно хотите учётную запись\?
+ Все локальные копии адресных книг, календарей и задач будут удалены.
+ синхронизировать эту коллекцию
+ только для чтения
+ календарь
+ список задач
+ Обновить список адресных книг
+ Создать новую адресную книгу
+ Обновить список календарей
+ Создать новый календарь
+ Не найдено приложение, поддерживающее WebCal
+ Установить ICSx⁵
+
+ Добавить учётную запись
+ Войти по email
+ Адрес электронной почты
+ Требуется действующий адрес электронной почты
+ Пароль
+ Требуется пароль
+ Войти по URL-адресу и имени пользователя
+ URL должен начинаться с http(s)://
+ URL-адрес должен начинаться с https://
+ Требуется имя хоста
+ Имя пользователя
+ Требуется Имя пользователя
+ Базовый URL
+ Войти по URL-адресу и клиентскому сертификату
+ Выберите сертификат
+ Войти
+ Назад
+ Добавить аккаунт
+ Имя аккаунта
+ Используйте ваш адрес электронной почты в качестве имени учётной записи, поскольку Android будет использовать имя учётной записи в поле ORGANIZER для событий, которые вы создаете. У вас не может быть двух учётных записей с тем же именем.
+ Метод группировки контактов:
+ Требуется имя учётной записи
+ Имя учётной записи уже используется
+ Учётная запись не может быть создана
+ Добавление учётной записи
+ Ожидайте, выполняется запрос к серверу для добавления учётной записи…
+ Не удалось залогиниться. Пожалуйста, проверьте своё имя пользователя и пароль.
+ Показать детали
+
+ Настройки: %s
+ Синхронизация
+ Интервал синхронизации контактов
+ Вручную
+ Каждые %d минут и немедленно при локальных изменениях
+ Интервал синхронизации календарей
+ Интервал синхронизации задач
+
+ - Только вручную
+ - Каждые 2 минуты
+ - Каждые 15 минут
+ - Каждые 30 минут
+ - Каждый час
+ - Каждые 2 часа
+ - Каждые 4 часа
+ - Один раз в день
+
+ Синхронизировать только через WiFi
+ Разрешить синхронизацию только через WiFi
+ Не учитывать тип соединения
+ Ограничение WiFi SSID
+ Будет синхронизироваться только %s
+ Будет синхронизироваться только более %s (требуются активированные службы определения местоположения)
+ Будут использоваться все WiFi-соединения
+ Названия (SSID), разделенные запятыми разрешенных WiFi-сетей(оставьте пустым для всех)
+ Для чтения имен WiFi требуются разрешение на геолокацию и постоянно активированные службы определения местоположения.
+ Дополнительная информация (FAQ)
+ Аутентификация
+ Имя пользователя
+ Введите имя пользователя:
+ Пароль
+ Обновить пароль согласно вашему серверу.
+ Введите свой пароль:
+ Псевдоним сертификата клиента
+ Календарь
+ Ограничение по времени для прошедших событий
+ Будут синхронизироваться все события
+
+ - События старше одного дня будут игнорироваться
+ - События старше %d дней будут игнорироваться
+ - События старше %d дней будут игнорироваться
+
+ События старше указанного количества дней будут игнорироваться (может быть 0). Оставьте пустым для синхронизации всех событий.
+ Напоминание по умолчанию
+
+ - Напоминание по умолчанию за 1 минуту до события
+ - Напоминание по умолчанию за %d минуты до события
+ - Напоминание по умолчанию за %d минут до события
+
+ Напоминания по умолчанию не создаются
+ Если напоминания по умолчанию должны быть созданы для событий без напоминания: это желаемое количество минут до события. Оставьте пустым, чтобы отключить напоминания по умолчанию.
+ Управление цветами календаря
+ Цвета календаря управляются менеджером учётных записей
+ Цвета календаря не управляются менеджером учётных записей
+ Поддержка цвета событий
+ Синхронизация цветов событий
+ Не синхронизировать цвета событий
+ Контакты
+ Метод группировки контактов
+
+ - Группы являются отдельными vCards
+ - Группы являются категориями контактов
+
+ Изменить метод группировки
+
+ Создать адресную книгу
+ Моя адресная книга
+ Создать календарь
+ Часовой пояс
+ Требуется часовой пояс
+ Возможные записи календаря
+ События
+ Задачи
+ Заметки / журнал
+ Совмещенные (события и задачи)
+ Цвет
+ Создание коллекции
+ Название
+ Требуется название
+ Описание
+ опционально
+ Место хранения
+ Создать
+ Удалить коллекцию
+ Вы уверены?
+ Эта коллекция (%s) и все ее данные будут удалены навсегда.
+ Эти данные должны быть удалены с сервера.
+ Удаление коллекции
+ Только для чтения
+ Свойства
+ Адрес (URL):
+ Копировать URL
+
+ Произошла ошибка.
+ Произошла ошибка HTTP.
+ Произошла ошибка ввода/вывода.
+ Показать детали
+
+ Отладочная информация
+ К этому сообщению будут добавлены журналы (требуется поддержка вложений принимающего приложения).
+ Адресная книга только для чтения
+ Разрешения менеджера учётных записей
+ Требуются дополнительные разрешения
+ OpenTasks устарел
+ Требуется версия: %1$s (текущая %2$s)
+ Ошибка аутентификации (проверьте учетные данные)
+ Ошибка сети или ввода/вывода – %s
+ Ошибка HTTP-сервера – %s
+ Ошибка локального хранилища – %s
+ Повторить
+ Просмотр элемента
+ Получен неверный контакт с сервера
+ Получено недействительное событие от сервера
+ Получена недействительная задача от сервера
+ Игнорирование одного или нескольких недействительных ресурсов
+
+ Менеджер учётных записей: безопасность подключения
+ Менеджер учётных записей обнаружил неизвестный сертификат. Хотите ли вы ему доверять\?
+ https://www.davx5.com/
+ / e / сообщит в Google поддельную модель устройства, чтобы защитить вашу конфиденциальность.
+\nВы можете проверить , какое именное устройство, в \"Google\'s Device Activity\" после входа в систему.
+ ПРЕДУПРЕЖДЕНИЕ
+ WebDAV
+ Google
+ Адресная книга /e/
+ /e/
+ Адресная книга Google
+ Войти с /e/ учётной записью
+ Учетные данные, частота синхронизации и т.д.
+ Использовать настраиваемый сервер
+ Обновить имя пользователя и пароль
+ Учётные данные
+ Использовать конкретный сервер
+ Требуется действительный URL адрес сервера
+ URL сервера (https://server_url)
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index 8ed69f38295ec7dfb4b13d0dfd39aa32927baa42..29a84d703e42b1ee62ffcb8362a02fe39f6bcf89 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -5,7 +5,6 @@
DAVx⁵ adresár
Adresáre
Pomoc
- Spravovať používateľské účty
Ladenie
Ďalšie dôležité správy
Synchronizácia
diff --git a/app/src/main/res/values-sl-rSI/strings.xml b/app/src/main/res/values-sl-rSI/strings.xml
index c027c6583b82d8324d57239379516d0fb92ce8be..aa4f427ebfa528b4405e1c7a0d5d3c98bc017466 100644
--- a/app/src/main/res/values-sl-rSI/strings.xml
+++ b/app/src/main/res/values-sl-rSI/strings.xml
@@ -5,7 +5,6 @@
DAVx⁵ imenik
Seznami s stiki
Pomoč
- Urejanje prijav
Razhroščevalnik
Ostale pomembne nastavitve
Sinhronizacija
diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml
index b47339b344cea21494c086edf25674cece16b593..4dfd53ba1ccd5dc76ebe9b5dc3474f676cb306b8 100644
--- a/app/src/main/res/values-sr/strings.xml
+++ b/app/src/main/res/values-sr/strings.xml
@@ -1,11 +1,10 @@
- ДАВдроид
+ Менаџер налога
ДАВдроид адресар
Адресари
Помоћ
- Управљај налозима
Тражење грешака
Остале важне поруке
Синхронизација
@@ -100,7 +99,7 @@
Пријавите се УРЛ-ом и сертификатом клијента
Изабери сертификат
Пријава
- Направи налог
+ Додај налог
Назив налога
Користите вашу е-адресу за назив налога јер Андроид користи назив налога за поље ОРГАНИЗАТОР за догађаје које направите. Не можете имати два налога истог назива.
Режим група контаката:
diff --git a/app/src/main/res/values-szl/strings.xml b/app/src/main/res/values-szl/strings.xml
index 74277d0a943a79805ac52e06e65a797c2b963a7b..44a3e63d296ee28acf8417431472aecc11f91222 100644
--- a/app/src/main/res/values-szl/strings.xml
+++ b/app/src/main/res/values-szl/strings.xml
@@ -5,7 +5,6 @@
Ksiōnżka adresowo DAVx⁵
Ksiōnżka adresowo
Pōmoc
- Zarzōndzej kōntami
Debugowanie
Inksze ważne wiadōmości
Synchrōnizacyjo
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 1e038bc4bd3bba3dd6c53f1bc55faa3271ddbb4b..d9640d77cad9936baaa3e6628179c4e6ba4816aa 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -1,10 +1,9 @@
- DAVx⁵
+ Muhasebe Müdürü
Rehberler
Yardım
- Hesapları yönet
Hata ayıklama
Senkronizasyon
@@ -28,7 +27,7 @@
Web sitesi
SSS
Bağış yap
- DAVx⁵\'e hoşgeldin!\n\nŞimdi bir CalDAV/CardDAV hesabı ekleyebilirsin.
+ Muhasebe Müdürü\'e hoşgeldin!\n\nŞimdi bir CalDAV/CardDAV hesabı ekleyebilirsin.
Servis keşfi başarısız
Kolleksiyon listesi yenilenemedi
@@ -71,7 +70,7 @@
Kullanıcı adı zorunludur
Baz URL
Giriş
- Hesap yarat
+ Hesap eklemek
Hesap adı
Hesap ismi olarak e-posta adresini kullan çünkü Android hesap ismini yarattığın olaylarda DÜZENLEYEN alanında kullanacaktır. Aynı isimde iki faklı hesabın olamaz.
Hesap adı zorunludur
@@ -107,6 +106,8 @@
Bu sayıdan daha eski olan olaylar yok sayılacaktır (0 olabilir). Tüm olayları senkronize etmek için boş bırak.
Takvim renklerini yönet
+ Takvim renkleri Muhasebe Müdürü tarafından yönetilmekte
+ Takvim renkleri Muhasebe Müdürü tarafından ayarlanmadı
Rehber yarat
Benim Rehberim
@@ -130,7 +131,7 @@
Kullanıcı adı
Parola
- DAVx⁵ izinleri
+ Muhasebe Müdürü izinleri
Ek izinler zorunludur
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 0f0cf8621399d56ac7f59e26595bc458e24d10de..9141d0b9d690bbef0187f2f2720c75fdca5b25e1 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -1,13 +1,12 @@
- DAVx⁵
+ Менеджер рахунків
Обліківки не існує (більше)
- Адресна книга DAVx⁵
+ Адресна книга Менеджер рахунків
Адресні книги
Це поле обовʼязкове
Допомога
- Керування обліковими записами
Поширити
База даних пошкоджена
Усі облікові записи видалено локально.
@@ -77,7 +76,7 @@
Підтримка
Політика конфіденційності
Відсутнє підключення до інтернету. Android не може розпочати синхронізацію.
- Вітаємо у DAVx⁵!\n\nТепер можете додавати облікові записи CalDAV/CardDAV.
+ Вітаємо у Менеджер рахунків!\n\nТепер можете додавати облікові записи CalDAV/CardDAV.
Автоматичну синхронізацію вимкнено зі сторони системи
Увімкнути
Синхронізувати всі обліківки
@@ -161,7 +160,7 @@
Вхід по посиланню та сертифікату клієнта
Обрати сертифікат
Увійти
- Створити запис
+ Додати обліковий
Назва запису
Використовуйте вашу електронну адресу як ім\'я облікового запису, так як Android буде використовувати ім\'я облікового запису в полі ORGANIZER для подій, які ви створюватимете. Ви не можете мати два облікових записи з однаковими іменами.
Метод групування контактів:
@@ -187,6 +186,7 @@
Інтервал синхронізації завдань
- Вручну
+ - Кожні 2 хвилини
- Кожні 15 хвилин
- Кожні 30 хвилин
- Щогодинно
@@ -232,6 +232,8 @@
Нагадування за замовчуванням не створюються
Якщо нагадування за замовчуванням створюються для подій без нагадування: бажана кількість хвилин до події. Залиште поле порожнім, щоб вимкнути нагадування за замовчуванням.
Керування кольорами
+ Кольори календаря керуються Менеджер рахунків
+ Кольори календаря не керуються Менеджер рахунків
Підтримка кольорів подій
CardDAV
Метод групування контактів
@@ -286,7 +288,7 @@
Ім\'я користувача
Пароль
- Дозволи DAVx⁵
+ Дозволи Менеджер рахунків
Потребує додаткові дозволи
Помилка аутентифікації (перевірте обліковий запис)
Помилка мережі та вводу/виводу — %s
@@ -299,6 +301,6 @@
Отримано помилкове завдання від сервера
Ігнорування одного або більше хибних джерел
- DAVx⁵: Безпека з\'єднання
- DAVx⁵ зіткнувся з невідомим сертифікатом. Чи довіряти йому?
+ Менеджер рахунків: Безпека з\'єднання
+ Менеджер рахунків зіткнувся з невідомим сертифікатом. Чи довіряти йому?
diff --git a/app/src/main/res/values-v27/styles.xml b/app/src/main/res/values-v27/styles.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f4cc27c6176a4f38a1feca27fee8e8c37273548f
--- /dev/null
+++ b/app/src/main/res/values-v27/styles.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml
index d972f4887e3887f3e49b1a80b42c9d1db6769958..bd318f56776b969120487b2b3019e3ec45bbc48a 100644
--- a/app/src/main/res/values-vi/strings.xml
+++ b/app/src/main/res/values-vi/strings.xml
@@ -5,9 +5,10 @@
Tài khoản không tồn tại (nữa)
Sổ địa chỉ của DAVx⁵
Sổ địa chỉ
+ Xóa
+ Hủy
Trường này là bắt buộc
Trợ giúp
- Quản lý các tài khoản
Chia sẻ
Cơ sở dữ liệu đã bị lỗi
Tất cả tài khoản đã bị xóa ở cục bộ.
@@ -392,6 +393,8 @@
Mật khẩu
Thêm nơi gắn
Không có dịch vụ WebDAV tại URL này
+ Xóa điểm gắn
+ Chi tiết kết nối sẽ bị mất, nhưng các tệp sẽ không bị xóa.
Đang truy cập tệp WebDAV
Đang tải xuống tệp WebDAV
Đang tải lên tệp WebDAV
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..221934a6180e966d55e7e236d48839e2ce073d08
--- /dev/null
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -0,0 +1,253 @@
+
+
+
+ 客户经理
+ 客户经理 通讯录
+ 通讯录
+ 帮助
+ 发送
+ 调试
+ 其它重要消息
+ 同步
+ 同步错误
+ 导致同步停止的重要错误,如异常的服务器响应
+ 同步警告
+ 不重要的同步问题,如某文件无效
+ 网络或 I/O 错误
+ 超时、连接异常等问题(通常是临时错误)
+
+ 自动同步
+ %s 的系统通常会禁止自动同步。在 Android 的系统设置中手工打开自动同步即可恢复。
+ 定时同步
+ 你的设备会限制 客户经理 的同步频率,如需恢复正常同步频率,请关闭电池优化设置。
+ 禁用电池优化
+ 不再显示
+ 暂不
+ 开源信息
+ 欢迎使用 客户经理,这是一款开源软件 (GPLv3)。开发 客户经理 的工作花费了数千小时,请您考虑捐助我们。
+ 显示捐助页面
+ 稍后提示
+ 更多信息
+ OpenTasks 未安装
+ 同步任务需安装 OpenTasks 免费应用。(如只需同步通讯录、事件,则不用安装)
+ 安装 OpenTasks 后,由于 Android 的限制,请重新安装 客户经理 并重新创建账户。
+ 安装 OpenTasks
+
+ 程序库
+ 版本 %1$s (%2$d)
+ 编译于 %s
+ 此版本只允许在 Google Play 上发行。
+ 本程序不附带任何担保。这是一款自由软件,你可以有条件地传播它。
+
+ 无法创建日志文件
+ 客户经理 日志
+ 发送日志
+
+ 打开导航抽屉
+ 关闭导航抽屉
+ CalDAV/CardDAV 同步器
+ 关于 / 许可
+ 测试版反馈
+ 设置
+ 最新消息
+ 外部链接
+ 应用网站
+ 手动
+ 常见问题
+ 帮助 / 论坛
+ 捐助
+ 欢迎使用 客户经理!\n\n请开始增加 CalDAV/CardDAV 账户。
+ 系统全局自动同步已禁用
+ 启用
+
+ 服务配置检测失败
+ 无法刷新集合列表
+
+ 设置
+ 调试
+ 显示调试信息
+ 查看软件和配置信息
+ 记录完整日志
+ 日志记录已开启
+ 日志记录已禁用
+ 连接
+ 覆盖代理设置
+ 使用自定义代理设置
+ 使用系统默认代理设置
+ HTTP 代理主机名
+ HTTP 代理端口
+ 安全
+ 不信任系统证书
+ 系统和用户增加的发布者不会被信任
+ 系统和用户增加的发布者会被信任(推荐)
+ 重设证书信任状态
+ 重设所有自定义证书的信任状态
+ 所有自定义证书已清除
+ 用户界面
+ 通知设置
+ 管理通知渠道等设置
+ 重设提示
+ 重新显示之前忽略过的提示
+ 所有提示将会再次显示
+
+ CardDAV
+ CalDAV
+ Webcal
+ 暂无通讯录。
+ 暂无日历。
+ 暂无日历订阅。
+ 下拉可从服务器获取最新列表。
+ 立即同步
+ 正在同步
+ 账户设置
+ 重命名账户
+ 重命名后,未上传的本地修改会被撤销,您需要重新执行同步。新账户名:
+ 重命名
+ 删除账户
+ 真的要删除账户吗?
+ 所有通讯录、日历和任务列表的本机存储将被删除。
+ 同步该集合
+ 只读
+ 日历
+ 任务列表
+ 刷新通讯录列表
+ 创建通讯录
+ 刷新日历列表
+ 创建日历
+ 找不到支持 Webcal 的应用
+ 安装 ICSx⁵
+
+ 增加账户
+ 使用邮箱地址登录
+ Email 地址
+ 请输入有效 Email 地址
+ 密码
+ 请输入密码
+ 使用 URL 和用户名登录
+ URL 需以 http(s):// 为开头
+ URL 需以 https:// 为开头
+ 请输入主机名
+ 用户名
+ 请输入用户名
+ 根地址
+ 使用 URL 和客户端证书登录
+ 选择证书
+ 登录
+ 返回
+ 新增帐户
+ 账户显示名
+ 请使用你的邮箱地址作为帐户名,因为 Android 会将你创建的日历事件的创建者项设置为帐户名。你不能拥有多个帐户名相同的账户。
+ 联系人分组方式
+ 请输入账户名
+ 账户名已被占用
+ 账户无法创建
+ 正在配置
+ 正在与服务器通信,请稍等…
+ 找不到 CalDAV 或 CardDAV 服务。
+ 显示详情
+
+ 设置:%s
+ 同步
+ 通讯录自动同步间隔
+ 手动同步
+ 每 %d 分钟或本地修改后
+ 日历自动同步间隔
+ 任务自动同步间隔
+
+ - 手动同步
+ - 每 2 分钟
+ - 每 15 分钟
+ - 每 30 分钟
+ - 每小时
+ - 每 2 小时
+ - 每 4 小时
+ - 每天一次
+
+ 只在 WiFi 下同步
+ 同步只在 WiFi 连接下进行
+ 同步不受数据连接类型限制
+ WiFi SSID 限制
+ 只使用 %s 网络同步
+ 将只在 %s 上同步(需要生效的位置服务)
+ 任意 WiFi 网络均可同步
+ 请用半角逗号分隔允许同步的 WiFi 网络名(SSID),留空则允许任意网络
+ 读取 WiFi 网络名称需要位置权限,以及永久生效的位置服务。
+ 更多信息(常见问题)
+ 认证
+ 用户名
+ 输入用户名
+ 密码
+ 修改服务器密码
+ 输入密码
+ 客户端证书别名
+ CalDAV
+ 旧日程时间限制
+ 同步所有日程
+
+ - %d 天前的日程不会被同步
+
+ 超过这个数字的天数的旧日程将会被忽略(可以为 0)。留空则同步所有日程。
+ 管理日历颜色
+ 日历颜色由 客户经理 设置
+ 日历颜色不由 客户经理 设置
+ 事件日历颜色支持
+ 同步日历事件颜色
+ 不同步日历事件颜色
+ CardDAV
+ 联系人分组方式
+ 修改分组方式
+
+ 创建通讯录
+ 我的通讯录
+ 创建日历
+ 时区
+ 请选择时区
+ 可能使用的日历类型
+ 事件
+ 任务
+ 笔记 / 日志
+ 混合(日程和任务)
+ 颜色
+ 正在创建集合
+ 标题
+ 请输入标题
+ 描述
+ 可选
+ 存储位置
+ 创建
+ 删除集合
+ 你确定吗?
+ 该集合 %s 及其所有数据将会被永久删除。
+ 这些数据将会被从远程服务器删除。
+ 正在删除集合
+ 强制只读
+ 属性
+ 地址 (URL):
+ 复制 URL
+
+ 出现错误
+ 出现 HTTP 错误
+ 出现 I/O 错误
+ 显示详情
+
+ 调试信息
+ 日志数据将作为附件与该信息一并发送(需要分享目标应用支持附件功能)。
+ 只读通讯录
+ 客户经理 权限
+ 需要额外权限
+ OpenTasks 版本太旧
+ 最低版本 %1$s (当前 %2$s)
+ 认证失败(请检查登录凭据,如用户名密码)
+ 网络或 I/O 错误 – %s
+ HTTP 服务器错误 – %s
+ 本地存储错误 – %s
+ 重试
+ 显示项目
+ 从服务器收到无效的通讯录
+ 从服务器收到无效的日历事件
+ 从服务器收到无效的任务项
+ 正在忽略若干无效资源
+
+ 客户经理: 连接安全性
+ 客户经理 遇到了未知证书。你是否要信任该证书?
+
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index b321324a062f54efef062a40c2060924b84e0f8a..5b4e658f204f7ef8c3d25d45db3e6d382d6e8fa1 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -1,12 +1,11 @@
- DAVx⁵
+ 客户经理
賬戶不存在 (anymore)
- DAVx⁵ 通訊錄
+ 客户经理 通訊錄
通訊錄
幫助
- 管理帳號
除錯
其他重要訊息
同步
@@ -55,7 +54,7 @@
贊助我們
隱私權政策
網際網絡沒有連接。Android不會進行同步。
- 歡迎使用 DAVx⁵!\n\n您現在可以新增 CalDAV/CardDAV 帳號
+ 歡迎使用 客户经理!\n\n您現在可以新增 CalDAV/CardDAV 帳號
操作系統的自動同步被關閉了
啟用
@@ -131,7 +130,7 @@
用網址和客戶端鑒權登入
點選憑證
登入
- 新建帳號
+ 新增帐户
帳號名稱
使用 Email 地址當作裝置上的帳號顯示名稱,因為當您在行事曆創建活動時,Android 會把帳號顯示名稱放到「活動發起人」欄位。兩個帳號不能有相同的名稱。
聯絡人群組的儲存格式
@@ -190,6 +189,8 @@
如果默認的提醒方式在創建時沒有這一項:在事項前幾分鐘,就可以留空來關閉默認的提醒方式。
管理行事曆的顏色
設定事項的顔色
+ 行事曆顏色由 客户经理 管理
+ 行事曆顏色不由 客户经理 管理
CardDAV(聯絡人檔案)
聯絡人群組的儲存格式
@@ -232,7 +233,7 @@
讀寫錯誤
顯示細節
- DAVx⁵ 權限
+ 客户经理 權限
需要額外的權限
鑒權失敗(你需要檢查登錄憑證)
網際網絡或者輸入輸出錯誤——%s
@@ -245,6 +246,6 @@
收到了無效的任務
略過了一個或多個無效的資料
- DAVx⁵: 連線安全性
- DAVx⁵ 發現未知的憑證,您要信任它嗎?
+ 客户经理: 連線安全性
+ 客户经理 發現未知的憑證,您要信任它嗎?
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index 5f468229d000e79669b85ba87289e02cb4b1b5f7..8c7eba5f6f2a528057166a4d64229304594527e9 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -5,9 +5,10 @@
帐户(已)不存在
DAVx⁵ 通讯录
通讯录
+ 删除
+ 取消
此字段是必填项
帮助
- 管理账户
分享
数据库损坏
所有帐户已在本地删除。
@@ -392,6 +393,8 @@
密码
添加 WebDAV 网址
此 URL 无 WebDAV 服务
+ 删除装载点
+ 将丢失连接详情,但不会删除文件
正在访问 WebDAV 文件
正在下载 WebDAV 文件
正在上传 WebDAV 文件
diff --git a/app/src/main/res/values/account_providers_auth_config.xml b/app/src/main/res/values/account_providers_auth_config.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b3b10fdbaa873cc965b9d52e768ab19a89bc1349
--- /dev/null
+++ b/app/src/main/res/values/account_providers_auth_config.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ Google
+
+ 100496780587-pbiu5eudcjm6cge2phduc6mt8mgbsmsr.apps.googleusercontent.com
+
+ https://accounts.google.com/.well-known/openid-configuration
+
+ openid profile email https://www.googleapis.com/auth/carddav https://www.googleapis.com/auth/calendar https://mail.google.com/
+
+
+ com.googleusercontent.apps.100496780587-pbiu5eudcjm6cge2phduc6mt8mgbsmsr:/oauth2redirect
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000000000000000000000000000000000000..78233173d756d63d301c297fba55aec8d75fe711
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,18 @@
+
+
+
+ @color/accentColor
+ #61000000
+ @color/accentColor
+ #61000000
+ #BD000000
+ @color/primaryTextColor
+ #61000000
+ #BD000000
+
diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d9edc26bb754e54acf72d9da8c9e640080a41531
--- /dev/null
+++ b/app/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,5 @@
+
+
+ #7CB342
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e37ce368c7bde6c7e2ff508833915009be9717e6..79fe42f1f29bea36d95d0a54d97ecd9539633cb2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,19 +1,36 @@
- DAVx⁵
- https://www.davx5.com/
- davx5app
-
+ Account Manager
+ https://e.foundation/
+ e_mydata
Account does not exist (anymore)
- bitfire.at.davdroid
- at.bitfire.davdroid.address_book
- DAVx⁵ Address book
- at.bitfire.davdroid.addressbooks
+ e.foundation.webdav
+ WebDAV
+ Google
+ e.foundation.webdav.google
+ /e/
+ e.foundation.webdav.eelo
+ foundation.e.accountmanager.address_book
+ WebDav Address book
+ foundation.e.accountmanager.eelo.address_book
+ /e/ Address book
+ foundation.e.accountmanager.google.address_book
+ Google Address book
+ foundation.e.accountmanager.addressbooks
Address books
+ Remove
+ Cancel
This field is required
+ foundation.e.notes.android.providers.AppContentProvider
+ foundation.e.mail.provider.AppContentProvider
+ foundation.e.drive.providers.MediasSyncProvider
+ foundation.e.drive.providers.SettingsSyncProvider
Help
- Manage accounts
+ foundation.e.drive
+ foundation.e.drive.providers.MeteredConnectionAllowedProvider
+ Account extra settings
+ Credentials, sync frequency, etc.
Share
Database corrupted
@@ -120,7 +137,7 @@
Open navigation drawer
Close navigation drawer
- CalDAV/CardDAV Sync Adapter
+ Calendar/Contacts Sync Adapter
About / License
Beta feedback
Please install an email client
@@ -137,7 +154,7 @@
Privacy policy
No Internet connectivity. Android will not run synchronization.
Storage space low. Android will not run synchronization.
- Welcome to DAVx⁵!\n\nYou can add a CalDAV/CardDAV account now.
+ Welcome to Account Manager!\n\nYou can add a Calendar/Contacts account now.
System-wide automatic synchronization is disabled
Enable
Sync all accounts
@@ -215,8 +232,8 @@
No compatible tasks app found
- CardDAV
- CalDAV
+ Contacts
+ Calendar
Webcal
No contacts sync (missing permissions)
No calendar sync (missing permissions)
@@ -253,6 +270,7 @@
Add account
+ Use your e.email or murena.io ID to sign in:
Login with email address
Email address
Valid email address required
@@ -266,26 +284,32 @@
Login with URL and client certificate
Select certificate
Login
- Create account
+ Add account
Account name
Use of apostrophes (\'), have been reported to cause problems on some devices.
Use your email address as account name because Android will use the account name as ORGANIZER field for events you create. You can\'t have two accounts with the same name.
Contact group method:
Account name required
Account name already taken
- Account could not be created
+ An account with the same name already exists
Advanced login (special use cases)
Use username/password
Use client certificate
No certificate found
Install certificate
- Configuration detection
- Please wait, querying server…
- Couldn\'t find CalDAV or CardDAV service.
+ Add account
+ Please wait, adding account…
+ Login failed. Please check your username and password.
Username (email address) / password wrong?
Show details
+ Use custom server
+ Server URL (https://server_url)
+ Server URL (%s)
+ Valid server URL address required
+ Use a specific server
+
Settings: %s
Synchronization
@@ -298,7 +322,8 @@
sync_interval_tasks
Tasks sync. interval
- - -1
+ - -1
+ - 120
- 900
- 1800
- 3600
@@ -307,7 +332,8 @@
- 86400
- - Only manually
+ - Only manually
+ - Every 2 minutes
- Every 15 minutes
- Every 30 minutes
- Every hour
@@ -331,16 +357,18 @@
Authentication
username
User name
+ Credentials
+ Update username and password
Enter user name:
password
Password
- Update the password according to your server.
+ Update password according to your server.
Enter your password:
certificate_alias
Client certificate alias
No certificate selected
caldav
- CalDAV
+ Calendar
time_range_past_days
Past event time limit
All events will be synchronized
@@ -359,14 +387,14 @@
If default reminders shall be created for events without reminder: the desired number of minutes before the event. Leave blank to disable default reminders.
manage_calendar_colors
Manage calendar colors
- Calendar colors are reset at each sync
- Calendar colors can be set by other apps
+ Calendar colors are managed by Account Manager
+ Calendar colors are not set by Account Manager
event_colors
Event color support
- Event colors are synced
- Event colors are not synced
+ Sync event colors
+ Do not sync event colors
carddav
- CardDAV
+ Contacts
contact_group_method
Contact group method
@@ -410,7 +438,7 @@
Owner:
- at.bitfire.davdroid.debug
+ foundation.e.accountmanager.debug
Debug info
ZIP archive
Contains debug info and logs
@@ -447,7 +475,7 @@
Almost no free space left
- at.bitfire.davdroid.webdav
+ foundation.e.accountmanager.webdav
WebDAV mounts
Quota used: %1$s / available: %2$s
Share content
@@ -462,13 +490,15 @@
Password
Add mount
No WebDAV service at this URL
+ Remove mount point
+ Connection details will be lost, but no files will be deleted.
Accessing WebDAV file
Downloading WebDAV file
Uploading WebDAV file
WebDAV mount
- DAVx⁵ permissions
+ Account Manager permissions
Additional permissions required
%s too old
Minimum required version: %1$s
@@ -484,7 +514,37 @@
Ignoring one or more invalid resources
- DAVx⁵: Connection security
- DAVx⁵ has encountered an unknown certificate. Do you want to trust it?
+ Account Manager: Connection security
+ Account Manager has encountered an unknown certificate. Do you want to trust it?
+
+ Added account successfully
+
+
+ WARNING
+ /e/ will report a fake device model to Google to protect your privacy.\nYou can check which one on Google\'s Device Activity after you log in.
+
+ My Account
+ /e/ Account overview
+ You can configure only one ecloud account on your device
+
+ Create Account
+ Invitation was sent to your email. If you didn\'t receive it, please check spam folder.
+ Instructions
+ 1 - Now, from another device or computer, open the invitation email and complete account creation.\n\n2 - Then, please come back in this screen and log in with your brand new murena.io account.\n\nNote: You can skip this step and add your account later in the Settings.
+ sign in on this device
+ setup later
+ Please, enter your e-mail address to receive an invitation to a free murena.io ID with a unique and personal email account and a personal cloud space.
+ Send
+ User already exists
+ A cloud account has already been created with this email address. You can log in now with your credentials.
+ Skip
+ Login
+ Try Again
+ Please enter a valid email
+ Error
+ The invitation couldn\'t be delivered to your email due to an online failure.\n\nPlease try again later.\n\nNote: you can also skip this process and add an account later in Settings. In case of difficulties, please contact support.
+ Enter email to receive invitation
+ Please check your internet connection
+ Sign In
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index b0d9e9e41f8b95701d0d9714759dcaa052b6e2a6..941befa101388e878d444d440e03b11a5d22710d 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -9,6 +9,7 @@
+ @lineageos.platform:color/color_default_gray1
#f5f5f5
#eeeeee
@@ -19,44 +20,140 @@
#EF5350
#d32f2f
- #7cb342
- #aee571
- #4b830d
- @android:color/black
+ @color/accentColor
+ @color/secondaryTextColor
- #ff6d00
- #ff9e40
- #c43c00
- @android:color/white
+ @lineageos.platform:color/color_default_primary
+ @lineageos.platform:color/color_default_primary_dark
+ @lineageos.platform:color/color_default_accent
+ @lineageos.platform:color/color_default_view_on_accent
+ @lineageos.platform:color/color_default_primary_text
+ @lineageos.platform:color/color_default_secondary_text
+ @lineageos.platform:color/color_default_background
+ @lineageos.platform:color/color_default_foreground
+ @lineageos.platform:color/color_default_divider
- @color/grey900
- @color/grey800
-
- @color/grey200
+ @color/accentColor
@color/red700
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @color/accentColor
+
+
-
+
- @color/secondaryLightColor
+
+
+
diff --git a/app/src/main/res/xml/account_authenticator.xml b/app/src/main/res/xml/account_authenticator.xml
index 85eaa203324c6da6ddcfe9e282e59fe55685847e..b2c7b4b3306ff6753a81c81d8d4d6e547b202227 100644
--- a/app/src/main/res/xml/account_authenticator.xml
+++ b/app/src/main/res/xml/account_authenticator.xml
@@ -1,6 +1,6 @@
\ No newline at end of file
+ android:icon="@mipmap/ic_launcher_round"
+ android:label="@string/account_name"
+ android:smallIcon="@mipmap/ic_launcher" />
diff --git a/app/src/main/res/xml/account_authenticator_address_book.xml b/app/src/main/res/xml/account_authenticator_address_book.xml
index 6305f31e7429ed7d7db27bfc90a66ce469e78951..d43b5cb3ceafdafbe4f7cd2df34c6cd7cd19cdd9 100644
--- a/app/src/main/res/xml/account_authenticator_address_book.xml
+++ b/app/src/main/res/xml/account_authenticator_address_book.xml
@@ -1,6 +1,6 @@
\ No newline at end of file
+ android:smallIcon="@mipmap/ic_launcher" />
diff --git a/app/src/main/res/xml/account_authenticator_eelo_address_book.xml b/app/src/main/res/xml/account_authenticator_eelo_address_book.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4538cc3b186888a473eadb61a0b87ed94e8263c4
--- /dev/null
+++ b/app/src/main/res/xml/account_authenticator_eelo_address_book.xml
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/app/src/main/res/xml/account_authenticator_google_address_book.xml b/app/src/main/res/xml/account_authenticator_google_address_book.xml
new file mode 100644
index 0000000000000000000000000000000000000000..08b70e6b320acfa95fdffcea317e87f98ae929a0
--- /dev/null
+++ b/app/src/main/res/xml/account_authenticator_google_address_book.xml
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/app/src/main/res/xml/eelo_account_authenticator.xml b/app/src/main/res/xml/eelo_account_authenticator.xml
new file mode 100644
index 0000000000000000000000000000000000000000..442c76b3d17dcbc6051e786ab18898852b768adc
--- /dev/null
+++ b/app/src/main/res/xml/eelo_account_authenticator.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/app/src/main/res/xml/eelo_sync_address_books.xml b/app/src/main/res/xml/eelo_sync_address_books.xml
new file mode 100644
index 0000000000000000000000000000000000000000..845ea6c17239396c328332442f8f95b936590ff5
--- /dev/null
+++ b/app/src/main/res/xml/eelo_sync_address_books.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/xml/eelo_sync_app_data.xml b/app/src/main/res/xml/eelo_sync_app_data.xml
new file mode 100644
index 0000000000000000000000000000000000000000..00e4670ee890dfe092f9fd6dc4ed533734dc05ea
--- /dev/null
+++ b/app/src/main/res/xml/eelo_sync_app_data.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/xml/eelo_sync_calendars.xml b/app/src/main/res/xml/eelo_sync_calendars.xml
new file mode 100644
index 0000000000000000000000000000000000000000..27d291ea35984560c256f4c9bad0e208f0f21dc4
--- /dev/null
+++ b/app/src/main/res/xml/eelo_sync_calendars.xml
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/app/src/main/res/xml/eelo_sync_contacts.xml b/app/src/main/res/xml/eelo_sync_contacts.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8b93ebf6e6eb0b0a464c3f042db3a7185ee1718a
--- /dev/null
+++ b/app/src/main/res/xml/eelo_sync_contacts.xml
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/app/src/main/res/xml/eelo_sync_email.xml b/app/src/main/res/xml/eelo_sync_email.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8c5dc376a1f88c3afe509698f4c00e6ba1949c36
--- /dev/null
+++ b/app/src/main/res/xml/eelo_sync_email.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/xml/eelo_sync_media.xml b/app/src/main/res/xml/eelo_sync_media.xml
new file mode 100644
index 0000000000000000000000000000000000000000..97c2331cdffcbba8f59b993362fc91d14af5a9af
--- /dev/null
+++ b/app/src/main/res/xml/eelo_sync_media.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/xml/eelo_sync_metered_edrive.xml b/app/src/main/res/xml/eelo_sync_metered_edrive.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b63de1510f5d0d003acd1c50f99263012575ee3a
--- /dev/null
+++ b/app/src/main/res/xml/eelo_sync_metered_edrive.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/xml/eelo_sync_notes.xml b/app/src/main/res/xml/eelo_sync_notes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..57c5cf24d5819967d3710bf1c9ed94fd96d1fbb2
--- /dev/null
+++ b/app/src/main/res/xml/eelo_sync_notes.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/xml/eelo_sync_tasks.xml b/app/src/main/res/xml/eelo_sync_tasks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..65eaa6a08f312d4ba2135d27052db4cfda01540f
--- /dev/null
+++ b/app/src/main/res/xml/eelo_sync_tasks.xml
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/app/src/main/res/xml/google_account_authenticator.xml b/app/src/main/res/xml/google_account_authenticator.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0ba6c7a616dbc55f6b07acfda29213f9ef2a47d3
--- /dev/null
+++ b/app/src/main/res/xml/google_account_authenticator.xml
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/app/src/main/res/xml/google_sync_address_books.xml b/app/src/main/res/xml/google_sync_address_books.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7bdbf6f90ba26c1d737c752fa90ccb5630908495
--- /dev/null
+++ b/app/src/main/res/xml/google_sync_address_books.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/xml/google_sync_calendars.xml b/app/src/main/res/xml/google_sync_calendars.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e61c04cb93d013e9f96bda1ce42adc34e9672943
--- /dev/null
+++ b/app/src/main/res/xml/google_sync_calendars.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/app/src/main/res/xml/google_sync_contacts.xml b/app/src/main/res/xml/google_sync_contacts.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b6e2633c57750968fcea498b1ac1a4eb875603c5
--- /dev/null
+++ b/app/src/main/res/xml/google_sync_contacts.xml
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/app/src/main/res/xml/google_sync_email.xml b/app/src/main/res/xml/google_sync_email.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8e2d28b82fa99a771f9d93de64599508b45a1d7a
--- /dev/null
+++ b/app/src/main/res/xml/google_sync_email.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/xml/google_sync_tasks.xml b/app/src/main/res/xml/google_sync_tasks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4c8b748eaa906db99d719a63d8fa9f976e8b9a85
--- /dev/null
+++ b/app/src/main/res/xml/google_sync_tasks.xml
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/app/src/main/res/xml/settings_account.xml b/app/src/main/res/xml/settings_account.xml
index abc435353c7b884437e35eea2a6fb5cdea761e64..847eb14da69ee48a1363dbef80efad0acd273f4d 100644
--- a/app/src/main/res/xml/settings_account.xml
+++ b/app/src/main/res/xml/settings_account.xml
@@ -46,6 +46,12 @@
+
+
-
\ No newline at end of file
+
diff --git a/app/src/main/res/xml/sync_prefs.xml b/app/src/main/res/xml/sync_prefs.xml
index 6e693253df8f7789cfa465cdebfe4a8dee7645fd..d42fda5538259b2d88b59030e20fde29366fb965 100644
--- a/app/src/main/res/xml/sync_prefs.xml
+++ b/app/src/main/res/xml/sync_prefs.xml
@@ -1,19 +1,24 @@
-
-
-
+
+
+
+ android:targetPackage="at.bitfire.davdroid" />
-
diff --git a/app/src/main/res/xml/sync_prefs_eelo.xml b/app/src/main/res/xml/sync_prefs_eelo.xml
new file mode 100644
index 0000000000000000000000000000000000000000..159726f55fa30881da85767fc7beae5e7557bfe8
--- /dev/null
+++ b/app/src/main/res/xml/sync_prefs_eelo.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/xml/sync_tasks.xml b/app/src/main/res/xml/sync_tasks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9fbfaa0c0022a60f327f70205ef6d22231026a41
--- /dev/null
+++ b/app/src/main/res/xml/sync_tasks.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/app/src/standard/java/at/bitfire/davdroid/OseFlavorModule.kt b/app/src/ose/java/at/bitfire/davdroid/OseFlavorModule.kt
similarity index 100%
rename from app/src/standard/java/at/bitfire/davdroid/OseFlavorModule.kt
rename to app/src/ose/java/at/bitfire/davdroid/OseFlavorModule.kt
diff --git a/build.gradle b/build.gradle
index d06901aa3e635c5e53b947ae3ed696eada6e022f..9ca95659bf440ea717fac9d26bc7a5a269942952 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,11 +9,11 @@
buildscript {
ext.versions = [
aboutLibraries: '8.9.4',
- appIntro: '6.1.0',
+ appIntro: '6.2.0',
dav4jvm: 'c61e4b0c80a5a8de1df99b4997445bb323d3ea3d',
- hilt: '2.42',
- kotlin: '1.7.0',
- okhttp: '4.9.3',
+ hilt: '2.43.2',
+ kotlin: '1.7.10',
+ okhttp: '4.10.0',
// latest Apache Commons versions that don't require Java 8 (Android 7)
commonsCollections: '4.2',
commonsLang: '3.8.1',
diff --git a/dav4android b/dav4android
new file mode 160000
index 0000000000000000000000000000000000000000..f661a07a0f195d9fd330e4dc7bc9174ff30fb651
--- /dev/null
+++ b/dav4android
@@ -0,0 +1 @@
+Subproject commit f661a07a0f195d9fd330e4dc7bc9174ff30fb651
diff --git a/e-ui-sdk.jar b/e-ui-sdk.jar
new file mode 100644
index 0000000000000000000000000000000000000000..5974432e9c6b33ca4a6473603e57cd3290d5bdaa
Binary files /dev/null and b/e-ui-sdk.jar differ
diff --git a/fastlane/metadata/android/en-US/changelogs/402030001.txt b/fastlane/metadata/android/en-US/changelogs/402030001.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ac0293854b655d60b8dd2f48fa9cc465fc74f228
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/402030001.txt
@@ -0,0 +1,3 @@
+* CalDAV: refactor and improve event validation and repairing (especially with recurring events)
+* WebDAV: connections now have a delete symbol, so that people know that they would delete the connection
+* minor bug fixes and improvements
diff --git a/gradle.properties b/gradle.properties
index c6bf06227a4bf6557135f618573cf62c3cf6fad4..824f2fa9184b98570653dbbea628f3a5f357b0bf 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -16,3 +16,4 @@ android.useAndroidX=true
org.gradle.daemon=true
org.gradle.jvmargs=-Xmx1536M -Dkotlin.daemon.jvm.options\="-Xmx1536M"
org.gradle.parallel=true
+android.enableJetifier=true
diff --git a/ical4android b/ical4android
index 41171b57fdc5f045b17d09df85853a6cc13ef4fd..c6d5064f62fe7987de566eb6e5b29e524800d904 160000
--- a/ical4android
+++ b/ical4android
@@ -1 +1 @@
-Subproject commit 41171b57fdc5f045b17d09df85853a6cc13ef4fd
+Subproject commit c6d5064f62fe7987de566eb6e5b29e524800d904
diff --git a/run-tests.sh b/run-tests.sh
deleted file mode 100755
index 511c5926448b29025d5e1484fcec63422fb4f91b..0000000000000000000000000000000000000000
--- a/run-tests.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh
-
-./gradlew -i --continue check mergeAndroidReports
-
-echo
-echo View lint report:
-echo -n file://
-realpath app/build/outputs/lint-results-gplayDebug.html
-
-echo
-echo View local unit test reports:
-echo -n file://
-realpath app/build/reports/tests/testStandardReleaseUnitTest/standardRelease/index.html
-
-echo
-echo "View merged Android test reports (debug):"
-echo -n file://
-realpath build/reports/androidTests/index.html
diff --git a/settings.gradle b/settings.gradle
index e5c3923c5f55e597a307a4b695c5177d93555b76..e9ca5a41c038d6ab93b2a1ccd48e01fecf05b51a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -3,3 +3,4 @@ include ':app'
include ':cert4android'
include ':ical4android'
include ':vcard4android'
+include ':dav4android'
\ No newline at end of file