* Cache configurations per job
* Use separate job for Dependency submission
* Use GRADLE_OPTS to enable build and configuration cache
* Test .android
* Cache .android for configuration cache
* Disable CodeQL for PRs
* Fix AVD path
* Nextcloud Login Flow: handle non-success status codes
* Update error message to use class name when localized message is null
* Update dav4jvm to get HTTP reason phrases in HttpException
* [WIP] Use Ktor for Nextcloud login flow
- Replace OkHttp with Ktor for HTTP requests
- Update URL handling to use Ktor's `Url` class
- Adjust `postForJson` method to use Ktor's HTTP client
- Refactor URL building logic for login flow initiation
* Use Ktor for Nextcloud login flow
- Migrate to Ktor's ContentNegotiation plugin for JSON handling
- Update dependencies and configuration for Ktor serialization
- Refactor `NextcloudLoginFlow` to use Ktor's JSON serialization
* Add tests
* Allow unit tests that mock/use HttpClient without Conscrypt
* KDoc
* Minor fixes
* Use toUrlOrNull from dav4jvm
* Don't change strings in this PR
* Update dav4jvm and synctools
* Update synctools (fixes#1797, closes#1859)
* Use `com.github.bitfireAT:synctools` because `com.github.bitfireat:synctools` is not available on Jitpack for this commit
* Remove the ignore annotation
* Turn inPendingState in to a hot state flow for the test duration
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Rename methods registering the sync state observer
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
---------
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Update authentication domain parameter
- Rename `onlyHost` to `authDomain` in `fromAccount`
- Update `authenticate` method to use `domain` instead of `host`
- Clarify documentation for `authDomain` parameter
* More KDoc
* Fix other calls / tests
* Move companion object to end of class
* Update synctools
* Make DmfsTaskList final
* Use DmfsTaskList SyncState
* Drop fields now provided in DmfsTask and adapt constructors
* Use column constants from DmfsTask instead
* Use DmfsTask column constants
* Update synctools
* Don't handle scheduleTag
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Update synctools
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
---------
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Add ResourceDownloader and tests
- Introduce `ResourceDownloader` class for downloading external resources
- Add unit tests for `ResourceDownloader`
- Refactor `ContactsSyncManager` to use `ResourceDownloader`
* KDoc
- Add detailed documentation for `download` method
- Clarify authentication handling and return behavior
* Minor changes
Log warning instead of throwing IllegalStateException on multiple build calls
- Change `build()` to log a warning instead of throwing an exception on subsequent calls.
- Change `buildKtor()` to log a warning instead of throwing an exception on subsequent calls.
* Update WebDAV property names according to new dav4jvm naming scheme
* Use new supported-report-set; fix `MaxResourceSize` property reference in CalendarSyncManager
* Remove comment
- Update SyncManager to handle LocalStorageException with DeadObjectException cause
- Refactor Syncer to catch all exceptions and handle specific cases
Add @MustBeClosed annotation to buildKtor method
This commit adds the `@MustBeClosed` annotation to the `buildKtor` method in `HttpClientBuilder.kt` to indicate that the returned `HttpClient` instance must be closed by the caller. It also updates the test in `HttpClientBuilderTest.kt` to use the `use` function to ensure proper resource management.
* Increase logging level
* Adjust log levels for visibility in non-verbose logs
- Change log level from FINER to FINE in StreamingFileDescriptor
- Update log level from FINER to FINE in AccountSettingsMigration8
- Add note about log levels in LogManager documentation
* Fix KDoc typo
* Update comment
* Support viewing jtxBoard resources from debug info
* Correct value of EXTRA_LOCAL_RESOURCE_URI
* Correct comment
* Use the same intent for journals, notes, calendar and tasks
* State working task authorities explicitly
* Use edit action to not crash opentasks
* Use getViewIntentUriFor for jtx Board tasks
* Remove explicit tasks authority for jtx Board
* Remove explicit tasks authority for jtx Board
* Remove early return statement
* Dont handle jtxBoard tasks in LocalTask which is only for Dmfs tasks
* Add some kdoc to LocalTask and LocalJtxICalObject
* Use when with in list
* Add FLAG_GRANT_READ_URI_PERMISSION to the correct intent
* Correct line endings to from CRLF to LF
* Refactor ClientCertKeyManager and HttpClientBuilder
- Add logging to `ClientCertKeyManager` for better error handling.
- Update `HttpClientBuilder` to conditionally use custom trust manager and hostname verifier based on `allowCustomCerts` flag.
- Rename `customCertsUI` to `allowCustomCerts` in build configuration.
* Update trust manager and hostname verifier selection logic
- Improve logging and error handling in `ClientCertKeyManager`
* App settings: hide certificate settings when custom certificates are not allowed
* Typo
* Add AccountSettingsMigration21 to cancel pending address book syncs
* Add application context annotation
* Add log statement
* Increase account settings current version
* Add and update kdoc
* Call cancelSync via integration
* Optimize imports
* Update kdoc
* Updating log statement
* Also cancel calendar syncs
* Don't infer authority from account type
* Update kdoc
* Cancel only on Android 14+
* Cancel for all authorities and update kdoc
* Use cancelSync directly in migration
* Enable forever pending sync workaround by canceling sync adapter framework syncs on Android 14+
* Stop always returning false for pending sync state of sync adapter framework
* Cancel by request and empty bundle
* Cancel syncs for calendar, tasks, and contacts separately
* Minor edits to log statement and kdoc
* Add migration test; Update migration
* Log all extras instead of just upload flag
* Use lazy on syncFrameworkIntegration injection
* Multiple changes
- don't cancel address book accounts of all main accounts
- merge loops
* Add authority to log statement
* Replace complex state verification logic by status changed flow
* Cancel syncs account wide across all authorities
* Add some delay to allow dummy sync requests to be created
* Reduce wait until pending
* Drop Thread.sleep()
* Use a callback flow instead of mutable state flow
* Shorten first true filter
* Shorten remaining first true filter
* Merge HttpClient and HttpClientBuilder
- Remove `HttpClient` class and replace with `OkHttpClient`
- Update all references to `HttpClient` to use `OkHttpClient`
- Add new `HttpClientBuilder` class for building `OkHttpClient` instances
- Update all builder usages to use the new `HttpClientBuilder` class
* KDoc
* Integrate Conscrypt for TLS
- Add Conscrypt dependency
- Initialize Conscrypt in HttpClientBuilder
- Create ConscryptIntegration utility
* KDoc
* Make object a class, better test
* Update cert4android to the latest version (doesn't bundle Conscrypt anymore)
* Merge HttpClient and HttpClientBuilder
- Remove `HttpClient` class and replace with `OkHttpClient`
- Update all references to `HttpClient` to use `OkHttpClient`
- Add new `HttpClientBuilder` class for building `OkHttpClient` instances
- Update all builder usages to use the new `HttpClientBuilder` class
* KDoc
* Fix typo
* Also set OWNER_ACCOUNT when updating calendar because renaming account
* Add test
* Update comment clarifying content values
* Assume calendar provider is present and drop null checks
* Remove unnecessary AutoCloseable implementations and client.close() calls
- Remove AutoCloseable from NextcloudLoginFlow and DavResourceFinder
- Remove client.close() calls in various classes and tests
- Update HttpClient to remove close() method
* Fix test
* Fix annotations / KDoc
* Refactor sequence handling in calendar sync
- Move sequence update logic to SequenceUpdater
- Update LocalCalendar to use new SequenceUpdater
- Remove redundant methods from LocalCalendar
- Update tests and dependencies
* Minor KDoc
* [WIP] Proof of concept for syncing without `Event` data class
* Replace AndroidEvent2 with EventsContract
* Update synctools, refactor upload logic in `CalendarSyncManager`
* KDoc
* Update UID immediately in `ContactsSyncManager`, `CalendarSyncManager`, and `TasksSyncManager`
- Remove `OnSuccessContext.uid` from `GeneratedResource`
* Minor changes
* Handle multiple events in a single iCalendar
- Rename `processVEvent` to `processICalendar`
- Add default alarm for non-full-day events again
- Prevent NPE on null flags (used for debug info)
* Fix tests
* Define interfaces
* [WIP] Refactor sequence and UID handling in event uploads
- Refactor `generateUpload` method to return `GeneratedResource`.
- Update `SyncManager` to handle `GeneratedResource`.
- Implement sequence and UID management in `CalendarSyncManager`.
- Remove redundant `prepareForUpload` method from `LocalEvent`.
* Refactor sequence handling in uploads
- Move UID validation to `DavUtils.isGoodFileBaseName`
- Update sequence directly in iCalendar for group-scheduled events
- Rename `resourceBaseName` to `suggestedBaseName` for clarity
* Refactor sequence / UID handling in contact uploads
- Update `LocalAddress` interface to include `updateUid` method
- Modify `ContactsSyncManager` to handle UID generation and update
- Remove redundant UID handling in `LocalContact` and `LocalGroup`
- Adjust code style settings for right margin
* Remove redundant UID update from `ContactsSyncManager` and `CalendarSyncManager`
* Implement UID handling in `TasksSyncManager` for uploads
* Update JtxSyncManager
- Update `JtxSyncManager.kt` to implement the `generateUpload` function.
- Update `LocalJtxICalObject.kt` to include the `updateUid` method for updating UIDs in the collection.
* Remove deprecated `prepareForUpload` method from `LocalResource`
- Remove `prepareForUpload` implementations from `LocalContact`, `LocalEvent`, `LocalGroup`, and `LocalTask`
* Rename `isGoodFileBaseName` to `isGoodFileName` in `DavUtils`
* Fix tests
* Move UID generation logic to `DavUtils.generateUidIfNecessary`
- Use `DavUtils.fileNameFromUid` for generating file names
- Update `ContactsSyncManager`, `CalendarSyncManager`, `TasksSyncManager`, and `JtxSyncManager` to use new utility methods
* Add tests for DavUtils
* Some tests
* Refactor onSuccessfulUpload
* Update KDoc
* Logging
* Remove unnecessary LocalEvent method
* KDoc
* Simplify LocalResource interface
- Remove generic parameter from LocalResource interface
- Update all implementations to reflect the change
- Adjust related test cases and exception handling
* Fix tests
* Update view item on sync error string
* Remove view item action from notification
* Show button in debug info screen to jump to problematic event resource
* Move companion object to the end of activity class
* Add local resource dump to intent
* Add kdoc
* Add some comments for not yet implemented resources
* Don't export DebugInfoActivity
* Send intent instead of URI and launch from DebugInfoActivity
* Add option to view problematic contact
* Extract intent builder logic to another method
* Add option to view problematic contact
* Minor changes for readability
* Extract dump string creation to interface method
* Pass Uri instead of intent and create view local resource intent in DebugInfoActivity
* Use androids existing getContactLookupUri method
* Remove extra variable
* Remove obsolete val declaration
* Rename dump to summary
* Refactor code structure for local resource URI handling
* Update code structure to use getDebugSummary for local resource summaries
* Update exception handling in SyncNotificationManager
Change the catch block to handle all `Throwable` exceptions instead of just `OutOfMemoryError`. This ensures that any potential issues arising from providing information about the local resource are caught and ignored.
* Add "copy remote URL" action
* Use string resource
* Truncate contact, task, and event strings to 1000 characters
* Fix tests
* Minor changes
- Replace `ContactsContract.RawContacts` with `RawContacts` in `LocalContact.kt`
- Remove unnecessary newline in `LocalJtxICalObject.kt`
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Using `SecureTextField`
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* `OutlinedSecureTextField` doesn't support `readOnly`
* fixed string conversions
* - Update AddWebdavMountScreen to use enabled instead of readOnly
- Ensure onKeyboardAction checks canContinue before proceeding
- Update UrlLogin and EmailLogin to ensure onKeyboardAction checks canContinue before proceeding
- Update InputDialogs to ensure confirmEnabled is checked before proceeding
* Use get() for deriving things from a mutable state
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Change context to default dispatcher on updating automatic sync when renaming account
* Minor changes
- add worker thread annotations
- use injected defaultDispatcher
* Add tests
* Apply withContext with default dispatcher on the whole rename method
Update dependencies and modify AboutActivity to use dynamic library loading
- Remove outdated aboutlibraries.json
- Update AboutActivity to dynamically load libraries using LocalContext
- Replace InvalidRemoteResourceException with InvalidICalendarException in sync managers
- Bump dependency versions for various libraries including mikepenz-aboutLibraries, okhttp, and unifiedpush
- Adjust build.gradle.kts and gradle/libs.versions.toml for new plugin and library versions
* Fix state matching logic in AndroidSyncFrameworkTest
- Add `fullMatch` parameter to control whether all expected states must be present
* Ensure non-optional expected state matches actual state
* Remove unused rule / variable
* Adapt test
- Update `onStatusChanged` to override the interface method.
- Replace custom assertion with `assertTrue` for state comparison.
* Use SensitiveString for passwords to prevent them from being logged by `toString()`
* Add test
* Fix other tests
* Credentials: equals / hashCode not needed anymore
* Add tests for equals
- Remove scheduleTag assignment in LocalGroup update method
- Refactor LocalGroupTest to use @Before and @After annotations
- Add new test case for update method in LocalGroupTest
* Configure Dependabot for Gradle dependencies
Add Gradle dependency management configuration to Dependabot.
* Update dependabot.yml to ignore specific Kotlin and KSP dependencies
* Finish activity after deleting
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added proper toast for when the account is deleted
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Simplify logic
* Missing fix
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* [WIP] Refactor LocalResource interface and implementations to use immutable properties and add deleteLocal method
* Use `Optional` for `fileName` in `clearDirty` methods, update syncManagers
* Update synctools
* Refactor LocalCalendar to use AndroidRecurringCalendar for event operations
* Use AndroidCalendar.findEvent
* Update SyncManager to process fileName, eTag, scheduleTag and flags
* SyncManager: make ETag and Schedule-Tag processing more understandable
* Make upload handling more clear
* Update synctools
* Fix bottom bar color on custom tabs
* Removed themind
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Refactor openDocument operation to use OsConstants for mode parsing
* RandomAccessCallbackWrapper: refactor so that it's only purpose is to avoid the memory leak
* Use main looper instead of a new thread per RandomAccessCallback
* Remove WebDAV access notification
* Remove nsk90-kstatemachine dependency
* Simplify fileDescriptor() method
* Use dedicated I/O thread again; use Kotlin `copyTo` for copying
* Handle `SecurityException` for `acquireContentProvider`
* Added optional `throwOnMissingPermissions` arg to `acquireContentProvider`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Set `throwOnMissingPermissions` to `true`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Adapt comments, remove now unnecessary try/catch in AccountSettingsMigration20
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Remove WebdavScope as it is no longer needed
* [WIP] DavDocumentsProviderImpl
* [WIP] Move DavDocumentsProvider to BaseDavDocumentsProvider and implementation to DavDocumentsProvider
* Adapt tests and DI
* [WIP] Implement Command pattern
* Finish Command pattern, add deprecation notices
* Unify DavDocumentsProvider with wrapper again
* Get rid of DavDocumentsActor
* Add notes about lifecycle, remove shutdown
* Choose real or fake (for tests) SyncAdapter over DI
* Minor changes
* Rename SyncAdapterServicesTest.kt to RealSyncAdapterTest.kt
* Group sync adapter / sync framework classes into new package
* Cache SyncAdapter in SyncAdapterServices
* Add documentation to SyncAdapter interface and rename RealSyncAdapterTest to SyncAdapterImplTest
* Clarify optional fields in UI
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Add icons to add webdav mount screen
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Add title to group mount point address and name
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Use assistant composable
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
---------
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* [WIP] Update synctools
* Refactor LocalEvent to use LegacyAndroidCalendar for event operations
* Refactor LocalEvent to use LegacyAndroidCalendar for event operations
* Update cert4android to get 16 kB page size support over Conscrypt 2.5.3 (#1581)
* Move SyncState to resource package because it's not in the database (#1585)
* Update dependencies, including dav4jvm that updates okhttp to 5.x (#1593)
* Update dependencies, including dav4jvm that updates okhttp to 5.x
* Update mockk and okhttp
* Bump version to 4.5.2-beta.1
* Move Insert/update to DAO (#1587)
* Move homeset insert/update logic from repository to DAO; add thread-safety test
* Rename insertOrUpdateByUrlRememberSync
* Fix exceptions being fetched as `Parcelable` instead of `Serializable` in `DebugInfoActivity` (#1597)
Typo: replace `getParcelableExtra` with `getSerializableExtra`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Bump version to 4.5.2
* Fetch translations from Transifex
* Add documentation and handle missing event in LocalEvent
* Minor changes
* Rename `event` to `getCachedEvent()` to make it more clear what it does
* Update SEQUENCE after successful event upload more explicitly
* Update sequence after successful calendar event upload
* Remove deprecated add() method from LocalResource
* Update KDoc
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Sunik Kupfer <kupfer@bitfire.at>
Co-authored-by: Arnau Mora <arnyminerz@proton.me>
* [WIP] Update synctools
* Refactor LocalEvent to use LegacyAndroidCalendar for event operations
* Refactor LocalEvent to use LegacyAndroidCalendar for event operations
* Update cert4android to get 16 kB page size support over Conscrypt 2.5.3 (#1581)
* Move SyncState to resource package because it's not in the database (#1585)
* Update dependencies, including dav4jvm that updates okhttp to 5.x (#1593)
* Update dependencies, including dav4jvm that updates okhttp to 5.x
* Update mockk and okhttp
* Bump version to 4.5.2-beta.1
* Move Insert/update to DAO (#1587)
* Move homeset insert/update logic from repository to DAO; add thread-safety test
* Rename insertOrUpdateByUrlRememberSync
* Fix exceptions being fetched as `Parcelable` instead of `Serializable` in `DebugInfoActivity` (#1597)
Typo: replace `getParcelableExtra` with `getSerializableExtra`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Bump version to 4.5.2
* Fetch translations from Transifex
* Add documentation and handle missing event in LocalEvent
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Sunik Kupfer <kupfer@bitfire.at>
Co-authored-by: Arnau Mora <arnyminerz@proton.me>
* [WIP] Refactor LocalEvent to delegate to AndroidEvent
* Move tests
* Use test rules from synctools
* Add null check for content provider client in JtxSyncManagerTest
* Update dependencies, move OkhttpClientTest
* Refactor LocalCalendar to wrap AndroidCalendar
* Update bitfire-synctools to 1a613d5d3c
* [WIP] Refactor LocalEvent to delegate to AndroidEvent
* Move tests
* Use test rules from synctools
* Add null check for content provider client in JtxSyncManagerTest
* Update dependencies, move OkhttpClientTest
* Add Fastmail OAuth login implementation
* [CI] Run tests on API level 36, too
* Add Fastmail OAuth login support
* Remove logging and move companion object to bottom
* Remove FastmailLogin and GoogleLogin to OAuthLogin and OAuthGoogle
- Remove FastmailLogin class
- Refactor GoogleLogin class to OAuthGoogle object
- Update AndroidManifest.xml to use ${applicationId} for OAuth redirect URI
- Add OAuthFastmail object for Fastmail OAuth integration
- Update GoogleLoginModel and FastmailLoginModel to use OAuthGoogle and OAuthFastmail respectively
- Add OAuthIntegration object for shared OAuth functionality
* Update Fastmail authentication error message and add redirect URI documentation
* Add error handling for refresh token exception
* Update sync stats to store sync data type instead of authority
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Use a real authority in the tests
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Replace authority with syncDataType in sync managers
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Minor changes
- import index
- edit comments
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Use lowercase localised strings for datatypes
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Pass sync data type extra as string
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Remove unknown datatype
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Move datatype name strings to collection screen section
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Update string usages
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Update test
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Add any type annotations to arrays
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
---------
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Implemented sort order
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Fixed column name
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Implemented sort order
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Fixed column name
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Improved issues
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Add test for WebDavDocumentDao.getChildren for ORDER BY
* Converted getChildren into a raw query
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Fix formatting of SQL query in WebDavDocumentDao
* Refactoring
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Drop comment
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Changed default sort to show directories first
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Fixed tests
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Switched to query constructor instead of in-place
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Changed log method
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Add DocumentSortByMapper to handle orderBy mapping for WebDavDocument queries
* Rename DavDocumentsProviderTest to DocumentSortByMapperTest and update test method name
* Refactor sorting and mapping
* Add "order by name" as last criterion
* Remove default sort order constant from DocumentSortByMapper and use WebDavDocumentDao.DEFAULT_ORDER instead
* Adapt comments
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Move distributor set/get to PushRegistrationManager
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Handle unsubscription after manual distributor change before resubscribing
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Minor changes
* Update distributor check to use method of the own class
* Use mutex and add KDoc
* UnifiedPush registration: add service type to "message for distributor"
---------
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
Co-authored-by: Arnau Mora <arnyminerz@proton.me>
* SyncManager: Handle CancellationException in sync process
* Wrap remote resource operations with runInterruptible; provide suspending SyncException wrappers
* Update more sync methods to use runInterruptible only for the HTTP request itself
* Make downloadRemote methods suspendable and use runInterruptible for better concurrency handling
* Update code style
* Fix tests
* Refactor SyncException to use runBlocking for wrapping resources
* Introduce coroutine dispatcher for sync operations
* Make `logSyncTimeBlocking` and `insertOrReplace` suspend functions
* Suspend first bunch of SyncManager methods; move sync dispatcher usage to SyncManager
* [WIP] Fix tests
TODO: extract test framework changes to separate PR
* Remove mainDispatcher from SyncManagerTest
* Remove explicit coroutineScope naming
* Move LoggerModule to di package and add TestLoggerModule
* Remove main dispatcher injection and use runTest directly
* Add verbose logging module for tests
* Add test for UnifiedPushService.onUnregistered
* Use ical4android that removes ClassLoader checks; refactor SyncDispatcher
* [Tests] Add SyncDispatcher provider for tests
* Add sync dispatcher with fixed thread pool
* Replace fixed thread pool context with thread pool executor (as we had it previously, but without setting the contextClassLoader)
* Replace sync dispatcher with I/O dispatcher with limited parallelism
* DavHomeSetRepository, DavServiceRepository: apply new naming scheme for (non-)suspending calls
* AccountRepository: apply new naming scheme for (non-)suspending calls
* Update repository methods to new naming scheme
* Remove packaging resources exclusion and configurations
* Update mikepenz-aboutLibraries to 12.1.0-rc03 and configure resource merging for LICENSE files
* Update subscriptions when collection is (un)selected for sync
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Remove collections change listener and its hilt module
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Remove observer pattern to listen for collection changes
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Update push subscriptions when collection is (un)selected for sync
* Update collection selection listener to use lazy initialization
* Update push subscriptions and sync when collection is (un)selected for sync
* Update app/src/main/kotlin/at/bitfire/davdroid/ui/CollectionSelectedUseCase.kt
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Move CollectionSelectedUseCase to account package
* Add test for CollectionSelectedUseCase
* Inject application scope instead of using a factory
* Update tests to run on our main dispatcher
---------
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Upgrade about libs to 12.1.0
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Update AboutLibraries version to 12.1.0-rc02
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Handle non-existing account gracefully when (un)subscribing collections
* Unsubscribe from all (subscribed) collections when no push distributor is selected
* Upgrade UnifiedPush Connector to 3.0.4
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Updated overrides
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added storing keys and auths
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Excluded tink
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Fixed deprecations and calls
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Integrate UnifiedPush 3.x connector and FCM distributor
* Integrate UnifiedPush connector 3.x, use VAPID and message encryption
* [WIP] Refactor push registration logic and remove deprecated methods
* [WIP] Remove PushRegistrationWorkerManager and refactor PushRegistrationManager
* Remove unused service repository dependency and update worker to suspend
* Add suspend modifier to DAO methods and repository methods
* Add runBlocking to getByService call in CollectionListRefresherTest
* Add documentation for UnifiedPushService and PushRegistrationManager
* Add fallback for push messages without topic
* [WIP] Add UnifiedPushService test with workaround for PushService binder
* Update UnifiedPush library version and clean up test code
* Refactor push message handling, synchronization and coroutines
* Add coroutine dispatchers for push registration and unregistration
* Add async support for push subscription updates
* Refactor unsubscribe logic into reusable method
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Perform delayed sync on a collection UI change
- sync state
- force-read-only state
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Use withContext to access DB on background thread
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Remove return comment
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Extract delay value to constant
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Use accountRepository to create account from name
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
---------
Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
* Extract notification handling to separate class
* Notify user at sync if content provider is missing
* Dismiss only content provider specific notification
* Remove title from notification text body
* Move sync warning strings into their own block
* Add KDoc, duplicate method for clarity
* Show message in notification for disabled tasks apps
* Pass authority through method calls
* Shorten method names
* Don't show content provider error notification when missing permission
* Rename methods and remove obsolete var
* Add spacing in content provider missing warning
* Improve kdoc
* Remove obsolete tasks provider error messages
* Syntactic sugar
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Added timestamp to debug info
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added timestamp to `DebugInfoActivity.IntentBuilder`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Show local time and UTC of timestamp
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Add LocalTestAddressBookStore.kt
* Update tests acquiring local test address books
* Remove unused methods from LocalTestAddressBook
* Extract dirty check methods to the single test class using them
* Remove unused read only flag
* Drop obsolete context
* Reusables as properties
* Rename LocalTestAddressBookStore to LocalTestAddressBookProvider
* Minor changes
* Remove test address book after provision finishes and don't remove all before
* Fix more tests by removing address book accounts after run, not before
* Wrap provision method call in try-finally
* Rename provide methods anonymous function param for clarity
* Extract account recreation to variable
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Use seeded random number generator for a 100% deterministic test result
* Fix typo
* Rename variable
* Mock random numbers and assert corresponding record is found
* Move companion object to the end of class
* Skip login type selection when logging in via intent
* Skip login type page if not default login type
* Add test for implicit email intent
* Fix test
* Update KDoc
* Refactor URI handling in LoginActivity and StandardLoginTypesProvider
* Skip login type page if intent is clear, but don't skip when using defaultLoginType
* Log unclear intents
* Use data class instead of pair
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Add AccountSettingsMigration20 to handle collection ID migration for syncer
* Add success path tests for address books and calendars
* Increase CURRENT_VERSION, fix task list store
* Update ical4android
* Match DB collections with content provider collections via ID
* Minor renaming and KDoc
* Move string constant to companion object
* Update KDoc
* Use getOrDefault to be more explicit
* Remove exception throw on missing collection ID
* Rewrite LocalAddressBookStoreTest
* Minor changes
- remove unused param
- make companion methods internal
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* [WIP] Use Hilt for HttpClient.Builder
* Inject Provider<HttpClientBuilder> when necessary
* Proxy support
* [WIP] Tests
* Fix tests
* Minor changes, enable cache support again
* Update HttpClient to use modern TLS connection specification (disable TLS 1.0 and 1.1)
* Use real CredentialsStore
* Add AppTheme to previews
* Show warning when contacts or calendar system apps are missing or disabled
* Change android icon to database missing icon
* Remove duplication
* Use packageChangedFlow to observer live changes
* Send user to settings app when deactivated and manual when missing
* Find whether content provider app is available by authority
* [WIP] Minor changes
* Open "Manage apps" instead of manual
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Split pair of show only personal settings
* Create and consume showOnlyPersonal settings separately
* Fix showOnlyPersonal flow state change not triggering re-emission
* Combine if statements
* Minor refactoring (lift out "if")
* Create separate reload methods
* Reload on model creation
* Use viewmodel scope
* Move init after relevant method declarations
* Add kdoc
* Remove deprecated getShowOnlyPersonalPair
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Test loginFromIntent
* Fix given URI
* Add test
* Use URI authority directly
* Add test for implicit intents
* Add URI port only if not -1
* Modify URI using Java URI
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Collection list refresh: Don't update home sets that have been fetched already
* Expand testDiscoverHomesets for personal flag
* Add comment
* Rename property; Update its kdoc
* Make class properties function params
* Extract home set class and property definitions for home set discovery
* Pull out HomeSetClassName and property names
* Minor KDoc changes
* Move collection and principal query properties
* Make properties private
* Make collectionProperties service-specific; drop unused SupportedAddressData
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Make entity properties immutable where possible
* Make WebDavDocument room entity fully immutable
* Make HomeSet room entity fully immutable
* Make Collection room entity fully immutable
* Minor change
* KDoc, use transaction for combined read/write access
* Minor changes
---------
Co-authored-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Moved account renaming to `LocalTaskListStore` and trying to fix issue
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed missing import
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Improved renaming algorithm
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added `asSyncAdapter`
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Split account renaming responsibility
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Split account renaming responsibility
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Got rid of unused `SettingsManager`
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Simplified updateAccount on LocalDataStore
* Added explanatory comment
* Changed provider acquiring to the store one
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* LocalTaskListStore takes provider name instead of authority
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Got rid of throws
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Simplified expressions
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added renaming of calendar accounts
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Fixed imports
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Moved calls to try-catch
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Typo
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Ignore exceptions of every store.updateAccount()
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* [WIP] Adapt SyncResult
* Remove numeric stats (not well-defined and not really used)
* Pass "too many retries" or "database error" back to sync framework on hard errors
* Migrated to using timezone id directly
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* added tests for collection timezone
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed calendar definition
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added missing line break
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Unnecessary forced null
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added ksp.incremental
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Version is now 16
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Comments cleanup
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added automatic migrations tests
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Renamed block to assertionsBlock
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added comment
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Got rid of extra comments
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Got rid of PR url
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added column drop with try-catch
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added `SdkSuppress`
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added version check for column drop
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Included SDK 34
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Commit recover
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* DB tests: inject Context
* DB migration tests: validate in target schema version; manual migration definitions: use new Kotlin syntax
* Use auto-migration instead of manual migration.
- No manual DROP COLUMN required.
- Added support for migration of unparseable VTIMEZONE.
* Update ical4android
* Service detection: ask for calendar default timezone (+ ID)
* Remove dropColumn because we don't need it for the current migration.
Leave the v4 -> v5 migration as it is.
* KDoc
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Enforced edge-to-edge
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed bottom padding
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Recovered ime padding
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Updated theme colors for intro
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Always using light primary color in intro
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Simplified settings
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added disabling of top padding
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Improved syntax
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed padding
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Add comments
* Use default fallback colors for status/system bar instead of transparent
- With transparent, system bar buttons are white on very-light-grey
* Use safeContentPadding for intro
* Use scrim color from theme
* IntroPage: correctly consume insets; Assistant: KDoc/example
* Branding box extends to upper edge
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Set correct navigation bar color, if applicable
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Let content shine through navigation bar / especially for lists like settings
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Brand background is no longer padded
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Window insets are now consumed by AppTheme
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed padding
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Do not consume insets
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Move content
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Enabled E2E in intro
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* [WIP] Move local collection management from companion objects to LocalDataStore
* Move Syncer.getLocalCollections to LocalDataStore.getAll()
- note that things like the "sync_enabled" Android calendar flag are not supported and always set to true
* Minor changes
* Implement LocalJtxCollectionStore
* Implement LocalTaskListStore
* Fix tests
* Drop initialUserData
* Address book read-only applies to entries of address book itself, so moving to LocalAddressBook
* KDoc, shouldBeReadOnly
* Test accountName
* Remove obsolete address book factory
* Test create address book
* Test createAccount
---------
Co-authored-by: Sunik Kupfer <kupfer@bitfire.at>
* Store subscription expiration in DB
* Regularly run PushRegistrationWorker, if needed
* Skip re-registering subscriptions that are not about to expire
* Add back-off for PushRegistrationWorkerManager
* Request expiration in 3 days
* Show expiration in UI, timestamps in seconds
* Fix tests
* Always evaluate read only
* Extract read only evaluation to companion method
* Extract read only evaluation to companion method
* Add test
* Always pass forceReadOnly flag
* Minor KDoc changes
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* LocalAddressBook: move contacts when renaming the address book account
* Don't make contacts dirty when moving
* Move isDirty to tests because it's only required for tests
* We don't have to set the user-data twice
* Add test for groups
* Always show "WiFi SSID card" in account settings when SSID restriction is active and adapt content according to whether all conditions are met or not
* Move explanation to top and add paragraph
* Remove unnecessary parenthesis
* Use two text composables and no spacer
* Fix preview
* Fixed surface color in dark theme
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Account screen: higher contrast for collection cards
* Account screen: use normal instead of elevated cards
* Adapt colors of card lists
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Syncer: make sure collections which are deleted are not synced
* Syncer: log when local collection is removed
* Update KDoc and tests
* Handle all CRUD work in updateCollections
* Update naming, KDoc, tests
* Minor changes (KDoc, naming)
* Log warning instead of throwing exception when not possible to find account for address book account
* Run sync and accounts cleanup in migration
* Rename accounts in migration
* Run account settings migrations on background thread
* Revert "Run account settings migrations on background thread"
This reverts commit 6b578da4f1.
* Add tests for AccountsCleanupWorker
* Move companion object to end of class
* Don't use AccountRepository for address book accounts
* Update account user data in LocalAddressBook
* Minor changes (naming etc)
* Add log line when migrating
* Try to fix test error
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Upgrade dav4jvm
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* separate CalendarTimezone and CalendarTimezoneId
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed timezone name setting
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed `VTIMEZONE` conversion
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Using text instead of CDATA
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed spec
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added comment
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Renamed `timezoneDef` to `timezoneId`
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Upgrade dav4jvm
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* separate CalendarTimezone and CalendarTimezoneId
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed timezone name setting
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed `VTIMEZONE` conversion
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Using text instead of CDATA
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed spec
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added comment
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Renamed `timezoneDef` to `timezoneId`
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* [CI] Update workflows to Java 21
* Set default value of the timezone state to null
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Add account name to address book account name
* Add parenthesis for account name and a hashtag for the collection id
* Use the correct id
* Move DI entry point to where it is used
* Sync worker management: move logic from companion object to new class
* Fix tests
* Move re-sync inputs from [OneTimeSyncWorker] to [BaseSyncWorker] as they're processed there
* Remove useless Companion
* Document that AccountSettings shouldn't be used in the main thread
* Throw exception when AccountSettings are used on the main thread
* Don't access AccountSettings on main thread
* Don't access AccountSettings on main thread
* Don't access AccountSettings on main thread
* Acquire account settings via address book account
* Extract the code to find an address books main account to the account repository
* Use collection id as reference in address book account
* Remove obsolete baos
* Find main account directly from collection in SyncManager
* Require main account to get account settings
* Stop deleting address book accounts without a main account, since they may exist on their own now
* Require content provider and introduce static deleteByCollection method
* Update KDoc
* Show all address book accounts separately
* Drop mainAccount method
* [DI] Use AssistedInject for LocalAddressBook
* Renaming, remove "main account" concept
* Fix debug info
* AccountsCleanupWorker: Rename main account to account
* Further remove main accounts
* Reduce redundancy
* AccountSettings: check account type
* AccountSettingsMigrations: drop v5 -> v6 migration (not tested anyway)
* AccountRepository: directly delete accounts
* Remove obsolete workerAccount
* Get all address books, even if not sync enabled
* Delete orphan address book accounts
* Rename two more occurrences of main account concept
* AccountSettings: allow test accounts
* Syncer: rename methods for clarity, add KDoc
* Drop empty test class
* Make code more readable and add comment
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Disabled `CoroutineCreationDuringComposition` in lint
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Moved disable
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Update ical4android
* Use standard content provider in TaskSyncer
* Check version instead of acquiring TaskProvider
* Add sync result error
---------
Co-authored-by: Arnau Mora <arnyminerz@proton.me>
* Fix overlapping method name and use interface everywhere
* Fix overlapping property name
* Update logger usage
---------
Co-authored-by: Arnau Mora Gras <arnyminerz@proton.me>
* Passing `collection` directly
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed imports
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Fix tests
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Log sync time using repository; no need for account/service check anymore
* SyncManagerTest: don't write SyncStats to DB
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Use address book contacts content provider provided by syncer
* Close any acquired content provider after sync
* Acquire/Check task provider provider as preparation step
* Provide sync arguments at syncer creation
* Acquire ContentProviderClient in syncer implementations
* Generalize sync algorithm in Syncer
* Use contacts authority for address books
* Generalize sync algorithm in CalendarSyncer
* Generalize sync algorithm in SyncerTest
* Generalize sync algorithm in TaskSyncer
* Rename preparation method and add an after sync method
* Generalize sync algorithm in JtxSyncer
* Generalize sync algorithm in AddressBookSyncer
* Use repositories instead of DAOs
* Replace deprecated log statements
* Use generic type for collection types
* Infer authorities when possible and pass only task authorities along
* No need to close TaskProvider explicitly
* Use colors only where needed
* Use provider with auto closable
* Get sync collections in syncer implementations
* Delete syncer test
* Pass provider through methods instead of using lateinit property
* Reorder constructor arguments
* Remove trailing commas
* Remove obsolete undocumented conditional
* Reorder methods
* Reorder methods
* Abort sync when preparations fail
* Drop obsolete permission check
* Use generics for url and delete
* Use generic for update
* Use generic for syncCollection
* Rename create to createCollection for consistency
* Revert "Rename create to createCollection for consistency"
This reverts commit 0fee4fe7fcf3ec8ef965c9a2e0db991a1bbbbcf7.
* Revert "Use generic for syncCollection"
This reverts commit ae129fd17e06146a1e9f8631e3cdbd2dc0a4db06.
* Revert "Use generic for update"
This reverts commit 42dd665851ba83a75bb498b98bd56624e2b09647.
* Revert "Use generics for url and delete"
This reverts commit 7ae1425039656d4a9937628ca1799ce8c59ceebb.
* Move delete() to LocalCollection
* Move url to LocalCollection
* Fix local test collection
* Minor changes
* Minor changes
- make sync private
- use to autoclose provider
* Query for sync collections once only
* Add KDoc and update comments
* Make property a local variable
* Update KDoc
* Add back ose conditional
* Remove blank line at beginning of method
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Use test account type (without sync adapters as side effects) for instrumented tests
* Provide standardized way to get test account; re-enable LocalAddressBookTest
* [WIP] Use NotificationRegistry to post notifications
* Replace NotificationUtils by NotificationRegistry
* Re-factor SyncConditions; move tests to default location
* Describe notification channels
* Use per-resource Guava cache with weak keys and values as WebDAV page cache
* Replace ExtendedLruCache by Guava cache
* Use injected logger in DavDocumentsProvider
* Use DI for RandomAccessCallback, move Wrapper to outer class
* Fix tests
* Use Hilt for more classes
* Use Guava LoadingCache as page cache
* Fix tests
* Minor code change
* Update dnsjava, use desugaring with nio, refactor DNS resolving
* KDoc
* Rewrite bestSRVRecord test
* Add pathsFromTXTRecords tests
* Add desugaring note
* Rename @AssistedFactory method to "create"
* testBestSRVRecord_MultipleRecords_Priority_Same: broaden range for distribution
* Use DI for AccountSettings
* AccountSettings: clarify different account variables
* Fix tests
* Inject @ApplicationContext instead of Application
* Add Hilt rule to various tests
* Fix tests
* Consequently use injected @ApplicationContext in Android tests; fix Hilt rules
* LogcatHandler: log source class as tag and not in the text, remove max length
* Separate LogManager and Logger usage
* Improve StringHandler for DavResourceFinder
* Tests, KDoc
* Provide collection to CalendarSyncManager
* Provide collection to ContactsSyncManager
* Provide collection to JtxSyncManager
* Provide collection to TasksSyncManager
* Provide collection to SyncManager
* Fix test
* Minor changes
* Add kdoc
* Minor changes
- added KDoc
- SyncManager can never handle address book authority (content
authority for contacts is contacts authority)
- moved @UsesThreadContextClassLoader to respective sync manager
* Mock collection in test
* Add comments separating the sync process into separate steps
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Drop address book provider
* Drop address book sync adapter service
* Replace address books authority with contacts authority
* Update kdoc
* Revert "Update kdoc"
This reverts commit dfb14d466f6c58d9422e59c770e0a5348a497b7d.
* Revert "Replace address books authority with contacts authority"
This reverts commit 0e15bf11b3235dfbc38696741100210fbe497dbd.
* Don't enable addressbook sync for main account
* Acquire content provider in Syncer
* Use contacts authority instead of address book authority when acquiring content provider
* Set default sync interval for address book authority again
* Minor re-ordering of lines
* Add comment, rename variable
* Move SyncAdapterServices out of adapter package
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Migrated into to compose
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Got rid of AppIntro
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Imports cleanup
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Imports cleanup
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Removed padding
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* When launching intro, going back closes the app
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added content description
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Moved IntroActivity.Model to IntroModel
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Given fixed padding
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Moved intro composables together
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Do not create new task
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Minor changes
* Remove last XML styles that were required for AppIntro
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* [wip] Create worker for push registration and call it from someplace in UI
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* [wip] Subscription registration request
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Don't enqueue push registration worker from UI
* Enqueue PushRegistrationWorker on collection changes
* Fix tests
* Update dav4jvm; Use new post method
* Remove obsolete context
* Add get and deleteAll methods to serviceRepository and update usages
* requestPushRegistration: make endpoint an argument
* Update push subscription fields in DB on successful registration
* Don't create notification channels in test class
* Remove workmanager init and provide empty set of listeners in tests
* Require network connection to run PushRegistrationWorker
* Move module declaration to a separate TestModules interface
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: Sunik Kupfer <kupfer@bitfire.at>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Call collection updates and setters only from repository
* Make collection repository changes observable
* Add kdoc
* Add basic test
* Extract RefreshCollectionsWorker; move some HomeSetDao calls to DavHomeSetRepository
* Replace more HomeSetDao calls
* Remove duplicate copyright notice
* Drop weak reference for observers
* Rename method
* Remove test service after run
* Verify notifying works with mockk
* Rename test
* Use construction injection
* Remove unused SettingsManager
* Remove obsolete mockk rule
* Use runBlocking instead of runTest
* Change to observer linkedList to mutableSetOf, remove synchronized calls
* Change to hilt multibinding
* Remove some unnecessary lines; allow empty set by Hilt
* CollectionListRefresher: delete collections using repository
* deleteRemote: call callback too; adapt KDoc
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* MKCALENDAR: wrap supported compoents in <CALDAV:supported-calendar-component-set>
* MKCALENDAR/MKCOL body generation: use Property.Name from dav4jvm instead of own strings
* [WIP] Colors
* Update navigation drawer
* Update colors
* [WIP] PermissionSwitchRow night mode
* Fix PermissionSwitchRow icon in night mode
* Use more intense colors for FABs
* Use correct account name when retrieving service
* Rename method, add kdoc
* Address books: require main account and use as Account
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Fixed padding for "Show only personal checkbox"
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Aligned text correctly
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Select nextcloud login type on nextcloud setup intent
* Fix linting error
* Add documentation
* Move model creation to compose LoginScreen
* Minor changes
- Use boolean to decide on skipping startPage
- Move login type selection logic to login types provider
* Minor changes
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Extract composables
* Drop sub component previews and minor adjustment
* Fix preview
* Extract view model
* Switch to M3
* Extract URI to Constant
* Minor changes
* We alway have AccountSettings
* Replace LiveData by State
* Use Snapshot.withMutableSnapshot in reload
* Don't show empty OAuth setting
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Refine chips in collection list
* Refine PermissionSwitchRow
* Collections list
* Fix WelcomePage and IntroActivity background color in dark mode
* Fix RadioWithSwitch in dark mode
* Drawer handler: branding in dark mode
* Extract composables
* Extract model and companion object
* Switch to M3
* Linting
* Drop previews for sub composables
* Minor adjustments for readability
* Minor changes
- use manual URL from Constants
- use M3 in some Composables
* Create PreferenceRepository (for now only for verbose logging)
* Move actual settings to model; M3 Composables
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* [WIP] More hilt
* Use assisted inject for AccountSettingsMigrations
* DavDocumentsProvider: inject CredentialsStore
* Create a new WebdavScope and scope caches and credentials store to it
* Fix CredentialsStoreTest
* Convert M2 calls to M3
* Extract composable to screen
* Extract viewmodel
* Make screen model independent
* Use only primitive types in screen
* Introduce uiState class and switch to compose state where easy
* Switch remaining live data to compose state
* Add kdoc
* Add scrolling, adapt buttons to M3
* Move Intent logic to Activity
- create/handle Intent in Activity (may be replaced by NavGraph in future)
- Activity: pass unpacked initial data to Screen
- Screen: use hiltViewModel (adds hilt-navigation-compose dependency) to
create model with initial data
- Screen: use Column instead of LazyColumn
* Fix test
* Optimize imports
* Minor changes
* Move AppTheme, fix showDebugInfo
* View instead of share logs; make local/remote resource smaller; make remote resource selectable
* Leave space for scrolling down past the FAB; don't show "Local resource: null"
* Re-order composables
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Added `canAccessWifiSsidLive`
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Fixed initial state
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Cleaned up code
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* More cleanup
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Removed inspection check
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Renamed function
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Using `broadcastReceiverFlow`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Simplified check
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Using `MODE_CHANGED_ACTION`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Updated comment
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Set default value for immediate
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Use derivedStateOf instead of produceState; correctly collect broadcastReceiverFlow
* Always show WifiSSID Card in Preview (otherwise Preview won't render)
* Don't call flow.map in Composable
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Soft fail sync on DeadObjectException so that it is retried without immediate error message
* Handle DeadObjectException (→ retries sync); Syncer: generalize all-catch
* Migrated to M3
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Replaced preview theme
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Fixed theme
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Forced all sets to be private
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Moved Composables and Model to individual files
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Fixed naming
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Theme / M3 changes
* Observe lifecycle from within Screen
* Minor changes
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* [WIP] Separate AccountScreen, use M3 elements
* [WIP] Use UseCases for complex flow calculations
* [WIP] Move account deletion logic into AccountRepository
* Move rename operation to repository
* Adapt FABs
* Don't use snackbars to show when the collection list is refreshed
* New collection list layout (bitfireAT/davx5#159)
* [WIP] Create AccountModel from within screen
* [WIP] Clean up AccountScreen
* [WIP] CreateAddressBook
* [WIP] Create address book / calendar screen
* [WIP] Begin CollectionScreen
* [WIP] CollectionScreen
* Error handling
* String resources
* Optimizations, remove unnecessary things
* WebDavMountsScreen: M3, refactoring
* [WIP] AddWebDavMount
* Use M3 pull-to-refresh
* AddWebDavMount, move logic to WebDavMountRepository
* Show loading state in LinearProgressBar
* Add WebDAV mount: IME action and focus requester
* Move "test WebDAV" logic from model to repository
* Move "refresh quota" logic to repository
* Move querying and deleting mounts to repository; IME navigation
* KDoc
* Move hasWebDav tests to repository
* [WIP] Rewrite login to M3 and better UI states
* Use AccountRepository to create account
* LoginModel is SSOT for page navigation
* Support forced group method
* Show progress bar when account is being created
* Make account name suggestions work again
* Use M3 text field supportText for errors
* Refactor: login by URL, login by email, advanced login
* Refactor Nextcloud login, move login flow logic to separate class
* Refactor Google login, move OAuth logic to separate class
* Fix errors when navigating back after successful resource detection
* Make PasswordTextField M3
* ManagedLogin: M3, UiState
* Updated theme; managed login functionality
* Improve back navigation
* Rename AppTheme to M2Theme, add M3 theme
* Rewrite AboutActivity to M3
* Apply M3 theme; minor optimizations
* Use M3 version of AboutLibraries
* Use material3 instead of material3-android dependency
* Use reversed theme
* [WIP] Use broadcastReceiverFlow and packageReceiverFlow
to make sure that broadcast receivers are unregistered
* Rewrite remaining BroadcastReceivers to use broadcastReceiverFlow
* TasksAppWatcher: minor coroutine changes
* KDoc
* TasksActivity: use Compose state instead of LiveData
* Check if keep-permissions changed when user comes back from settings app
* Use one model only
* Use mutable state flows
* Use compose mutable state
* [CI] Improve caching behavior
* Freshly created model can never be null
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Use Compose state instead of LiveData; reset token before starting Login flow
* [WIP] Reset state variables when needed
* Always run postForJson in IO dispatcher; show progress when polling for login data
* Reset login URL in onReturnFromBrowser
* Do not show existing password when changing
* Use PasswordTextField for password input dialogs
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Added custom Compose theme
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Got rid of accompanist theme adapter
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Removed unused import
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added actionbar to the activities that didn't have one
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Theme now always hides actionbar
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added back string
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Got rid of all color definitions
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Moved color definition to drawable
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Using Compose colors
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Using AppCompat theme
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Removed XML theme
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Moved color definition
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added bars coloring in Compose
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added dark theme
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added custom Compose theme
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Got rid of accompanist theme adapter
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Removed unused import
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added actionbar to the activities that didn't have one
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Theme now always hides actionbar
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added back string
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Got rid of all color definitions
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Moved color definition to drawable
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Using Compose colors
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Using AppCompat theme
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Removed XML theme
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Moved color definition
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added bars coloring in Compose
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added dark theme
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Changed content description
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Using `onSupportNavigateUp`
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Changed color on top of primary green
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added up navigation
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Made `onSupportNavigateUp` optional
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Typo
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Got rid of edge-to-edge
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added back some XML styles
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Simplify TasksCard calling
* Move theme colors to flavor-specific ThemeColors file
* Remove global AppTheme paddings for now
* Optimize imports
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Don't use Gradle build and configuration cache for releases
- don't enable Gradle build and configuration cache for the project, but recommend it for the developer
- explicitly enable Gradle build and configuration cache for CI test jobs
- let AboutLibraries generate lib definitions itself again
- also don't archive test results (sometimes fails and we never use the results)
* Add encryption key for gradle cache
* Only warn on configuration cache problems (caused by AboutLibraries)
The list was computed in an automated way and includes:
intro_battery_not_whitelisted
intro_battery_whitelisted
permissions_jtx_status_off
permissions_jtx_status_on
about_flavor_info
about_translations_thanks
install_email_client
accounts_global_sync_disabled
accounts_global_sync_enable
app_settings_tasks_provider_synchronizing_with
account_no_address_books
account_no_calendars
account_no_webcals
account_swipe_down
account_create_new_address_book
account_create_new_calendar
settings_title
settings_enter_username
settings_enter_password
settings_key_default_alarm
certificate_notification_connection_security
trust_certificate_unknown_certificate_found
- OneTimeSyncWorker is also started by sync framework, so it should take network restrictions into consideration
- add "manual" flag for manual syncs that ignore network restrictions
* [WIP] Don't create a separate SyncWorker for every sync (run directly within onetime/periodic sync instead)
* [WIP] address books
* Account(s)Activity: don't show pending workers
* Migration to set new periodic sync worker tags
* Fix tests
* ContactsSyncAdapter issues address book sync on main account (not contacts sync)
* SyncAdapterService: optimize blocking with Flow instead of LiveData
* Refactoring
* Better live handling of (un)installed task apps
* Minor changes
* SettingsManager: explicitly mark possibility of null LiveData values
* Fix tests
* Move homepage and other Web URLs to Constants; minor refactoring
* Use AppTheme with built-in safe LocalUriHandler instead of MdcTheme; minor refactoring
* Account settings: add TODO for Compose rewrite
* Use UriHandler instead of UiUtils.launch when possible
* Migrated AddWebdavMountActivity to Compose
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Minor changes, use PasswordTextField
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* [WIP] Add AccountActivity2 in Compose
* Make paging collections work when data changes
* [WIP] Add ProgressIndicator TODO
* [WIP] CardDAV: add swipe-to-refresh
* [WIP] Correctly use Pager
* [WIP] Only show Webcal tab when there are subscriptions
* [WIP] Implement collection properties dialog
* Implement "create collection" and "show only personal collection"
* [WIP] Add collection overflow menu items
* Show color as left border, max. 2 icons per row
* [WIP] Delete collection dialog
* Add "delete collection"
* Implement "Force read-only"
* Delete old XML classes and resources
* Add permissions warning
* Implement "Rename account"
* Case-insensitive sorting, minor changes
* Horizontal arrangement
* Less integration of Webcal subscriptions (other layout)
* Accessibility
* Collection list: provide ID als key for lazy list
* Only show "Create addressbook/calendar" when there's at least one writable homeset
* Make readOnly a LocalCollection property
* Move readOnly detection to SyncManager
* Add readOnly state access to LocalCalendar
* Add not implemented error to readOnly state access of LocalJtxCollection
* Handle read-only state of calendar at dirty events upload
* Handle read-only state of calendar at processing of locally deleted events
* Remove todo and update kdoc
* Fix indenting
* Add read-only prop to LocalTestCollection
* Add read-only state access to LocalTaskList
* LocalTestCollection: don't set read-only
* Update ical4android (for new KDoc)
* Make LocalCollection readOnly-API read only and take value from content provider during populate()
* SyncManager: use readOnly direct from localCollection
* Lift resetDeleted up to LocalResource
* Override and use resetDeleted for LocalEvent
* Add resetDeleted to LocalJtxICalObject
* Add resetDeleted to LocalTask
* Add resetDeleted to LocalTask
* Add resetDeleted to LocalTestResource
* Provide default access level
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Migrated to Jetpack Compose
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added `observeBoolean`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Simplified settings interaction
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Migrated to Jetpack Compose
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added `observeBoolean`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Simplified settings interaction
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Use SafeAndroidUriHandler instead of UiUtils.launchUri
* Removed animation for manufacturerWarning
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Removed animation for manufacturerWarning
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added `getBooleanLive`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Using `getBooleanLive`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Moved UI definitions to file scope
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Don't use specific times for waiting in tests
* Renamed function
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* More exact naming
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Add foreground notification type to expedited workers (required for Android 14)
* Make SyncWorker a long-running worker
* Don't use expedited SyncWorker for everything; handle foreground service launch restriction
* AddressBookSyncer: only request expedited for sub-jobs when parent job is expedited, too
* RefreshCollectionsWorker is not long-running -> no foreground service type needed
* Fix tests
* Don't use foreground service type in ForegroundInfo
* Make SyncWorker not long-running
* Rewrite RenameAccountFragment to compose
* Add padding to text field, disable RENAME button when old name = new name
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Show battery saver warning in account list and debug info
* Move app warnings to model class
* Debug info: more verbose text
* Restore previous strings for sync enqueued/started
* Make ranged GET requests cancellable; reduce notification update frequency
* Include original exception as a cause in WebDAV ErrnoException
* Add KDoc for threading
* Gave more flexibility
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Migrated to Compose
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Adjusted paddings
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added missing observer
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* CardWithImagE: add another preview with subtitle, icon and content
* Made buttons uppercase
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Adjusted spacings
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Changed snackbar host state
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Changed nullable expression
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Using shareFile for zip
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Minor changes (comments/formatting)
* Switched to view instead of sharing files
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Adapted image height for landscape
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* CardView: allow to pass image alignment; use card_theme_max_height
* DebugInfoActivity: paddings, images
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* WebDAV: don't try to load 0-byte segments
* Extracted segmentation logic to SegmentedReader for testability
* Reorganize and simplify caches
* Refactor thumbnail cache
* Use coroutines with Dispatchers.IO instead of custom Executor
* Remove obsolete classes
* Fix tests, simplify DiskCache
* Paging reader: cache current page
* PagingReader tests
* Thumbnails: timeout for generation and not only for waiting
* openDocumentThumbnail: actually cancel HTTP request when method is cancelled
* Better KDoc
* Add further tests
* Renamed LoginCredentialsFragmentFactory to LoginFragmentFactory
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Fixed fragment name
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Rename LoginInitFragment (managed) to ManagedLoginInitFragment
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* RefreshCollectionsWorker: use runInterruptible instead of interrupting manually
* SyncWorker: use CoroutineWorker + runInterruptible
* Use global SyncWorkDispatcher that guarantees classLoader to be set
* Set SyncWorkDispatcher for whole SyncWorker's doWork
* Remove obsolete test
* SyncManager: add structured concurrency again
* Use up to <number of processors> threads for synchronization
---------
Co-authored-by: Sunik Kupfer <kupfer@bitfire.at>
- Rewrite DetectConfigurationFragment to Compose
- Use coroutines and runInterruptible instead of Thread
- Only cancel service detection when back is pressed
* RandomAccessCallback.Wrapper: support multiple state machine instances at same time
- support multiple state machine instances at same time
- provide explicit Exception/error code when the remote server doesn't support ranged requests
* Only use RandomAccessCallback when server explicitly advertises range requests
---------
Co-authored-by: Arnau Mora <arnyminerz@proton.me>
* Minor changes
- update kdoc
- rename method and variables
* Add proxy parents to related resource detection
* Rename argument, query ResourceType
* Remove unnecessary utility method
* Change parentOf to extension function; Always return URL with trailing slash
* Use calendar-proxy-read/write ResourceType from new dav4jvm
* Use max. two levels of recursion to detect shared Google calendars
* Revise test and adapt method
* Simplify HttpUrl.parent()
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* LoginActivity: refactor menu to MenuProvider; LoginModel: add contact group type
* Take LoginModel group method into account when creating the account; Nextcloud login: set preferred contact group type
* Replace onActivityResult by contract
* Add Nextcloud option to default login screen
* Decouple NextcloudLoginFlowComposable from model
* UI and model changes
* Single-line URL field
* Add progress indicator and other secondary UI
* [WIP] Add timeout for RandomAccessCallback
* Use state machine to handle timeout
* Use sealed class for states, guard callback access with correct states
* Use tags instead of uniqueWorkNames for work queries.
* Also include address book accounts, when querying sync status.
Give address book account sync workers their parent (main account) sync workers tag too, such that they will be included at the query for sync status of their parent account.
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Low storage: don't show notification anymore, adapt info message
- The impact of low storage is not as critical anymore that a notification is required.
- Info message adapted
* Update "account settings: ignore VPN" strings
* Update "No internet" string
- use Google Play In-App Review API for private feedback on -gplay (fall back to email)
- start email intent again when "beta feedback" is selected in navigation drawer
* Doubled bottom padding
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Account activity: increase margin for two FABs even more
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Add tests for internetAvailable()
* Add tests for wifiAvailable()
* Add TODO for test case
* Add tests for internetAvailable() covering multiple network connections
* Minor KDoc
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
If a WebDAV server is misconfigured (for example, behind an HTTP proxy that
strips a URL prefix and doesn't correctly forward this to the WebDAV server)
then PROPFIND can return resources whose URLs don't match the request URL. These
are resolved by dav4jvm as HrefRelation.OTHER.
Currently this situation produces no output at all in DAVx5 (logs or app) and
the WebDAV share appears accessible but empty. It is possible to create files in
the share, but not to see them again afterwards!
Of course a misconfigured server isn't the WebDAV client's responsibility to
resolve, but adding a warning in the log provides an extra clue for anyone
trying to debug it.
* Use appropriate delayUntil value for retrying syncs on 503s.
Crop server suggested retryAfter value to self defined min/max values and use a reasonable default value if non-existent.
* Add tests for getDelayUntil
* Wait appropriate delay, before retrying sync after a soft error happened
* Increase max and default sync delays after soft errors
* Increase initial backoff time for SyncWorker retries
* Minor getDelayUntil changes
* Minor changes
- store delayUntil in seconds
- pass duration instead of timestamp to Thread.sleep
- other minor changes
* Use Instant instead of Long timestamps
* Correct calculation of blocking duration
* Indicate soft error occurred on 503 server message
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Update dependencies (including cert4android and vcard4android)
* Migrated to new version of ical4android
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Increased compileSdk
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Upgraded browser
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Only use `appInForeground` for `customCertsUi`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Removed unnecessary variable and fixed trust manager
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Cleaned up trust manager factory
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Update dependencies (including cert4android and vcard4android)
* Migrated to new version of ical4android
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Increased compileSdk
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Upgraded browser
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Only use `appInForeground` for `customCertsUi`
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Removed unnecessary variable and fixed trust manager
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Cleaned up trust manager factory
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Minor changes
* Fixed build for SDK 34
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Migrated certificate trusting
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* NetworkConfigProvider: handle invalid trusted certificate
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Arnau Mora <arnyminerz@proton.me>
* Add setting to ignore VPNs at connection detection
* Minor changes
- move methods to ConnectionUtils to keep SyncWorker class compact
- always use "ignore VPNs" as Boolean
- other minor changes
* Show ignore VPNs setting only below api lvl 23
* Change strings
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
Hopefully fixesbitfireAT/davx5#308
* Add new setAndVerifyUserData extension function to AccountManager
* Use new setAndVerifyUserData extension function instead of insecure setUserData
* Update KDoc [skip CI]
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
- use Kotlin and CompletableDeferred instead of Java synchronization
- signal cancellation by completing CompletableDeferred instead of Thread.currentThread.interrupt()
* Upgraded AGP
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Enabled automatic locale config generation
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added fallback language
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added legacy service
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added `Accept-Language` header to custom tabs
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Nextcloud Login Flow/Google OAuth: also send language tag for default locale
---------
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Added refresh collections fab
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added listener for clicks on refresh collections fab
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Adjusted sizing
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Updated tooltip and description for collections sync
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Removed Snackbar
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added warning for null serviceId
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Changed refresh collections service id fetching method
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Tooltip updates on refresh collections list
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Migrate to ViewPager2; show "Refresh collections" for WebCal, too
* Added refresh collections fab
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added listener for clicks on refresh collections fab
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Adjusted sizing
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Updated tooltip and description for collections sync
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Removed Snackbar
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Added warning for null serviceId
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Changed refresh collections service id fetching method
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Tooltip updates on refresh collections list
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Migrate to ViewPager2; show "Refresh collections" for WebCal, too
* Changed collections refresh action update method
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
* Use lambda syntax for observers
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
Co-authored-by: Sunik Kupfer <kupfer@bitfire.at>
* Comment out failing test
* Check internet connection before syncing for API 23+
* [Skip CI] Amend comments
* Comment out whole test class
* Comment out whole test class
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Hide/Show auth settings instead of removing them prevents NPE
* Provide original OAuth login email as default value for GoogleLoginFragment started from account settings
* Account settings: explicitly trim empty user name to null
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Block sync framework until SyncWorker finishes
* Bump version code for 4.3.3 (previous version code was never released publicly)
* Fetch translations from Transifex
* Release internal version automatically [skip ci]
* Update periodic sync workers when "Sync only on WiFi" flag is changed (#282)
* Update periodic sync workers when "sync only on WiFi" flag is changed
* Remove BootCompletedReceiver which was only needed to repair sync intervals (not required with WorkManager anymore)
* Bump version code to 403030006 (stays 4.3.3)
* Use unique worker name, Java notify/wait and observeForever
* Remove observer when sync finished
* Catch and ignore, but log interruption exceptions
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Move GoogleOAuth members into GoogleLoginFragment
* Require login flow capable browser and notify user if missing
* Receive AppAuth redirects only in standard and gplay flavor
* Set davx5 as user-agent for AppAuth connection builder
* Re-authentication in Account settings
* Catch unauthorized exceptions at collection refresh and notify user to re-authenticate
* Suggest email address on account creation
* Set contact groups default setting as per-contact categories for oauth logins
* Add authentication to debug info, minor other changes
* Better error handling; don't pre-set group type
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* When renaming show a toast when account with new name exists already
* Replace toasts with snackbars
* Apply code styling hints
* Move lambdas out of parentheses
* Inject application instead of context
* Replace Toast with Snackbar
* Shorten messages shown in snackbars
* Show Toast in UI instead of model; use AndroidViewModel
* Move account name check out of lock; don't close activity if not successful
* Duplicate account name check: only check for our account type
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Add new preselect_collections option and deprecate sync_all_collections option
* Optimize imports
* At refresh, decide on whether a collection should be preselected
* Add preselect_collections_blacklist setting and restriction
* Adhere to preselect_collections_blacklist setting
* Add preselect_collections values
* Also check for empty regex string and use new setting values
* Add unit tests
* Remove sync_all_collections setting and restriction
* Blacklist nextclouds recently contacted addressbook in restriction and setting by default
* Improve kdoc
* KDoc, changed setting names, minor code optimizations
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Update periodic sync workers when "sync only on WiFi" flag is changed
* Remove BootCompletedReceiver which was only needed to repair sync intervals (not required with WorkManager anymore)
* Make it clear that the first call of recursive method queryHomeSets is for the current-user-principal home set
* Update whitespace in kdoc
* Update kdoc
* Add last synced time to collection properties
* Show last synced time for every to the collection relevant authority
* Try finding the application name for given package name
* Resolve authority to package name before finding application label
* Use AndroidViewModel instead of ViewModel; change model LiveData to val
* Rewrite to Compose, use relative time description
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* AccountSettings: prevent redundant calls, move migrations to separate class
* Don't create AccountSettings while migrating
* Double thread sleep time to wait for sync framework to get disabled, and update logging
* Remove manual testing helper
* Fix tests
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Fixed toast threading
* Added `AndroidViewModel.context`
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Moved to `AndroidViewModel`
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Changed error invocation
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Added back constructor inject
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
* Save Application with val instead of util method
* Use LiveData for error message
---------
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Implement proper network check before manual sync
Do a proper connectivity check, to show a message to the user, about the sync being scheduled for when connectivity is available, before enqueueing the SyncWorker.
* Update the sync status in accounts adapter to include pending syncs
This is relevant for when a manual sync is triggered without connectivity.
* Replace Toast by Snackbar
* Replace ViewModel by AndroidViewModel
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
- disable per-app language preference for now (will be enabled again with bitfireAT/davx5#245)
- disable Jetifier (doesn't seem to be explicitly required for in-app rating API anymore)
- remove Locator dependency
- update ical4android
- add JetPack Compose dependencies
- use existing XML theme as Compose MdcTheme
- update AboutLibraries to newest version (uses Compose)
- embed AboutLibraries Compose into existing Fragment layout
ClosesbitfireAT/davx5#14
* extract WorkManager util functions and kdoc
* add PeriodicSyncWorker
* refactor and some kdoc
* use PeriodicSyncWorker and add todos
* allow SyncAdapter arguments to be passed to SyncWorker and have re-synchronization use SyncWorker
* handle sync cancellation in AccountSetting migration
* handle sync cancellation when account is renamed
* remove sync frameworks global sync setting and sync state awareness for the GUI
* Observe sync worker status in AccountListFragment
* Create setup for stepwise refactor of the sync adapters. This should keep the app from failing to build.
* Create new abstract BaseSyncer class for generic sync code. Adapt consumers and tests to use the new class.
* Move calender sync code to new CalenderSyncer class which is independent from the sync framework
* In CalendarSyncAdapterService pass sync requests from Sync Adapter Framework to SyncWorker
* Use CalenderSyncer in SyncWorker
* Move contacts sync code to new ContactsSyncer class.
* Move address book sync code to new AddressBookSyncer class
* Move jtx sync code to new JtxSyncer class
* Move tasks sync code to new TaskSyncer class
* Remove duplicate code in inherited sync adapters.
* Remove refactoring helper interface, duplicate generic sync code and some linting.
* Adapt tests for new Syncer class and move to the new package
* Remove remaining duplicate code in SyncAdapterService, add todos and edit kdoc.
* Move all the single line sync adapter services into one file.
* Remove concurrent sync runner code and its test, as we now use WorkManagers one time work requests.
* Remove SAF manual sync flag usage where unnecessary.
* Drop ability to prioritise collections for sync, as not used and hindering removal of sync adapter arguments.
* Pass simple string array to SyncWorker instead of bundle to simplify code.
* Restructure work query code.
* Get debug info from account settings and WorkManager.
* Write tests for PeriodicSyncWorker
* Test account creation will set a default sync interval for CardDAV and CalDAV
* Throw an exception if accountManager returns null for sync interval value
* Do proper interval check and add tests for AccountSettings
* Use work manager query to determine whether work is in a specific state
* [WIP] Add test to check that task provider is configured correctly on account creation
* Edit test checking that task sync is configured correctly on account creation with/without installed task app(s), by mocking TaskUtil
* Edit test such that it does not require a flaky flag
* Remove periodic sync when tasks app is uninstalled
* Bring back content triggered syncs
* Rename enqueueSyncWorker method to enqueue only for clarity
* Enable SyncAdapterFramework to cancel running SyncWorker
* Add test ensuring that SyncWorker.onStopped() interrupts the running sync thread
* Add retry policy sync on soft errors
* Check users sync conditions before enqueueing SyncWorker
* Add test for whether user sync conditions are treated correctly and kdoc
* Rename ambiguous shorthand "SAF" to "SyncFramework", as SAF usually means StorageAccessFramework
* Migration: Disable sync framework periodic syncs when interval is changed for specified authority
* Add Workers info to debug info
* Use WorkInfo.runAttemptCount to fail work after 20 soft errors
* Notify user if retry limit for soft errors has been reached
* Remove left over concurrency sync run tests prevention
* Migration: Continue to remove periodic sync framework syncs until user migration to PeriodicSyncWorker syncs is complete
* Kdoc and small changes
* Migration: Change to hard migration strategy
* Drop repairSyncIntervals method in favor of hard migration strategy
* Improve debug info of workers
* Remove sync framework periodic syncs, created by enabling content triggered syncs
* Change minimum sync interval to 15 min; minor other changes
* Fix tests
* Implement requested changes and update kdoc
* Add network connectivity restrictions to PeriodicSyncWorker
* Minor changes
* Move back sync classes to syncadapter package for now (can be separated later)
* Add KDoc
* Changes from review
* Rename test methods
* Add back global sync status warning
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Log warning if principal URL does not provide CalDAV/CardDAV service
* Unified log messages for identical cases
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Alter the SyncWorker sync request to allow passing sync arguments along
* Request sync in SettingsActivity via SyncWorker instead of ContentResolver
* Don't use catch-all arguments as worker arguments
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Changed `password` with `token`
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* Fetch script: don't use --minimum-perc 20 because it's in .tx/config
---------
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* check sync workers properly
* Move utils around
* Merge live data, instead of observing in view, to recalculate account list.
* Update LiveData with same value
* Remove unused context property.
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* provide owner url in jtx collection
* Updated contract, added owner displayname to collections sync
* Update ical4android
---------
Co-authored-by: Patrick Lang <72232737+patrickunterwegs@users.noreply.github.com>
* add principal table with dao
* add principal table with dao
* collection saves ownerId instead of owner URL
* save and refresh principals
* show display name of collection owner in GUI
* show only the owner name (preferably) or respective url
* remove principals which do not own any collections
* Don't mock AppDatabase
* ensure we are really dealing with a principal and save it even without its display name
* ensure owner label is hidden when neither owner-displayname nor owner-url are available
* save principal urls without trailing slash
* use a custom query to find principals without collections
* Some changes
- insertOrUpdateByUrl
- don't explicitly set id=0 when not necessary,
- make it work when there are already entries with trailing slahes
- added TODOs
* Small changes
- Update principal only if display name changed
- Rename methods
- Kdoc
- Tests
* stop using simple methods with vague names
* rename method insertOrUpdateOrGet to insertOrUpdate and leave existing kdoc for explanation
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* adapted JtxSyncManager, added new method in LocalJtxCollection
* minor code improvement
* inserting recurring entry as well, as the series might not have been processed yet
* version bump (preliminarily)
* version bump (preliminarily)
* Enabled automatic popup of the custom certificate dialog
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* Use chaining instead of .let
---------
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* add test fixtures
* Use direct DB access instead of DaoTools
* minor changes and kdoc
* minor changes and kdoc
* remove obsolete DaoTools, SyncableDao and IdEntity classes
* KDoc
* use hashmap instead of list and added kdoc
* always load from database
* add a test and make test structur more flexible for future tests
* minor KDoc
---------
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Reformat code
* Use sync-adapter URI to count jtx Board entries
* Debug info: restrict entry counts per withSyncAdapter URI and not over WHERE clause
* [WIP] refactor
* [WIP] refactor
* save, update and delete homesets one by one
* save, update and delete collections one by one
* cleaner code
* prevent jumps in row ids
* [WIP] small changes and kdoc
* remove duplicate code and add kdoc
* improve kdoc
* remove redundancy based on service type in resource finder
* tests setup
* handle cancellation
* add tests
* Don't use IdEntity for service detection anymore
* HomeSetDao: getByUrl requires a service (there may be two accounts with the same homeset URLs, for instance with different credentials)
* Deprecate DaoTools
* Minor changes
* Add TODO
* use self explanatory variables instead of a pair
* update kdoc
* add unfinished tests
* add test for updating a collection
* add test for preserving collection flags
* mark collections as homeless if not rediscovered in its homeset
* proper implementation of update and delete of homeless collections with test
* minor changes and kdoc
* Tests: adapt mock server 404
* KDoc
* get collections by service and url, deprecate getByUrl()
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Added `GetETag.NAME` fetching when `PROPFIND`ing
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* `GetETag.eTag` is only taken if tag is not weak
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* Using `GetETag` instead of `QuotedStringUtils` and ignoring weak eTags
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* Updated `dav4jvm`
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* Fixed checks
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* Use new dav4jvm where weak can't be null
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* added language selection
* PermissionsFragment: Hide notification permission switch on Android < 13
* Retrieve locales with a function
* Added locales flavoring
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* Moved locales functions to `locales.gradle`
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* Added `locales_config.xml` generation
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* Now gets generated automatically
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* Added `android:localeConfig`
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* Updated submodules
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
* Using `logger` instead of `println`
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
Signed-off-by: Arnau Mora <arnyminer.z@gmail.com>
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
Co-authored-by: Arnau Mora <arnyminer.z@gmail.com>
* rabase with dev branch
* added test for checking whether manual work-manager sync queues worker
* overwrite getForegroundInfo to show a "sync running" notification, to run expedited work on Android <12
* basic error state with sensible feedback from syncframework
* remove integer state flags and pass SyncResult as string
* Manual sync cancellation
* rabase with dev branch
* Minor changes
- add Jtx Board sync adapter to sync worker
- use new notification ID for sync worker
* status bar reflects sync of SyncWorker and sync framework correctly
* [WIP] custom hilt SyncComponent
* fix autoclose cast not available below api24
* SyncScope implementation using WeakReference
* Remove unnecessary logging call
* AddressBooksSyncAdapter.sync uses SyncWorker instead of ContentResolve to call requestSync
* add some code documentation
* move all utility objects into one package
* Also check SyncWorker state for accounts list sync status bar
* clean up imports
* Remove duplicate copyright notices
* Minor changes
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* LoginSetupActivity: allow http/https in intent filter
Initially introduced in 054f1ece61,
this `intent-filter` breaks login from the Nextcloud app, as we send the server URI as `http`/`https`.
Signed-off-by: Álvaro Brey <alvaro.brey@nextcloud.com>
* Update intent-filter for login flow on api lvl 33 (closesbitfireAT/davx5#172)
Signed-off-by: Álvaro Brey <alvaro.brey@nextcloud.com>
Co-authored-by: Sunik Kupfer <kupfer@bitfire.at>
* Remove forced wifi-only sync when Data Saver is active
* move data saver warning to AppWarningsManager
* Minor changes
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* move warning notification logic into a warning class
* Move Warnings to UI package
* Minor changes
* Move "global sync disabled" warning to AccountListFragment, too
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* SyncManager: remove retry intent
* refactor DavService to RefreshCollectionsWorker now using WorkManager
* move DavResourceFinder to new service detection package
* Optimize imports
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* [WIP] save task list access level to android task list for tasks.org to use
* Disrecommend using OpenTasks in selection dialog
* Update string, use matching ical4android
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* check for notify permission before notifying
* [WIP] add notification permission request
* Revert "check for notify permission before notifying"
This reverts commit ed8e046d73163bef5684622bd877f08b9ee781c6.
* add notification permission request
* [WIP] add notifications disabled card in accounts view
* add notifications disabled card in accounts view
* reorder permissions
* use dp instead of mm for image max height in permissions view
* stop using array to bundle notification permissions
* Use new permissions contract for PermissionsFragment
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* [WIP] add managed restriction to force read-only addressbooks
* Honor app-wide read-only address book setting when syncing address books
* reflect status of force read-only address books setting in the GUI
Co-authored-by: Sunik Kupfer <kupfer@bitfire.at>
* use FragmentComponentManagers findActivity method provided by hilt (closesbitfireAT/davx5#106)
* WebCalFragment CalendarViewHolder: Pass Fragment instead of FragmentManager so that requireActivity() can be used
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Removed update related to from JtxSyncManager
updateRelatedTo is now done implicitely in the sync content provider for every inserted or updated icalobject/relatedto
* Update ical4android
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* [WIP] initialization code to make tests non-flaky
* init code as junit rule and remove flaky annotations
* remove exception for flaky tests in Github test workflow
* ensure correct class rule execution order
* Sync adapter: share single HttpClient between all SyncManagers (should fixbitfireAT/davx5#99)
* HttpClient: use producer for CertManager
* Call setAccountVisibility only when necessary
* Fix tests
* Use Hilt for DI
* Use Hilt for settings providers
* Use Hilt for login credentials fragment
* Use Hilt instead of ServiceLoader for intro fragments
* Rewrite from Koin to Hilt
* Tests
* Use more Hilt modules for service loading (account drawer, intro fragments)
* Lint
* WebDAV provider: don't listen to changes in onCreate (causes problems with Hilt and tests)
* Add intent filter for caldav(s)://, carddav(s):// and davx5:// schemes
* Define intent-filter only for standard and gplay flavors
* Merge manifest; remove Espresso tests (further tests should be added)
* Lint
ClosesbitfireAT/davx5#77
* Service detection: update properties of already existing collections which are not in homesets
* Trigger service detection after creating a collection because the server may change properties
* jtx sync: query tasks/journals only when supported
Should fixbitfireAT/davx5#78
* Set InputType for proxy_host and proxy_port programmatically
Since AndroidX it is no longer sufficient to simply specify
android:inputType in settings_app.xml.
* Drop custom IntEditTextPreference.kt
Doesn't appear to be necessary anymore.
* Updated queryCapabilities to use the same code as in TasksSyncManager
Might solve #59
* Added try-catch block for sync-method
updated min version for JtxBoard in TaskProvider.kt
Should solve #59
* removed syncResult.databaseError = true
* Changed wrong file before
* Created TasksSyncUtils to put notifyProviderTooOld method
* Cleaned up imports
* Added Version check in JtxSyncAdapterService.kt, required TaskProvider.checkVersion to be public
* Minor changes
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
* Make "Battery optimization whitelisting" a global DAVx5 setting
* Make "Keep in foreground" setting dependent of "Battery optimization whitelisting" setting
* if foreground service is enabled, remind user to enable battery optimization whitelisting too, before starting the foreground service
Co-authored-by: Ricki Hirner <hirner@bitfire.at>
- WebDAV service detection: accept compliance class 2 or 3, because they both imply class 1 (there are servers which don't show class 1 although they MUST)
- WebDAV random access: fix division by zero when file size reported by HEAD is zero
With the recent move to GitHub, the AboutInfo override for dav4jvm was
broken as it still used com_gitlab_bitfireAT__dav4jvm whereas it is now:
```
$ ./gradlew findLibraries | grep dav4jvm
bitfireAT/dav4jvm (f1d9354a41) -> com_github_bitfireAT__dav4jvm
Manually requested license: mpl_2_0
```
Since the autogenerated dav4jvm AboutInfo looks fine (see attached
screenshot), remove the override.
- Android 8 to 10: use all DNS servers; prioritize resolvers of active connections
(before: use only DNS servers of "active" connection, which may be a VPN connection without servers)
- Android 10+: use new DnsResolver API so that we don't need to know DNS servers anymore (also supports DoT etc.)
We typically provide a dark variant for icons that are used on a light
background. The current share icon sticks out a bit, so add a dark
variant of that icon and use that in the Debug activity.
- set isSyncable(AddressBooks)=0 at account creation when there is no CardDAV service
- OpenTasksWatcher: enumerate real accounts and not services from DB -> isSyncable(tasks) will be set to 0 correctly for accounts without CalDAV service
- SyncAdapter base class: set autoInitialize to true, although it should not be needed regularly
The battery optimization screen used some additional padding which made
it look out of place when swiping through the intro screens.
Instead of applying app:cardUseCompatPadding="true" to the other
screens, we remove it from intro_battery_optimizations.xml.
While at it, fix the indentation of the TextView element.
Recent okhttp versions require Android 5. Also, a lot of workarounds
(like non-vector graphics for notification icons) which are cumbersome
to maintain have accumulated.
So, DAVx5 will require Android 5 (SDK level 21) from the next release,
which will probably tagged as 3.0.
2.6.x (currently 2.6.5) will be the last branch which supports Android 4.4.
Maybe there will never be a version after 2.6.5, which will still be offered for
Android 4.4 devices. If there's big need for a maintenance release (like severe security
problems), there may be further 2.6.x releases (branched from 2.6.5), but
development and new features will only go to the master branch.
Recent okhttp versions require Android 5. Also, a lot of workarounds
(like non-vector graphics for notification icons) which are cumbersome
to maintain have accumulated.
So, DAVx5 will require Android 5 (SDK level 21) from the next release,
which will probably tagged as 3.0.
2.6.x (currently 2.6.5) will be the last branch which supports Android 4.4.
Maybe there will never be a version after 2.6.5, which will still be offered for
Android 4.4 devices. If there's big need for a maintenance release (like severe security
problems), there may be further 2.6.x releases (branched from 2.6.5), but
development and new features will only go to the master branch.
- Collection sync: don't save new sync state before downloading is finished
- throw exception when waiting for completion times out
- always use multi-get, even for single vCards/iCalendars
* move .ui.AccountSettingsActivity to .ui.account.SettingsActivity
* add setting for default alarms
* add sync extra: SyncAdapterService.SYNC_EXTRAS_RELOAD_ALL (forces full re-synchronization of all members)
* LocalCollection: add forgetETags() which resets the ETags of members
* account settings: automatic reloading of members when certain settings are modified
- ask for ACCESS_FINE_LOCATION/ACCESS_BACKGROUND_LOCATION when sync is restricted to specific WiFi SSIDs
- use Android 5+ way to determine active network connections, if possible
* remove external storage permissions because logs are now written to the app data directory
* ical4android: use ical4j 2.2.3 with built-in RFC 7986 properties
* don't use a separate :sync process anymore, so that settings management doesn't need IPC
* remove Settings service and IPC, use singleton with application Context instead
* adapt default number of sync worker threads
* library updates
2018-12-26 13:30:00 +01:00
828 changed files with 71175 additions and 18666 deletions
Please delete this paragraph and other repeating text (like the examples) after reading and before submitting the PR.
The PR should be in _Draft_ state during development. As soon as it's finished, it should be marked as _Ready for review_ and a reviewer should be chosen.
See also: [Writing A Great Pull Request Description](https://www.pullrequest.com/blog/writing-a-great-pull-request-description/)
### Purpose
What this PR is intended to do and why this is desirable.
Example:
> Adds support for AAA in BBB, as requested by several people in issue #XX.
### Short description
A short description of the chosen approach to achieve the purpose.
Example:
> - Added authentication option _Some authentication_ to _some module_.
> - Added support for _Some authentication_ to _some content provider_.
> - Added UI support for _Some authentication_ in account settings.
Related information (links to Android docs and other resources that help to understand/review
the changes) can also be put here.
### Checklist
- [ ] The PR has a proper title, description and label.
- [ ] I have [self-reviewed the PR](https://patrickdinh.medium.com/review-your-own-pull-requests-5634cad10b7a).
- [ ] I have added documentation to complex functions and functions that can be used by other modules.
- [ ] I have added reasonable tests or consciously decided to not add tests.
"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)",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"accountName",
"columnName":"accountName",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"principal",
"columnName":"principal",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_service_accountName_type",
"unique":true,
"columnNames":[
"accountName",
"type"
],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_service_accountName_type` ON `${TABLE_NAME}` (`accountName`, `type`)"
}
],
"foreignKeys":[]
},
{
"tableName":"homeset",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `personal` INTEGER NOT NULL, `url` TEXT NOT NULL, `privBind` INTEGER NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"personal",
"columnName":"personal",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privBind",
"columnName":"privBind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_homeset_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_homeset_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"collection",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `homeSetId` INTEGER, `type` TEXT NOT NULL, `url` TEXT NOT NULL, `privWriteContent` INTEGER NOT NULL, `privUnbind` INTEGER NOT NULL, `forceReadOnly` INTEGER NOT NULL, `displayName` TEXT, `description` TEXT, `owner` TEXT, `color` INTEGER, `timezone` TEXT, `supportsVEVENT` INTEGER, `supportsVTODO` INTEGER, `supportsVJOURNAL` INTEGER, `source` TEXT, `sync` INTEGER NOT NULL, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`homeSetId`) REFERENCES `homeset`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"homeSetId",
"columnName":"homeSetId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privWriteContent",
"columnName":"privWriteContent",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"privUnbind",
"columnName":"privUnbind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"forceReadOnly",
"columnName":"forceReadOnly",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"description",
"columnName":"description",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"owner",
"columnName":"owner",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"color",
"columnName":"color",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"timezone",
"columnName":"timezone",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsVEVENT",
"columnName":"supportsVEVENT",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVTODO",
"columnName":"supportsVTODO",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVJOURNAL",
"columnName":"supportsVJOURNAL",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"source",
"columnName":"source",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"sync",
"columnName":"sync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_collection_serviceId_type",
"unique":false,
"columnNames":[
"serviceId",
"type"
],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_serviceId_type` ON `${TABLE_NAME}` (`serviceId`, `type`)"
},
{
"name":"index_collection_homeSetId_type",
"unique":false,
"columnNames":[
"homeSetId",
"type"
],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_homeSetId_type` ON `${TABLE_NAME}` (`homeSetId`, `type`)"
},
{
"name":"index_collection_url",
"unique":false,
"columnNames":[
"url"
],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_url` ON `${TABLE_NAME}` (`url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
},
{
"table":"homeset",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"homeSetId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"syncstats",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `collectionId` INTEGER NOT NULL, `authority` TEXT NOT NULL, `lastSync` INTEGER NOT NULL, FOREIGN KEY(`collectionId`) REFERENCES `collection`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"collectionId",
"columnName":"collectionId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"authority",
"columnName":"authority",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"lastSync",
"columnName":"lastSync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_syncstats_collectionId_authority",
"unique":true,
"columnNames":[
"collectionId",
"authority"
],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_syncstats_collectionId_authority` ON `${TABLE_NAME}` (`collectionId`, `authority`)"
}
],
"foreignKeys":[
{
"table":"collection",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"collectionId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"webdav_mount",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL)",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"name",
"columnName":"name",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[],
"foreignKeys":[]
}
],
"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, '6fcabe50cbd00a4215dbe536a565dd2a')"
"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)",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"accountName",
"columnName":"accountName",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"principal",
"columnName":"principal",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_service_accountName_type",
"unique":true,
"columnNames":[
"accountName",
"type"
],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_service_accountName_type` ON `${TABLE_NAME}` (`accountName`, `type`)"
}
],
"foreignKeys":[]
},
{
"tableName":"homeset",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `personal` INTEGER NOT NULL, `url` TEXT NOT NULL, `privBind` INTEGER NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"personal",
"columnName":"personal",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privBind",
"columnName":"privBind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_homeset_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_homeset_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"collection",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `homeSetId` INTEGER, `type` TEXT NOT NULL, `url` TEXT NOT NULL, `privWriteContent` INTEGER NOT NULL, `privUnbind` INTEGER NOT NULL, `forceReadOnly` INTEGER NOT NULL, `displayName` TEXT, `description` TEXT, `owner` TEXT, `color` INTEGER, `timezone` TEXT, `supportsVEVENT` INTEGER, `supportsVTODO` INTEGER, `supportsVJOURNAL` INTEGER, `source` TEXT, `sync` INTEGER NOT NULL, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`homeSetId`) REFERENCES `homeset`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"homeSetId",
"columnName":"homeSetId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privWriteContent",
"columnName":"privWriteContent",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"privUnbind",
"columnName":"privUnbind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"forceReadOnly",
"columnName":"forceReadOnly",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"description",
"columnName":"description",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"owner",
"columnName":"owner",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"color",
"columnName":"color",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"timezone",
"columnName":"timezone",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsVEVENT",
"columnName":"supportsVEVENT",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVTODO",
"columnName":"supportsVTODO",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVJOURNAL",
"columnName":"supportsVJOURNAL",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"source",
"columnName":"source",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"sync",
"columnName":"sync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_collection_serviceId_type",
"unique":false,
"columnNames":[
"serviceId",
"type"
],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_serviceId_type` ON `${TABLE_NAME}` (`serviceId`, `type`)"
},
{
"name":"index_collection_homeSetId_type",
"unique":false,
"columnNames":[
"homeSetId",
"type"
],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_homeSetId_type` ON `${TABLE_NAME}` (`homeSetId`, `type`)"
},
{
"name":"index_collection_url",
"unique":false,
"columnNames":[
"url"
],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_url` ON `${TABLE_NAME}` (`url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
},
{
"table":"homeset",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"homeSetId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"syncstats",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `collectionId` INTEGER NOT NULL, `authority` TEXT NOT NULL, `lastSync` INTEGER NOT NULL, FOREIGN KEY(`collectionId`) REFERENCES `collection`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"collectionId",
"columnName":"collectionId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"authority",
"columnName":"authority",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"lastSync",
"columnName":"lastSync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_syncstats_collectionId_authority",
"unique":true,
"columnNames":[
"collectionId",
"authority"
],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_syncstats_collectionId_authority` ON `${TABLE_NAME}` (`collectionId`, `authority`)"
}
],
"foreignKeys":[
{
"table":"collection",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"collectionId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"webdav_document",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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 )",
"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)",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"accountName",
"columnName":"accountName",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"principal",
"columnName":"principal",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_service_accountName_type",
"unique":true,
"columnNames":[
"accountName",
"type"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_service_accountName_type` ON `${TABLE_NAME}` (`accountName`, `type`)"
}
],
"foreignKeys":[]
},
{
"tableName":"homeset",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `personal` INTEGER NOT NULL, `url` TEXT NOT NULL, `privBind` INTEGER NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"personal",
"columnName":"personal",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privBind",
"columnName":"privBind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_homeset_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_homeset_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"collection",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `homeSetId` INTEGER, `ownerId` INTEGER, `type` TEXT NOT NULL, `url` TEXT NOT NULL, `privWriteContent` INTEGER NOT NULL, `privUnbind` INTEGER NOT NULL, `forceReadOnly` INTEGER NOT NULL, `displayName` TEXT, `description` TEXT, `color` INTEGER, `timezone` TEXT, `supportsVEVENT` INTEGER, `supportsVTODO` INTEGER, `supportsVJOURNAL` INTEGER, `source` TEXT, `sync` INTEGER NOT NULL, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`homeSetId`) REFERENCES `homeset`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`ownerId`) REFERENCES `principal`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"homeSetId",
"columnName":"homeSetId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"ownerId",
"columnName":"ownerId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privWriteContent",
"columnName":"privWriteContent",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"privUnbind",
"columnName":"privUnbind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"forceReadOnly",
"columnName":"forceReadOnly",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"description",
"columnName":"description",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"color",
"columnName":"color",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"timezone",
"columnName":"timezone",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsVEVENT",
"columnName":"supportsVEVENT",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVTODO",
"columnName":"supportsVTODO",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVJOURNAL",
"columnName":"supportsVJOURNAL",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"source",
"columnName":"source",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"sync",
"columnName":"sync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_collection_serviceId_type",
"unique":false,
"columnNames":[
"serviceId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_serviceId_type` ON `${TABLE_NAME}` (`serviceId`, `type`)"
},
{
"name":"index_collection_homeSetId_type",
"unique":false,
"columnNames":[
"homeSetId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_homeSetId_type` ON `${TABLE_NAME}` (`homeSetId`, `type`)"
},
{
"name":"index_collection_url",
"unique":false,
"columnNames":[
"url"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_url` ON `${TABLE_NAME}` (`url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
},
{
"table":"homeset",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"homeSetId"
],
"referencedColumns":[
"id"
]
},
{
"table":"principal",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"ownerId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"principal",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `url` TEXT NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_principal_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_principal_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"syncstats",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `collectionId` INTEGER NOT NULL, `authority` TEXT NOT NULL, `lastSync` INTEGER NOT NULL, FOREIGN KEY(`collectionId`) REFERENCES `collection`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"collectionId",
"columnName":"collectionId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"authority",
"columnName":"authority",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"lastSync",
"columnName":"lastSync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_syncstats_collectionId_authority",
"unique":true,
"columnNames":[
"collectionId",
"authority"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_syncstats_collectionId_authority` ON `${TABLE_NAME}` (`collectionId`, `authority`)"
}
],
"foreignKeys":[
{
"table":"collection",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"collectionId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"webdav_document",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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 )",
"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)",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"accountName",
"columnName":"accountName",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"principal",
"columnName":"principal",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_service_accountName_type",
"unique":true,
"columnNames":[
"accountName",
"type"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_service_accountName_type` ON `${TABLE_NAME}` (`accountName`, `type`)"
}
],
"foreignKeys":[]
},
{
"tableName":"homeset",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `personal` INTEGER NOT NULL, `url` TEXT NOT NULL, `privBind` INTEGER NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"personal",
"columnName":"personal",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privBind",
"columnName":"privBind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_homeset_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_homeset_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"collection",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `homeSetId` INTEGER, `ownerId` INTEGER, `type` TEXT NOT NULL, `url` TEXT NOT NULL, `privWriteContent` INTEGER NOT NULL, `privUnbind` INTEGER NOT NULL, `forceReadOnly` INTEGER NOT NULL, `displayName` TEXT, `description` TEXT, `color` INTEGER, `timezone` TEXT, `supportsVEVENT` INTEGER, `supportsVTODO` INTEGER, `supportsVJOURNAL` INTEGER, `source` TEXT, `sync` INTEGER NOT NULL, `pushTopic` TEXT, `supportsWebPush` INTEGER NOT NULL DEFAULT 0, `pushSubscription` TEXT, `pushSubscriptionCreated` INTEGER, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`homeSetId`) REFERENCES `homeset`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`ownerId`) REFERENCES `principal`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"homeSetId",
"columnName":"homeSetId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"ownerId",
"columnName":"ownerId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privWriteContent",
"columnName":"privWriteContent",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"privUnbind",
"columnName":"privUnbind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"forceReadOnly",
"columnName":"forceReadOnly",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"description",
"columnName":"description",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"color",
"columnName":"color",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"timezone",
"columnName":"timezone",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsVEVENT",
"columnName":"supportsVEVENT",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVTODO",
"columnName":"supportsVTODO",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVJOURNAL",
"columnName":"supportsVJOURNAL",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"source",
"columnName":"source",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"sync",
"columnName":"sync",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"pushTopic",
"columnName":"pushTopic",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsWebPush",
"columnName":"supportsWebPush",
"affinity":"INTEGER",
"notNull":true,
"defaultValue":"0"
},
{
"fieldPath":"pushSubscription",
"columnName":"pushSubscription",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"pushSubscriptionCreated",
"columnName":"pushSubscriptionCreated",
"affinity":"INTEGER",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_collection_serviceId_type",
"unique":false,
"columnNames":[
"serviceId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_serviceId_type` ON `${TABLE_NAME}` (`serviceId`, `type`)"
},
{
"name":"index_collection_homeSetId_type",
"unique":false,
"columnNames":[
"homeSetId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_homeSetId_type` ON `${TABLE_NAME}` (`homeSetId`, `type`)"
},
{
"name":"index_collection_url",
"unique":false,
"columnNames":[
"url"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_url` ON `${TABLE_NAME}` (`url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
},
{
"table":"homeset",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"homeSetId"
],
"referencedColumns":[
"id"
]
},
{
"table":"principal",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"ownerId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"principal",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `url` TEXT NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_principal_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_principal_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"syncstats",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `collectionId` INTEGER NOT NULL, `authority` TEXT NOT NULL, `lastSync` INTEGER NOT NULL, FOREIGN KEY(`collectionId`) REFERENCES `collection`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"collectionId",
"columnName":"collectionId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"authority",
"columnName":"authority",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"lastSync",
"columnName":"lastSync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_syncstats_collectionId_authority",
"unique":true,
"columnNames":[
"collectionId",
"authority"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_syncstats_collectionId_authority` ON `${TABLE_NAME}` (`collectionId`, `authority`)"
}
],
"foreignKeys":[
{
"table":"collection",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"collectionId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"webdav_document",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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 )",
"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)",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"accountName",
"columnName":"accountName",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"principal",
"columnName":"principal",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_service_accountName_type",
"unique":true,
"columnNames":[
"accountName",
"type"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_service_accountName_type` ON `${TABLE_NAME}` (`accountName`, `type`)"
}
],
"foreignKeys":[]
},
{
"tableName":"homeset",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `personal` INTEGER NOT NULL, `url` TEXT NOT NULL, `privBind` INTEGER NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"personal",
"columnName":"personal",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privBind",
"columnName":"privBind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_homeset_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_homeset_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"collection",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `homeSetId` INTEGER, `ownerId` INTEGER, `type` TEXT NOT NULL, `url` TEXT NOT NULL, `privWriteContent` INTEGER NOT NULL, `privUnbind` INTEGER NOT NULL, `forceReadOnly` INTEGER NOT NULL, `displayName` TEXT, `description` TEXT, `color` INTEGER, `timezone` TEXT, `supportsVEVENT` INTEGER, `supportsVTODO` INTEGER, `supportsVJOURNAL` INTEGER, `source` TEXT, `sync` INTEGER NOT NULL, `pushTopic` TEXT, `supportsWebPush` INTEGER NOT NULL DEFAULT 0, `pushSubscription` TEXT, `pushSubscriptionCreated` INTEGER, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`homeSetId`) REFERENCES `homeset`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`ownerId`) REFERENCES `principal`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"homeSetId",
"columnName":"homeSetId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"ownerId",
"columnName":"ownerId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privWriteContent",
"columnName":"privWriteContent",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"privUnbind",
"columnName":"privUnbind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"forceReadOnly",
"columnName":"forceReadOnly",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"description",
"columnName":"description",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"color",
"columnName":"color",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"timezone",
"columnName":"timezone",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsVEVENT",
"columnName":"supportsVEVENT",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVTODO",
"columnName":"supportsVTODO",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVJOURNAL",
"columnName":"supportsVJOURNAL",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"source",
"columnName":"source",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"sync",
"columnName":"sync",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"pushTopic",
"columnName":"pushTopic",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsWebPush",
"columnName":"supportsWebPush",
"affinity":"INTEGER",
"notNull":true,
"defaultValue":"0"
},
{
"fieldPath":"pushSubscription",
"columnName":"pushSubscription",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"pushSubscriptionCreated",
"columnName":"pushSubscriptionCreated",
"affinity":"INTEGER",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_collection_serviceId_type",
"unique":false,
"columnNames":[
"serviceId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_serviceId_type` ON `${TABLE_NAME}` (`serviceId`, `type`)"
},
{
"name":"index_collection_homeSetId_type",
"unique":false,
"columnNames":[
"homeSetId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_homeSetId_type` ON `${TABLE_NAME}` (`homeSetId`, `type`)"
},
{
"name":"index_collection_ownerId_type",
"unique":false,
"columnNames":[
"ownerId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_ownerId_type` ON `${TABLE_NAME}` (`ownerId`, `type`)"
},
{
"name":"index_collection_pushTopic_type",
"unique":false,
"columnNames":[
"pushTopic",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_pushTopic_type` ON `${TABLE_NAME}` (`pushTopic`, `type`)"
},
{
"name":"index_collection_url",
"unique":false,
"columnNames":[
"url"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_url` ON `${TABLE_NAME}` (`url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
},
{
"table":"homeset",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"homeSetId"
],
"referencedColumns":[
"id"
]
},
{
"table":"principal",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"ownerId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"principal",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `url` TEXT NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_principal_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_principal_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"syncstats",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `collectionId` INTEGER NOT NULL, `authority` TEXT NOT NULL, `lastSync` INTEGER NOT NULL, FOREIGN KEY(`collectionId`) REFERENCES `collection`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"collectionId",
"columnName":"collectionId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"authority",
"columnName":"authority",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"lastSync",
"columnName":"lastSync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_syncstats_collectionId_authority",
"unique":true,
"columnNames":[
"collectionId",
"authority"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_syncstats_collectionId_authority` ON `${TABLE_NAME}` (`collectionId`, `authority`)"
}
],
"foreignKeys":[
{
"table":"collection",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"collectionId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"webdav_document",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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 )",
"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)",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"accountName",
"columnName":"accountName",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"principal",
"columnName":"principal",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_service_accountName_type",
"unique":true,
"columnNames":[
"accountName",
"type"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_service_accountName_type` ON `${TABLE_NAME}` (`accountName`, `type`)"
}
],
"foreignKeys":[]
},
{
"tableName":"homeset",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `personal` INTEGER NOT NULL, `url` TEXT NOT NULL, `privBind` INTEGER NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"personal",
"columnName":"personal",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privBind",
"columnName":"privBind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_homeset_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_homeset_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"collection",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `homeSetId` INTEGER, `ownerId` INTEGER, `type` TEXT NOT NULL, `url` TEXT NOT NULL, `privWriteContent` INTEGER NOT NULL, `privUnbind` INTEGER NOT NULL, `forceReadOnly` INTEGER NOT NULL, `displayName` TEXT, `description` TEXT, `color` INTEGER, `timezone` TEXT, `supportsVEVENT` INTEGER, `supportsVTODO` INTEGER, `supportsVJOURNAL` INTEGER, `source` TEXT, `sync` INTEGER NOT NULL, `pushTopic` TEXT, `supportsWebPush` INTEGER NOT NULL DEFAULT 0, `pushSubscription` TEXT, `pushSubscriptionExpires` INTEGER, `pushSubscriptionCreated` INTEGER, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`homeSetId`) REFERENCES `homeset`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`ownerId`) REFERENCES `principal`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"homeSetId",
"columnName":"homeSetId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"ownerId",
"columnName":"ownerId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privWriteContent",
"columnName":"privWriteContent",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"privUnbind",
"columnName":"privUnbind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"forceReadOnly",
"columnName":"forceReadOnly",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"description",
"columnName":"description",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"color",
"columnName":"color",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"timezone",
"columnName":"timezone",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsVEVENT",
"columnName":"supportsVEVENT",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVTODO",
"columnName":"supportsVTODO",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVJOURNAL",
"columnName":"supportsVJOURNAL",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"source",
"columnName":"source",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"sync",
"columnName":"sync",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"pushTopic",
"columnName":"pushTopic",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsWebPush",
"columnName":"supportsWebPush",
"affinity":"INTEGER",
"notNull":true,
"defaultValue":"0"
},
{
"fieldPath":"pushSubscription",
"columnName":"pushSubscription",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"pushSubscriptionExpires",
"columnName":"pushSubscriptionExpires",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"pushSubscriptionCreated",
"columnName":"pushSubscriptionCreated",
"affinity":"INTEGER",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_collection_serviceId_type",
"unique":false,
"columnNames":[
"serviceId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_serviceId_type` ON `${TABLE_NAME}` (`serviceId`, `type`)"
},
{
"name":"index_collection_homeSetId_type",
"unique":false,
"columnNames":[
"homeSetId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_homeSetId_type` ON `${TABLE_NAME}` (`homeSetId`, `type`)"
},
{
"name":"index_collection_ownerId_type",
"unique":false,
"columnNames":[
"ownerId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_ownerId_type` ON `${TABLE_NAME}` (`ownerId`, `type`)"
},
{
"name":"index_collection_pushTopic_type",
"unique":false,
"columnNames":[
"pushTopic",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_pushTopic_type` ON `${TABLE_NAME}` (`pushTopic`, `type`)"
},
{
"name":"index_collection_url",
"unique":false,
"columnNames":[
"url"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_url` ON `${TABLE_NAME}` (`url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
},
{
"table":"homeset",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"homeSetId"
],
"referencedColumns":[
"id"
]
},
{
"table":"principal",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"ownerId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"principal",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `url` TEXT NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_principal_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_principal_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"syncstats",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `collectionId` INTEGER NOT NULL, `authority` TEXT NOT NULL, `lastSync` INTEGER NOT NULL, FOREIGN KEY(`collectionId`) REFERENCES `collection`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"collectionId",
"columnName":"collectionId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"authority",
"columnName":"authority",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"lastSync",
"columnName":"lastSync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_syncstats_collectionId_authority",
"unique":true,
"columnNames":[
"collectionId",
"authority"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_syncstats_collectionId_authority` ON `${TABLE_NAME}` (`collectionId`, `authority`)"
}
],
"foreignKeys":[
{
"table":"collection",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"collectionId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"webdav_document",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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 )",
"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)",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"accountName",
"columnName":"accountName",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"principal",
"columnName":"principal",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_service_accountName_type",
"unique":true,
"columnNames":[
"accountName",
"type"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_service_accountName_type` ON `${TABLE_NAME}` (`accountName`, `type`)"
}
],
"foreignKeys":[]
},
{
"tableName":"homeset",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `personal` INTEGER NOT NULL, `url` TEXT NOT NULL, `privBind` INTEGER NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"personal",
"columnName":"personal",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privBind",
"columnName":"privBind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_homeset_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_homeset_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"collection",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `homeSetId` INTEGER, `ownerId` INTEGER, `type` TEXT NOT NULL, `url` TEXT NOT NULL, `privWriteContent` INTEGER NOT NULL, `privUnbind` INTEGER NOT NULL, `forceReadOnly` INTEGER NOT NULL, `displayName` TEXT, `description` TEXT, `color` INTEGER, `timezoneId` TEXT, `supportsVEVENT` INTEGER, `supportsVTODO` INTEGER, `supportsVJOURNAL` INTEGER, `source` TEXT, `sync` INTEGER NOT NULL, `pushTopic` TEXT, `supportsWebPush` INTEGER NOT NULL DEFAULT 0, `pushSubscription` TEXT, `pushSubscriptionExpires` INTEGER, `pushSubscriptionCreated` INTEGER, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`homeSetId`) REFERENCES `homeset`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`ownerId`) REFERENCES `principal`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"homeSetId",
"columnName":"homeSetId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"ownerId",
"columnName":"ownerId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privWriteContent",
"columnName":"privWriteContent",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"privUnbind",
"columnName":"privUnbind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"forceReadOnly",
"columnName":"forceReadOnly",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"description",
"columnName":"description",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"color",
"columnName":"color",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"timezoneId",
"columnName":"timezoneId",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsVEVENT",
"columnName":"supportsVEVENT",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVTODO",
"columnName":"supportsVTODO",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVJOURNAL",
"columnName":"supportsVJOURNAL",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"source",
"columnName":"source",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"sync",
"columnName":"sync",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"pushTopic",
"columnName":"pushTopic",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsWebPush",
"columnName":"supportsWebPush",
"affinity":"INTEGER",
"notNull":true,
"defaultValue":"0"
},
{
"fieldPath":"pushSubscription",
"columnName":"pushSubscription",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"pushSubscriptionExpires",
"columnName":"pushSubscriptionExpires",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"pushSubscriptionCreated",
"columnName":"pushSubscriptionCreated",
"affinity":"INTEGER",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_collection_serviceId_type",
"unique":false,
"columnNames":[
"serviceId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_serviceId_type` ON `${TABLE_NAME}` (`serviceId`, `type`)"
},
{
"name":"index_collection_homeSetId_type",
"unique":false,
"columnNames":[
"homeSetId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_homeSetId_type` ON `${TABLE_NAME}` (`homeSetId`, `type`)"
},
{
"name":"index_collection_ownerId_type",
"unique":false,
"columnNames":[
"ownerId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_ownerId_type` ON `${TABLE_NAME}` (`ownerId`, `type`)"
},
{
"name":"index_collection_pushTopic_type",
"unique":false,
"columnNames":[
"pushTopic",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_pushTopic_type` ON `${TABLE_NAME}` (`pushTopic`, `type`)"
},
{
"name":"index_collection_url",
"unique":false,
"columnNames":[
"url"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_url` ON `${TABLE_NAME}` (`url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
},
{
"table":"homeset",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"homeSetId"
],
"referencedColumns":[
"id"
]
},
{
"table":"principal",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"ownerId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"principal",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `url` TEXT NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_principal_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_principal_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"syncstats",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `collectionId` INTEGER NOT NULL, `authority` TEXT NOT NULL, `lastSync` INTEGER NOT NULL, FOREIGN KEY(`collectionId`) REFERENCES `collection`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"collectionId",
"columnName":"collectionId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"authority",
"columnName":"authority",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"lastSync",
"columnName":"lastSync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_syncstats_collectionId_authority",
"unique":true,
"columnNames":[
"collectionId",
"authority"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_syncstats_collectionId_authority` ON `${TABLE_NAME}` (`collectionId`, `authority`)"
}
],
"foreignKeys":[
{
"table":"collection",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"collectionId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"webdav_document",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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 )",
"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)",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"accountName",
"columnName":"accountName",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"principal",
"columnName":"principal",
"affinity":"TEXT"
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_service_accountName_type",
"unique":true,
"columnNames":[
"accountName",
"type"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_service_accountName_type` ON `${TABLE_NAME}` (`accountName`, `type`)"
}
]
},
{
"tableName":"homeset",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `personal` INTEGER NOT NULL, `url` TEXT NOT NULL, `privBind` INTEGER NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"personal",
"columnName":"personal",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privBind",
"columnName":"privBind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT"
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_homeset_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_homeset_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"collection",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `homeSetId` INTEGER, `ownerId` INTEGER, `type` TEXT NOT NULL, `url` TEXT NOT NULL, `privWriteContent` INTEGER NOT NULL, `privUnbind` INTEGER NOT NULL, `forceReadOnly` INTEGER NOT NULL, `displayName` TEXT, `description` TEXT, `color` INTEGER, `timezoneId` TEXT, `supportsVEVENT` INTEGER, `supportsVTODO` INTEGER, `supportsVJOURNAL` INTEGER, `source` TEXT, `sync` INTEGER NOT NULL, `pushTopic` TEXT, `supportsWebPush` INTEGER NOT NULL DEFAULT 0, `pushVapidKey` TEXT, `pushSubscription` TEXT, `pushSubscriptionExpires` INTEGER, `pushSubscriptionCreated` INTEGER, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`homeSetId`) REFERENCES `homeset`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`ownerId`) REFERENCES `principal`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"homeSetId",
"columnName":"homeSetId",
"affinity":"INTEGER"
},
{
"fieldPath":"ownerId",
"columnName":"ownerId",
"affinity":"INTEGER"
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privWriteContent",
"columnName":"privWriteContent",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"privUnbind",
"columnName":"privUnbind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"forceReadOnly",
"columnName":"forceReadOnly",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT"
},
{
"fieldPath":"description",
"columnName":"description",
"affinity":"TEXT"
},
{
"fieldPath":"color",
"columnName":"color",
"affinity":"INTEGER"
},
{
"fieldPath":"timezoneId",
"columnName":"timezoneId",
"affinity":"TEXT"
},
{
"fieldPath":"supportsVEVENT",
"columnName":"supportsVEVENT",
"affinity":"INTEGER"
},
{
"fieldPath":"supportsVTODO",
"columnName":"supportsVTODO",
"affinity":"INTEGER"
},
{
"fieldPath":"supportsVJOURNAL",
"columnName":"supportsVJOURNAL",
"affinity":"INTEGER"
},
{
"fieldPath":"source",
"columnName":"source",
"affinity":"TEXT"
},
{
"fieldPath":"sync",
"columnName":"sync",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"pushTopic",
"columnName":"pushTopic",
"affinity":"TEXT"
},
{
"fieldPath":"supportsWebPush",
"columnName":"supportsWebPush",
"affinity":"INTEGER",
"notNull":true,
"defaultValue":"0"
},
{
"fieldPath":"pushVapidKey",
"columnName":"pushVapidKey",
"affinity":"TEXT"
},
{
"fieldPath":"pushSubscription",
"columnName":"pushSubscription",
"affinity":"TEXT"
},
{
"fieldPath":"pushSubscriptionExpires",
"columnName":"pushSubscriptionExpires",
"affinity":"INTEGER"
},
{
"fieldPath":"pushSubscriptionCreated",
"columnName":"pushSubscriptionCreated",
"affinity":"INTEGER"
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_collection_serviceId_type",
"unique":false,
"columnNames":[
"serviceId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_serviceId_type` ON `${TABLE_NAME}` (`serviceId`, `type`)"
},
{
"name":"index_collection_homeSetId_type",
"unique":false,
"columnNames":[
"homeSetId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_homeSetId_type` ON `${TABLE_NAME}` (`homeSetId`, `type`)"
},
{
"name":"index_collection_ownerId_type",
"unique":false,
"columnNames":[
"ownerId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_ownerId_type` ON `${TABLE_NAME}` (`ownerId`, `type`)"
},
{
"name":"index_collection_pushTopic_type",
"unique":false,
"columnNames":[
"pushTopic",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_pushTopic_type` ON `${TABLE_NAME}` (`pushTopic`, `type`)"
},
{
"name":"index_collection_url",
"unique":false,
"columnNames":[
"url"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_url` ON `${TABLE_NAME}` (`url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
},
{
"table":"homeset",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"homeSetId"
],
"referencedColumns":[
"id"
]
},
{
"table":"principal",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"ownerId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"principal",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `url` TEXT NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT"
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_principal_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_principal_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"syncstats",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `collectionId` INTEGER NOT NULL, `authority` TEXT NOT NULL, `lastSync` INTEGER NOT NULL, FOREIGN KEY(`collectionId`) REFERENCES `collection`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"collectionId",
"columnName":"collectionId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"authority",
"columnName":"authority",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"lastSync",
"columnName":"lastSync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_syncstats_collectionId_authority",
"unique":true,
"columnNames":[
"collectionId",
"authority"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_syncstats_collectionId_authority` ON `${TABLE_NAME}` (`collectionId`, `authority`)"
}
],
"foreignKeys":[
{
"table":"collection",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"collectionId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"webdav_document",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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 )",
"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)",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"accountName",
"columnName":"accountName",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"principal",
"columnName":"principal",
"affinity":"TEXT"
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_service_accountName_type",
"unique":true,
"columnNames":[
"accountName",
"type"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_service_accountName_type` ON `${TABLE_NAME}` (`accountName`, `type`)"
}
]
},
{
"tableName":"homeset",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `personal` INTEGER NOT NULL, `url` TEXT NOT NULL, `privBind` INTEGER NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"personal",
"columnName":"personal",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privBind",
"columnName":"privBind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT"
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_homeset_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_homeset_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"collection",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `homeSetId` INTEGER, `ownerId` INTEGER, `type` TEXT NOT NULL, `url` TEXT NOT NULL, `privWriteContent` INTEGER NOT NULL, `privUnbind` INTEGER NOT NULL, `forceReadOnly` INTEGER NOT NULL, `displayName` TEXT, `description` TEXT, `color` INTEGER, `timezoneId` TEXT, `supportsVEVENT` INTEGER, `supportsVTODO` INTEGER, `supportsVJOURNAL` INTEGER, `source` TEXT, `sync` INTEGER NOT NULL, `pushTopic` TEXT, `supportsWebPush` INTEGER NOT NULL DEFAULT 0, `pushVapidKey` TEXT, `pushSubscription` TEXT, `pushSubscriptionExpires` INTEGER, `pushSubscriptionCreated` INTEGER, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`homeSetId`) REFERENCES `homeset`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`ownerId`) REFERENCES `principal`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"homeSetId",
"columnName":"homeSetId",
"affinity":"INTEGER"
},
{
"fieldPath":"ownerId",
"columnName":"ownerId",
"affinity":"INTEGER"
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privWriteContent",
"columnName":"privWriteContent",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"privUnbind",
"columnName":"privUnbind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"forceReadOnly",
"columnName":"forceReadOnly",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT"
},
{
"fieldPath":"description",
"columnName":"description",
"affinity":"TEXT"
},
{
"fieldPath":"color",
"columnName":"color",
"affinity":"INTEGER"
},
{
"fieldPath":"timezoneId",
"columnName":"timezoneId",
"affinity":"TEXT"
},
{
"fieldPath":"supportsVEVENT",
"columnName":"supportsVEVENT",
"affinity":"INTEGER"
},
{
"fieldPath":"supportsVTODO",
"columnName":"supportsVTODO",
"affinity":"INTEGER"
},
{
"fieldPath":"supportsVJOURNAL",
"columnName":"supportsVJOURNAL",
"affinity":"INTEGER"
},
{
"fieldPath":"source",
"columnName":"source",
"affinity":"TEXT"
},
{
"fieldPath":"sync",
"columnName":"sync",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"pushTopic",
"columnName":"pushTopic",
"affinity":"TEXT"
},
{
"fieldPath":"supportsWebPush",
"columnName":"supportsWebPush",
"affinity":"INTEGER",
"notNull":true,
"defaultValue":"0"
},
{
"fieldPath":"pushVapidKey",
"columnName":"pushVapidKey",
"affinity":"TEXT"
},
{
"fieldPath":"pushSubscription",
"columnName":"pushSubscription",
"affinity":"TEXT"
},
{
"fieldPath":"pushSubscriptionExpires",
"columnName":"pushSubscriptionExpires",
"affinity":"INTEGER"
},
{
"fieldPath":"pushSubscriptionCreated",
"columnName":"pushSubscriptionCreated",
"affinity":"INTEGER"
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_collection_serviceId_type",
"unique":false,
"columnNames":[
"serviceId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_serviceId_type` ON `${TABLE_NAME}` (`serviceId`, `type`)"
},
{
"name":"index_collection_homeSetId_type",
"unique":false,
"columnNames":[
"homeSetId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_homeSetId_type` ON `${TABLE_NAME}` (`homeSetId`, `type`)"
},
{
"name":"index_collection_ownerId_type",
"unique":false,
"columnNames":[
"ownerId",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_ownerId_type` ON `${TABLE_NAME}` (`ownerId`, `type`)"
},
{
"name":"index_collection_pushTopic_type",
"unique":false,
"columnNames":[
"pushTopic",
"type"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_pushTopic_type` ON `${TABLE_NAME}` (`pushTopic`, `type`)"
},
{
"name":"index_collection_url",
"unique":false,
"columnNames":[
"url"
],
"orders":[],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_url` ON `${TABLE_NAME}` (`url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
},
{
"table":"homeset",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"homeSetId"
],
"referencedColumns":[
"id"
]
},
{
"table":"principal",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"ownerId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"principal",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `url` TEXT NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT"
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_principal_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_principal_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"syncstats",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `collectionId` INTEGER NOT NULL, `dataType` TEXT NOT NULL, `lastSync` INTEGER NOT NULL, FOREIGN KEY(`collectionId`) REFERENCES `collection`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"collectionId",
"columnName":"collectionId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"dataType",
"columnName":"dataType",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"lastSync",
"columnName":"lastSync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"autoGenerate":true,
"columnNames":[
"id"
]
},
"indices":[
{
"name":"index_syncstats_collectionId_dataType",
"unique":true,
"columnNames":[
"collectionId",
"dataType"
],
"orders":[],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_syncstats_collectionId_dataType` ON `${TABLE_NAME}` (`collectionId`, `dataType`)"
}
],
"foreignKeys":[
{
"table":"collection",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"collectionId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"webdav_document",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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 )",
"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)",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"accountName",
"columnName":"accountName",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"principal",
"columnName":"principal",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_service_accountName_type",
"unique":true,
"columnNames":[
"accountName",
"type"
],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_service_accountName_type` ON `${TABLE_NAME}` (`accountName`, `type`)"
}
],
"foreignKeys":[]
},
{
"tableName":"homeset",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `personal` INTEGER NOT NULL, `url` TEXT NOT NULL, `privBind` INTEGER NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"personal",
"columnName":"personal",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privBind",
"columnName":"privBind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_homeset_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_homeset_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"collection",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `homeSetId` INTEGER, `type` TEXT NOT NULL, `url` TEXT NOT NULL, `privWriteContent` INTEGER NOT NULL, `privUnbind` INTEGER NOT NULL, `forceReadOnly` INTEGER NOT NULL, `displayName` TEXT, `description` TEXT, `owner` TEXT, `color` INTEGER, `timezone` TEXT, `supportsVEVENT` INTEGER, `supportsVTODO` INTEGER, `supportsVJOURNAL` INTEGER, `source` TEXT, `sync` INTEGER NOT NULL, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`homeSetId`) REFERENCES `homeset`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"homeSetId",
"columnName":"homeSetId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privWriteContent",
"columnName":"privWriteContent",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"privUnbind",
"columnName":"privUnbind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"forceReadOnly",
"columnName":"forceReadOnly",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"description",
"columnName":"description",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"owner",
"columnName":"owner",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"color",
"columnName":"color",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"timezone",
"columnName":"timezone",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsVEVENT",
"columnName":"supportsVEVENT",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVTODO",
"columnName":"supportsVTODO",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVJOURNAL",
"columnName":"supportsVJOURNAL",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"source",
"columnName":"source",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"sync",
"columnName":"sync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_collection_serviceId_type",
"unique":false,
"columnNames":[
"serviceId",
"type"
],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_serviceId_type` ON `${TABLE_NAME}` (`serviceId`, `type`)"
},
{
"name":"index_collection_homeSetId_type",
"unique":false,
"columnNames":[
"homeSetId",
"type"
],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_homeSetId_type` ON `${TABLE_NAME}` (`homeSetId`, `type`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
},
{
"table":"homeset",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"homeSetId"
],
"referencedColumns":[
"id"
]
}
]
}
],
"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, 'b8699ef3cc4c62e8851df4360fb69e00')"
"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)",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"accountName",
"columnName":"accountName",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"principal",
"columnName":"principal",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_service_accountName_type",
"unique":true,
"columnNames":[
"accountName",
"type"
],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_service_accountName_type` ON `${TABLE_NAME}` (`accountName`, `type`)"
}
],
"foreignKeys":[]
},
{
"tableName":"homeset",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `personal` INTEGER NOT NULL, `url` TEXT NOT NULL, `privBind` INTEGER NOT NULL, `displayName` TEXT, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"personal",
"columnName":"personal",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privBind",
"columnName":"privBind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_homeset_serviceId_url",
"unique":true,
"columnNames":[
"serviceId",
"url"
],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_homeset_serviceId_url` ON `${TABLE_NAME}` (`serviceId`, `url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"collection",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `serviceId` INTEGER NOT NULL, `homeSetId` INTEGER, `type` TEXT NOT NULL, `url` TEXT NOT NULL, `privWriteContent` INTEGER NOT NULL, `privUnbind` INTEGER NOT NULL, `forceReadOnly` INTEGER NOT NULL, `displayName` TEXT, `description` TEXT, `owner` TEXT, `color` INTEGER, `timezone` TEXT, `supportsVEVENT` INTEGER, `supportsVTODO` INTEGER, `supportsVJOURNAL` INTEGER, `source` TEXT, `sync` INTEGER NOT NULL, FOREIGN KEY(`serviceId`) REFERENCES `service`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`homeSetId`) REFERENCES `homeset`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"serviceId",
"columnName":"serviceId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"homeSetId",
"columnName":"homeSetId",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"type",
"columnName":"type",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"url",
"columnName":"url",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"privWriteContent",
"columnName":"privWriteContent",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"privUnbind",
"columnName":"privUnbind",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"forceReadOnly",
"columnName":"forceReadOnly",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"displayName",
"columnName":"displayName",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"description",
"columnName":"description",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"owner",
"columnName":"owner",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"color",
"columnName":"color",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"timezone",
"columnName":"timezone",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"supportsVEVENT",
"columnName":"supportsVEVENT",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVTODO",
"columnName":"supportsVTODO",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"supportsVJOURNAL",
"columnName":"supportsVJOURNAL",
"affinity":"INTEGER",
"notNull":false
},
{
"fieldPath":"source",
"columnName":"source",
"affinity":"TEXT",
"notNull":false
},
{
"fieldPath":"sync",
"columnName":"sync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_collection_serviceId_type",
"unique":false,
"columnNames":[
"serviceId",
"type"
],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_serviceId_type` ON `${TABLE_NAME}` (`serviceId`, `type`)"
},
{
"name":"index_collection_homeSetId_type",
"unique":false,
"columnNames":[
"homeSetId",
"type"
],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_homeSetId_type` ON `${TABLE_NAME}` (`homeSetId`, `type`)"
},
{
"name":"index_collection_url",
"unique":false,
"columnNames":[
"url"
],
"createSql":"CREATE INDEX IF NOT EXISTS `index_collection_url` ON `${TABLE_NAME}` (`url`)"
}
],
"foreignKeys":[
{
"table":"service",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"serviceId"
],
"referencedColumns":[
"id"
]
},
{
"table":"homeset",
"onDelete":"SET NULL",
"onUpdate":"NO ACTION",
"columns":[
"homeSetId"
],
"referencedColumns":[
"id"
]
}
]
},
{
"tableName":"syncstats",
"createSql":"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `collectionId` INTEGER NOT NULL, `authority` TEXT NOT NULL, `lastSync` INTEGER NOT NULL, FOREIGN KEY(`collectionId`) REFERENCES `collection`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields":[
{
"fieldPath":"id",
"columnName":"id",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"collectionId",
"columnName":"collectionId",
"affinity":"INTEGER",
"notNull":true
},
{
"fieldPath":"authority",
"columnName":"authority",
"affinity":"TEXT",
"notNull":true
},
{
"fieldPath":"lastSync",
"columnName":"lastSync",
"affinity":"INTEGER",
"notNull":true
}
],
"primaryKey":{
"columnNames":[
"id"
],
"autoGenerate":true
},
"indices":[
{
"name":"index_syncstats_collectionId_authority",
"unique":true,
"columnNames":[
"collectionId",
"authority"
],
"createSql":"CREATE UNIQUE INDEX IF NOT EXISTS `index_syncstats_collectionId_authority` ON `${TABLE_NAME}` (`collectionId`, `authority`)"
}
],
"foreignKeys":[
{
"table":"collection",
"onDelete":"CASCADE",
"onUpdate":"NO ACTION",
"columns":[
"collectionId"
],
"referencedColumns":[
"id"
]
}
]
}
],
"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, '7e4bfdf7f9fa3529c333cf9485f8cf50')"
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.