diff --git a/changelog/unreleased/4791 b/changelog/unreleased/4791
new file mode 100644
index 00000000000..afb15cd21e6
--- /dev/null
+++ b/changelog/unreleased/4791
@@ -0,0 +1,5 @@
+Enhancement: Make share search minimum length capability-driven
+
+The minimum number of characters required to search users for sharing and members for joining has been made configurable through the files_sharing.search_min_lenght capability.
+
+https://github.com/owncloud/android/pull/4791
diff --git a/owncloudApp/src/main/java/com/owncloud/android/db/ProviderMeta.java b/owncloudApp/src/main/java/com/owncloud/android/db/ProviderMeta.java
index 017956186e7..8e3ee117fef 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/db/ProviderMeta.java
+++ b/owncloudApp/src/main/java/com/owncloud/android/db/ProviderMeta.java
@@ -147,6 +147,7 @@ static public class ProviderTableMeta implements BaseColumns {
public static final String CAPABILITIES_SHARING_PUBLIC_MULTIPLE = "sharing_public_multiple";
public static final String CAPABILITIES_SHARING_PUBLIC_SUPPORTS_UPLOAD_ONLY = "supports_upload_only";
public static final String CAPABILITIES_SHARING_RESHARING = "sharing_resharing";
+ public static final String CAPABILITIES_SHARING_SEARCH_MIN_LENGTH = "search_min_length";
public static final String CAPABILITIES_SHARING_FEDERATION_OUTGOING = "sharing_federation_outgoing";
public static final String CAPABILITIES_SHARING_FEDERATION_INCOMING = "sharing_federation_incoming";
public static final String CAPABILITIES_FILES_BIGFILECHUNKING = "files_bigfilechunking";
diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/releasenotes/ReleaseNotesViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/releasenotes/ReleaseNotesViewModel.kt
index 895f722d47c..d1461b42251 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/presentation/releasenotes/ReleaseNotesViewModel.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/releasenotes/ReleaseNotesViewModel.kt
@@ -58,6 +58,11 @@ class ReleaseNotesViewModel(
subtitle = R.string.release_notes_4_8_0_subtitle_spaces_permanent_links,
type = ReleaseNoteType.ENHANCEMENT
),
+ ReleaseNote(
+ title = R.string.release_notes_4_8_0_title_search_minimum_length,
+ subtitle = R.string.release_notes_4_8_0_subtitle_search_minimum_length,
+ type = ReleaseNoteType.ENHANCEMENT
+ ),
ReleaseNote(
title = R.string.release_notes_bugfixes_title,
subtitle = R.string.release_notes_bugfixes_subtitle,
diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/sharing/sharees/UsersAndGroupsSearchProvider.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/sharing/sharees/UsersAndGroupsSearchProvider.kt
index 4830d94b286..6ffc55e0623 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/presentation/sharing/sharees/UsersAndGroupsSearchProvider.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/sharing/sharees/UsersAndGroupsSearchProvider.kt
@@ -38,6 +38,7 @@ import android.provider.BaseColumns
import android.widget.Toast
import com.owncloud.android.MainApp
import com.owncloud.android.R
+import com.owncloud.android.domain.capabilities.model.OCCapability
import com.owncloud.android.presentation.authentication.AccountUtils
import com.owncloud.android.domain.capabilities.usecases.GetStoredCapabilitiesUseCase
import com.owncloud.android.domain.sharing.sharees.GetShareesAsyncUseCase
@@ -134,6 +135,12 @@ class UsersAndGroupsSearchProvider : ContentProvider() {
accountName = account.name
)
)
+ val minSearchLength = capabilities?.getFilesSharingSearchMinLength()
+ ?: OCCapability.DEFAULT_FILES_SHARING_SEARCH_MIN_LENGTH
+
+ if (userQuery.length < minSearchLength) {
+ return MatrixCursor(COLUMNS)
+ }
val getShareesAsyncUseCase: GetShareesAsyncUseCase by inject()
diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/spaces/members/AddMemberFragment.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/spaces/members/AddMemberFragment.kt
index 86282cea29b..24c37874a36 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/presentation/spaces/members/AddMemberFragment.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/spaces/members/AddMemberFragment.kt
@@ -32,6 +32,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.owncloud.android.R
import com.owncloud.android.databinding.AddMemberFragmentBinding
+import com.owncloud.android.domain.capabilities.model.OCCapability
+import com.owncloud.android.domain.capabilities.usecases.GetStoredCapabilitiesUseCase
import com.owncloud.android.domain.members.model.OCMember
import com.owncloud.android.domain.members.model.OCMemberType
import com.owncloud.android.domain.roles.model.OCRole
@@ -41,6 +43,7 @@ import com.owncloud.android.extensions.collectLatestLifecycleFlow
import com.owncloud.android.extensions.showErrorInSnackbar
import com.owncloud.android.presentation.common.UIResult
import com.owncloud.android.utils.DisplayUtils
+import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.activityViewModel
import org.koin.core.parameter.parametersOf
import timber.log.Timber
@@ -51,6 +54,7 @@ import java.util.TimeZone
class AddMemberFragment: Fragment(), SearchMembersAdapter.SearchMembersAdapterListener {
private var _binding: AddMemberFragmentBinding? = null
private val binding get() = _binding!!
+ private val getStoredCapabilitiesUseCase: GetStoredCapabilitiesUseCase by inject()
private val spaceMembersViewModel: SpaceMembersViewModel by activityViewModel {
parametersOf(
@@ -66,6 +70,7 @@ class AddMemberFragment: Fragment(), SearchMembersAdapter.SearchMembersAdapterLi
private var editMode = false
private var selectedMemberId = ""
+ private var minimumSearchLength = OCCapability.DEFAULT_FILES_SHARING_SEARCH_MIN_LENGTH
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = AddMemberFragmentBinding.inflate(inflater, container, false)
@@ -91,6 +96,7 @@ class AddMemberFragment: Fragment(), SearchMembersAdapter.SearchMembersAdapterLi
}
}
+ initSearchMinLength()
subscribeToViewModels()
binding.searchBar.apply {
@@ -101,7 +107,11 @@ class AddMemberFragment: Fragment(), SearchMembersAdapter.SearchMembersAdapterLi
override fun onQueryTextSubmit(query: String): Boolean = true
override fun onQueryTextChange(newText: String): Boolean {
- if (newText.length > 2) { spaceMembersViewModel.searchMembers(newText) } else { spaceMembersViewModel.clearSearch() }
+ if (newText.length >= minimumSearchLength) {
+ spaceMembersViewModel.searchMembers(newText)
+ } else {
+ spaceMembersViewModel.clearSearch()
+ }
return true
}
})
@@ -111,7 +121,7 @@ class AddMemberFragment: Fragment(), SearchMembersAdapter.SearchMembersAdapterLi
private fun showOrHideEmptyView(hasMembers: Boolean) {
binding.membersRecyclerView.isVisible = hasMembers
binding.emptyDataParent.apply {
- val shouldShow = !hasMembers && binding.searchBar.query.length > 2
+ val shouldShow = !hasMembers && binding.searchBar.query.length >= minimumSearchLength
root.isVisible = shouldShow
if (shouldShow) {
listEmptyDatasetIcon.setImageResource(R.drawable.ic_share_generic_white)
@@ -121,6 +131,13 @@ class AddMemberFragment: Fragment(), SearchMembersAdapter.SearchMembersAdapterLi
}
}
+ private fun initSearchMinLength() {
+ val accountName = requireArguments().getString(ARG_ACCOUNT_NAME) ?: return
+ minimumSearchLength = getStoredCapabilitiesUseCase(
+ GetStoredCapabilitiesUseCase.Params(accountName = accountName)
+ )?.getFilesSharingSearchMinLength() ?: OCCapability.DEFAULT_FILES_SHARING_SEARCH_MIN_LENGTH
+ }
+
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
requireActivity().setTitle(if (editMode) R.string.members_edit else R.string.members_add)
diff --git a/owncloudApp/src/main/java/com/owncloud/android/providers/FileContentProvider.kt b/owncloudApp/src/main/java/com/owncloud/android/providers/FileContentProvider.kt
index caed10fe839..ba74d8acfbb 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/providers/FileContentProvider.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/providers/FileContentProvider.kt
@@ -1478,6 +1478,8 @@ class FileContentProvider(val executors: Executors = Executors()) : ContentProvi
ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_SUPPORTS_UPLOAD_ONLY
capabilityProjectionMap[ProviderTableMeta.CAPABILITIES_SHARING_RESHARING] =
ProviderTableMeta.CAPABILITIES_SHARING_RESHARING
+ capabilityProjectionMap[ProviderTableMeta.CAPABILITIES_SHARING_SEARCH_MIN_LENGTH] =
+ ProviderTableMeta.CAPABILITIES_SHARING_SEARCH_MIN_LENGTH
capabilityProjectionMap[ProviderTableMeta.CAPABILITIES_SHARING_FEDERATION_OUTGOING] =
ProviderTableMeta.CAPABILITIES_SHARING_FEDERATION_OUTGOING
capabilityProjectionMap[ProviderTableMeta.CAPABILITIES_SHARING_FEDERATION_INCOMING] =
diff --git a/owncloudApp/src/main/res/values/strings.xml b/owncloudApp/src/main/res/values/strings.xml
index 8269300445a..c5e34e23bf8 100644
--- a/owncloudApp/src/main/res/values/strings.xml
+++ b/owncloudApp/src/main/res/values/strings.xml
@@ -747,6 +747,8 @@
Infinite Scale users can see all members of a space and manage them with right permissions
Permanent links for spaces
Infinite Scale users can now get a permanent link for a space and share it with other members
+ Configurable minimum search length
+ The minimum number of characters before searching users and members is now configured by server capabilities
Open in web
diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt
index 81718bb25bf..15031a0dacc 100644
--- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt
+++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/RemoteCapability.kt
@@ -63,6 +63,7 @@ data class RemoteCapability(
var filesSharingPublicMultiple: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN,
var filesSharingPublicSupportsUploadOnly: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN,
var filesSharingResharing: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN,
+ var filesSharingSearchMinLength: Int? = null,
var filesSharingFederationOutgoing: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN,
var filesSharingFederationIncoming: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN,
var filesSharingUserProfilePicture: CapabilityBooleanType = CapabilityBooleanType.UNKNOWN,
diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt
index 722054839d6..7b672375e29 100644
--- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt
+++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponse.kt
@@ -77,6 +77,8 @@ data class CapabilityResponse(
filesSharingPublicExpireDateEnforced = CapabilityBooleanType.fromBooleanValue(
capabilities?.fileSharingCapabilities?.fileSharingPublic?.fileSharingPublicExpireDate?.enforced
),
+ filesSharingSearchMinLength = capabilities?.fileSharingCapabilities?.fileSharingSearchMinLenght
+ ?: capabilities?.fileSharingCapabilities?.fileSharingSearchMinLength,
filesBigFileChunking = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.bigfilechunking),
filesUndelete = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.undelete),
filesVersioning = CapabilityBooleanType.fromBooleanValue(capabilities?.fileCapabilities?.versioning),
@@ -123,6 +125,10 @@ data class FileSharingCapabilities(
val fileSharingPublic: FileSharingPublic?,
@Json(name = "resharing")
val fileSharingReSharing: Boolean?,
+ @Json(name = "search_min_lenght")
+ val fileSharingSearchMinLenght: Int?,
+ @Json(name = "search_min_length")
+ val fileSharingSearchMinLength: Int?,
@Json(name = "federation")
val fileSharingFederation: FileSharingFederation?,
@Json(name = "user")
diff --git a/owncloudComLibrary/src/test/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponseTest.kt b/owncloudComLibrary/src/test/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponseTest.kt
new file mode 100644
index 00000000000..861cbeddb79
--- /dev/null
+++ b/owncloudComLibrary/src/test/java/com/owncloud/android/lib/resources/status/responses/CapabilityResponseTest.kt
@@ -0,0 +1,87 @@
+/* ownCloud Android Library is available under MIT license
+ *
+ * Copyright (C) 2026 ownCloud GmbH.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+ * OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package com.owncloud.android.lib.resources.status.responses
+
+import com.squareup.moshi.JsonAdapter
+import com.squareup.moshi.Moshi
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Test
+
+class CapabilityResponseTest {
+
+ private val adapter: JsonAdapter = Moshi.Builder()
+ .build()
+ .adapter(CapabilityResponse::class.java)
+
+ @Test
+ fun `toRemoteCapability maps misspelled search min length field`() {
+ val capabilityResponse = adapter.fromJson(
+ """
+ {
+ "version": {
+ "major": 10,
+ "minor": 0,
+ "micro": 0,
+ "string": "10.0.0",
+ "edition": "community"
+ },
+ "capabilities": {
+ "files_sharing": {
+ "search_min_lenght": 5
+ }
+ }
+ }
+ """.trimIndent()
+ )
+
+ assertNotNull(capabilityResponse)
+ assertEquals(5, capabilityResponse?.toRemoteCapability()?.filesSharingSearchMinLength)
+ }
+
+ @Test
+ fun `toRemoteCapability maps correctly spelled search min length field`() {
+ val capabilityResponse = adapter.fromJson(
+ """
+ {
+ "version": {
+ "major": 10,
+ "minor": 0,
+ "micro": 0,
+ "string": "10.0.0",
+ "edition": "community"
+ },
+ "capabilities": {
+ "files_sharing": {
+ "search_min_length": 4
+ }
+ }
+ }
+ """.trimIndent()
+ )
+
+ assertNotNull(capabilityResponse)
+ assertEquals(4, capabilityResponse?.toRemoteCapability()?.filesSharingSearchMinLength)
+ }
+}
diff --git a/owncloudData/schemas/com.owncloud.android.data.OwncloudDatabase/49.json b/owncloudData/schemas/com.owncloud.android.data.OwncloudDatabase/49.json
new file mode 100644
index 00000000000..22c26845888
--- /dev/null
+++ b/owncloudData/schemas/com.owncloud.android.data.OwncloudDatabase/49.json
@@ -0,0 +1,1158 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 49,
+ "identityHash": "2f5a1bd0d839ad8881d4829ef521b339",
+ "entities": [
+ {
+ "tableName": "app_registry",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`account_name` TEXT NOT NULL, `mime_type` TEXT NOT NULL, `ext` TEXT, `app_providers` TEXT NOT NULL, `name` TEXT, `icon` TEXT, `description` TEXT, `allow_creation` INTEGER, `default_application` TEXT, PRIMARY KEY(`account_name`, `mime_type`))",
+ "fields": [
+ {
+ "fieldPath": "accountName",
+ "columnName": "account_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mimeType",
+ "columnName": "mime_type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ext",
+ "columnName": "ext",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "appProviders",
+ "columnName": "app_providers",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "icon",
+ "columnName": "icon",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "allowCreation",
+ "columnName": "allow_creation",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "defaultApplication",
+ "columnName": "default_application",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "account_name",
+ "mime_type"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "folder_backup",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountName` TEXT NOT NULL, `behavior` TEXT NOT NULL, `sourcePath` TEXT NOT NULL, `uploadPath` TEXT NOT NULL, `wifiOnly` INTEGER NOT NULL, `chargingOnly` INTEGER NOT NULL, `name` TEXT NOT NULL, `lastSyncTimestamp` INTEGER NOT NULL, `spaceId` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "accountName",
+ "columnName": "accountName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "behavior",
+ "columnName": "behavior",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sourcePath",
+ "columnName": "sourcePath",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uploadPath",
+ "columnName": "uploadPath",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "wifiOnly",
+ "columnName": "wifiOnly",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "chargingOnly",
+ "columnName": "chargingOnly",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastSyncTimestamp",
+ "columnName": "lastSyncTimestamp",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "spaceId",
+ "columnName": "spaceId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "capabilities",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`account` TEXT, `version_major` INTEGER NOT NULL, `version_minor` INTEGER NOT NULL, `version_micro` INTEGER NOT NULL, `version_string` TEXT, `version_edition` TEXT, `core_pollinterval` INTEGER NOT NULL, `dav_chunking_version` TEXT NOT NULL, `sharing_api_enabled` INTEGER NOT NULL DEFAULT -1, `sharing_public_enabled` INTEGER NOT NULL DEFAULT -1, `sharing_public_password_enforced` INTEGER NOT NULL DEFAULT -1, `sharing_public_password_enforced_read_only` INTEGER NOT NULL DEFAULT -1, `sharing_public_password_enforced_read_write` INTEGER NOT NULL DEFAULT -1, `sharing_public_password_enforced_public_only` INTEGER NOT NULL DEFAULT -1, `sharing_public_expire_date_enabled` INTEGER NOT NULL DEFAULT -1, `sharing_public_expire_date_days` INTEGER NOT NULL, `sharing_public_expire_date_enforced` INTEGER NOT NULL DEFAULT -1, `sharing_public_upload` INTEGER NOT NULL DEFAULT -1, `sharing_public_multiple` INTEGER NOT NULL DEFAULT -1, `supports_upload_only` INTEGER NOT NULL DEFAULT -1, `sharing_resharing` INTEGER NOT NULL DEFAULT -1, `search_min_length` INTEGER, `sharing_federation_outgoing` INTEGER NOT NULL DEFAULT -1, `sharing_federation_incoming` INTEGER NOT NULL DEFAULT -1, `sharing_user_profile_picture` INTEGER NOT NULL DEFAULT -1, `files_bigfilechunking` INTEGER NOT NULL DEFAULT -1, `files_undelete` INTEGER NOT NULL DEFAULT -1, `files_versioning` INTEGER NOT NULL DEFAULT -1, `files_private_links` INTEGER NOT NULL DEFAULT -1, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `app_providers_enabled` INTEGER, `app_providers_version` TEXT, `app_providers_appsUrl` TEXT, `app_providers_openUrl` TEXT, `app_providers_openWebUrl` TEXT, `app_providers_newUrl` TEXT, `spaces_enabled` INTEGER, `spaces_projects` INTEGER, `spaces_shareJail` INTEGER, `spaces_hasMultiplePersonalSpaces` INTEGER, `password_policy_maxCharacters` INTEGER, `password_policy_minCharacters` INTEGER, `password_policy_minDigits` INTEGER, `password_policy_minLowercaseCharacters` INTEGER, `password_policy_minSpecialCharacters` INTEGER, `password_policy_minUppercaseCharacters` INTEGER)",
+ "fields": [
+ {
+ "fieldPath": "accountName",
+ "columnName": "account",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "versionMajor",
+ "columnName": "version_major",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "versionMinor",
+ "columnName": "version_minor",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "versionMicro",
+ "columnName": "version_micro",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "versionString",
+ "columnName": "version_string",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "versionEdition",
+ "columnName": "version_edition",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "corePollInterval",
+ "columnName": "core_pollinterval",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "davChunkingVersion",
+ "columnName": "dav_chunking_version",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filesSharingApiEnabled",
+ "columnName": "sharing_api_enabled",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingPublicEnabled",
+ "columnName": "sharing_public_enabled",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingPublicPasswordEnforced",
+ "columnName": "sharing_public_password_enforced",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingPublicPasswordEnforcedReadOnly",
+ "columnName": "sharing_public_password_enforced_read_only",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingPublicPasswordEnforcedReadWrite",
+ "columnName": "sharing_public_password_enforced_read_write",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingPublicPasswordEnforcedUploadOnly",
+ "columnName": "sharing_public_password_enforced_public_only",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingPublicExpireDateEnabled",
+ "columnName": "sharing_public_expire_date_enabled",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingPublicExpireDateDays",
+ "columnName": "sharing_public_expire_date_days",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "filesSharingPublicExpireDateEnforced",
+ "columnName": "sharing_public_expire_date_enforced",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingPublicUpload",
+ "columnName": "sharing_public_upload",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingPublicMultiple",
+ "columnName": "sharing_public_multiple",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingPublicSupportsUploadOnly",
+ "columnName": "supports_upload_only",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingResharing",
+ "columnName": "sharing_resharing",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingSearchMinLength",
+ "columnName": "search_min_length",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "filesSharingFederationOutgoing",
+ "columnName": "sharing_federation_outgoing",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingFederationIncoming",
+ "columnName": "sharing_federation_incoming",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesSharingUserProfilePicture",
+ "columnName": "sharing_user_profile_picture",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesBigFileChunking",
+ "columnName": "files_bigfilechunking",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesUndelete",
+ "columnName": "files_undelete",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesVersioning",
+ "columnName": "files_versioning",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "filesPrivateLinks",
+ "columnName": "files_private_links",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "-1"
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "appProviders.enabled",
+ "columnName": "app_providers_enabled",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "appProviders.version",
+ "columnName": "app_providers_version",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "appProviders.appsUrl",
+ "columnName": "app_providers_appsUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "appProviders.openUrl",
+ "columnName": "app_providers_openUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "appProviders.openWebUrl",
+ "columnName": "app_providers_openWebUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "appProviders.newUrl",
+ "columnName": "app_providers_newUrl",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "spaces.enabled",
+ "columnName": "spaces_enabled",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "spaces.projects",
+ "columnName": "spaces_projects",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "spaces.shareJail",
+ "columnName": "spaces_shareJail",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "spaces.hasMultiplePersonalSpaces",
+ "columnName": "spaces_hasMultiplePersonalSpaces",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "passwordPolicy.maxCharacters",
+ "columnName": "password_policy_maxCharacters",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "passwordPolicy.minCharacters",
+ "columnName": "password_policy_minCharacters",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "passwordPolicy.minDigits",
+ "columnName": "password_policy_minDigits",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "passwordPolicy.minLowercaseCharacters",
+ "columnName": "password_policy_minLowercaseCharacters",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "passwordPolicy.minSpecialCharacters",
+ "columnName": "password_policy_minSpecialCharacters",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "passwordPolicy.minUppercaseCharacters",
+ "columnName": "password_policy_minUppercaseCharacters",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "files",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`parentId` INTEGER, `owner` TEXT NOT NULL, `remotePath` TEXT NOT NULL, `remoteId` TEXT, `length` INTEGER NOT NULL, `creationTimestamp` INTEGER, `modificationTimestamp` INTEGER NOT NULL, `mimeType` TEXT NOT NULL, `etag` TEXT, `permissions` TEXT, `privateLink` TEXT, `storagePath` TEXT, `name` TEXT, `treeEtag` TEXT, `keepInSync` INTEGER, `lastSyncDateForData` INTEGER, `lastUsage` INTEGER, `fileShareViaLink` INTEGER, `needsToUpdateThumbnail` INTEGER NOT NULL, `modifiedAtLastSyncForData` INTEGER, `etagInConflict` TEXT, `fileIsDownloading` INTEGER, `sharedWithSharee` INTEGER, `sharedByLink` INTEGER NOT NULL, `spaceId` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, FOREIGN KEY(`owner`, `spaceId`) REFERENCES `spaces`(`account_name`, `space_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "owner",
+ "columnName": "owner",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "remotePath",
+ "columnName": "remotePath",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "remoteId",
+ "columnName": "remoteId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "length",
+ "columnName": "length",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "creationTimestamp",
+ "columnName": "creationTimestamp",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "modificationTimestamp",
+ "columnName": "modificationTimestamp",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "mimeType",
+ "columnName": "mimeType",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "etag",
+ "columnName": "etag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "permissions",
+ "columnName": "permissions",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "privateLink",
+ "columnName": "privateLink",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "storagePath",
+ "columnName": "storagePath",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "treeEtag",
+ "columnName": "treeEtag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "availableOfflineStatus",
+ "columnName": "keepInSync",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lastSyncDateForData",
+ "columnName": "lastSyncDateForData",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lastUsage",
+ "columnName": "lastUsage",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileShareViaLink",
+ "columnName": "fileShareViaLink",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "needsToUpdateThumbnail",
+ "columnName": "needsToUpdateThumbnail",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "modifiedAtLastSyncForData",
+ "columnName": "modifiedAtLastSyncForData",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "etagInConflict",
+ "columnName": "etagInConflict",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "fileIsDownloading",
+ "columnName": "fileIsDownloading",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedWithSharee",
+ "columnName": "sharedWithSharee",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedByLink",
+ "columnName": "sharedByLink",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "spaceId",
+ "columnName": "spaceId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "spaces",
+ "onDelete": "CASCADE",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "owner",
+ "spaceId"
+ ],
+ "referencedColumns": [
+ "account_name",
+ "space_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "files_sync",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`fileId` INTEGER NOT NULL, `uploadWorkerUuid` BLOB, `downloadWorkerUuid` BLOB, `isSynchronizing` INTEGER NOT NULL, PRIMARY KEY(`fileId`), FOREIGN KEY(`fileId`) REFERENCES `files`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "fileId",
+ "columnName": "fileId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "uploadWorkerUuid",
+ "columnName": "uploadWorkerUuid",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "downloadWorkerUuid",
+ "columnName": "downloadWorkerUuid",
+ "affinity": "BLOB",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isSynchronizing",
+ "columnName": "isSynchronizing",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "fileId"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "files",
+ "onDelete": "CASCADE",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "fileId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "ocshares",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`share_type` INTEGER NOT NULL, `share_with` TEXT, `path` TEXT NOT NULL, `permissions` INTEGER NOT NULL, `shared_date` INTEGER NOT NULL, `expiration_date` INTEGER NOT NULL, `token` TEXT, `shared_with_display_name` TEXT, `share_with_additional_info` TEXT, `is_directory` INTEGER NOT NULL, `id_remote_shared` TEXT NOT NULL, `owner_share` TEXT NOT NULL, `name` TEXT, `url` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "shareType",
+ "columnName": "share_type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "shareWith",
+ "columnName": "share_with",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "path",
+ "columnName": "path",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "permissions",
+ "columnName": "permissions",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "sharedDate",
+ "columnName": "shared_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "expirationDate",
+ "columnName": "expiration_date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "token",
+ "columnName": "token",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedWithDisplayName",
+ "columnName": "shared_with_display_name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sharedWithAdditionalInfo",
+ "columnName": "share_with_additional_info",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "isFolder",
+ "columnName": "is_directory",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "remoteId",
+ "columnName": "id_remote_shared",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountOwner",
+ "columnName": "owner_share",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "shareLink",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "transfers",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localPath` TEXT NOT NULL, `remotePath` TEXT NOT NULL, `accountName` TEXT NOT NULL, `fileSize` INTEGER NOT NULL, `status` INTEGER NOT NULL, `localBehaviour` INTEGER NOT NULL, `forceOverwrite` INTEGER NOT NULL, `transferEndTimestamp` INTEGER, `lastResult` INTEGER, `createdBy` INTEGER NOT NULL, `transferId` TEXT, `spaceId` TEXT, `sourcePath` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
+ "fields": [
+ {
+ "fieldPath": "localPath",
+ "columnName": "localPath",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "remotePath",
+ "columnName": "remotePath",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountName",
+ "columnName": "accountName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fileSize",
+ "columnName": "fileSize",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "status",
+ "columnName": "status",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "localBehaviour",
+ "columnName": "localBehaviour",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "forceOverwrite",
+ "columnName": "forceOverwrite",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "transferEndTimestamp",
+ "columnName": "transferEndTimestamp",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "lastResult",
+ "columnName": "lastResult",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "createdBy",
+ "columnName": "createdBy",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "transferId",
+ "columnName": "transferId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "spaceId",
+ "columnName": "spaceId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "sourcePath",
+ "columnName": "sourcePath",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "spaces",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`account_name` TEXT NOT NULL, `drive_alias` TEXT, `drive_type` TEXT NOT NULL, `space_id` TEXT NOT NULL, `last_modified_date_time` TEXT, `name` TEXT NOT NULL, `owner_id` TEXT, `web_url` TEXT, `description` TEXT, `quota_remaining` INTEGER, `quota_state` TEXT, `quota_total` INTEGER, `quota_used` INTEGER, `root_etag` TEXT, `root_id` TEXT NOT NULL, `root_web_dav_url` TEXT NOT NULL, `root_deleted_state` TEXT, `space_role` TEXT, PRIMARY KEY(`account_name`, `space_id`))",
+ "fields": [
+ {
+ "fieldPath": "accountName",
+ "columnName": "account_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "driveAlias",
+ "columnName": "drive_alias",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "driveType",
+ "columnName": "drive_type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "space_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastModifiedDateTime",
+ "columnName": "last_modified_date_time",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "ownerId",
+ "columnName": "owner_id",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "webUrl",
+ "columnName": "web_url",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "description",
+ "columnName": "description",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "quota.remaining",
+ "columnName": "quota_remaining",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "quota.state",
+ "columnName": "quota_state",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "quota.total",
+ "columnName": "quota_total",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "quota.used",
+ "columnName": "quota_used",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "root.eTag",
+ "columnName": "root_etag",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "root.id",
+ "columnName": "root_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "root.webDavUrl",
+ "columnName": "root_web_dav_url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "root.deleteState",
+ "columnName": "root_deleted_state",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "root.role",
+ "columnName": "space_role",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "account_name",
+ "space_id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "spaces_special",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`spaces_special_account_name` TEXT NOT NULL, `spaces_special_space_id` TEXT NOT NULL, `spaces_special_etag` TEXT NOT NULL, `file_mime_type` TEXT NOT NULL, `special_id` TEXT NOT NULL, `last_modified_date_time` TEXT, `name` TEXT NOT NULL, `size` INTEGER NOT NULL, `special_folder_name` TEXT NOT NULL, `special_web_dav_url` TEXT NOT NULL, PRIMARY KEY(`spaces_special_space_id`, `special_id`), FOREIGN KEY(`spaces_special_account_name`, `spaces_special_space_id`) REFERENCES `spaces`(`account_name`, `space_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "accountName",
+ "columnName": "spaces_special_account_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "spaceId",
+ "columnName": "spaces_special_space_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "eTag",
+ "columnName": "spaces_special_etag",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fileMimeType",
+ "columnName": "file_mime_type",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "special_id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "lastModifiedDateTime",
+ "columnName": "last_modified_date_time",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "size",
+ "columnName": "size",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "specialFolderName",
+ "columnName": "special_folder_name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "webDavUrl",
+ "columnName": "special_web_dav_url",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "spaces_special_space_id",
+ "special_id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": [
+ {
+ "table": "spaces",
+ "onDelete": "CASCADE",
+ "onUpdate": "NO ACTION",
+ "columns": [
+ "spaces_special_account_name",
+ "spaces_special_space_id"
+ ],
+ "referencedColumns": [
+ "account_name",
+ "space_id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "user_quotas",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountName` TEXT NOT NULL, `used` INTEGER NOT NULL, `available` INTEGER NOT NULL, `total` INTEGER, `state` TEXT, PRIMARY KEY(`accountName`))",
+ "fields": [
+ {
+ "fieldPath": "accountName",
+ "columnName": "accountName",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "used",
+ "columnName": "used",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "available",
+ "columnName": "available",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "total",
+ "columnName": "total",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "state",
+ "columnName": "state",
+ "affinity": "TEXT",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "accountName"
+ ]
+ },
+ "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, '2f5a1bd0d839ad8881d4829ef521b339')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/owncloudData/src/main/java/com/owncloud/android/data/OwncloudDatabase.kt b/owncloudData/src/main/java/com/owncloud/android/data/OwncloudDatabase.kt
index db30f05b676..882e5576667 100644
--- a/owncloudData/src/main/java/com/owncloud/android/data/OwncloudDatabase.kt
+++ b/owncloudData/src/main/java/com/owncloud/android/data/OwncloudDatabase.kt
@@ -83,6 +83,7 @@ import com.owncloud.android.data.user.db.UserQuotaEntity
AutoMigration(from = 45, to = 46),
AutoMigration(from = 46, to = 47),
AutoMigration(from = 47, to = 48),
+ AutoMigration(from = 48, to = 49),
],
version = ProviderMeta.DB_VERSION,
exportSchema = true
diff --git a/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java b/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java
index 8788f7285d8..bd02f0d1a40 100644
--- a/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java
+++ b/owncloudData/src/main/java/com/owncloud/android/data/ProviderMeta.java
@@ -31,7 +31,7 @@ public class ProviderMeta {
public static final String DB_NAME = "filelist";
public static final String NEW_DB_NAME = "owncloud_database";
- public static final int DB_VERSION = 48;
+ public static final int DB_VERSION = 49;
private ProviderMeta() {
}
@@ -90,6 +90,7 @@ static public class ProviderTableMeta implements BaseColumns {
public static final String CAPABILITIES_SHARING_PUBLIC_SUPPORTS_UPLOAD_ONLY = "supports_upload_only";
public static final String CAPABILITIES_SHARING_PUBLIC_UPLOAD = "sharing_public_upload";
public static final String CAPABILITIES_SHARING_RESHARING = "sharing_resharing";
+ public static final String CAPABILITIES_SHARING_SEARCH_MIN_LENGTH = "search_min_length";
public static final String CAPABILITIES_SHARING_USER_PROFILE_PICTURE = "sharing_user_profile_picture";
public static final String CAPABILITIES_SPACES_PREFIX = "spaces_";
public static final String CAPABILITIES_PASSWORD_POLICY_PREFIX = "password_policy_";
diff --git a/owncloudData/src/main/java/com/owncloud/android/data/capabilities/datasources/implementation/OCLocalCapabilitiesDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/capabilities/datasources/implementation/OCLocalCapabilitiesDataSource.kt
index ecd58d84c27..b283a04be83 100644
--- a/owncloudData/src/main/java/com/owncloud/android/data/capabilities/datasources/implementation/OCLocalCapabilitiesDataSource.kt
+++ b/owncloudData/src/main/java/com/owncloud/android/data/capabilities/datasources/implementation/OCLocalCapabilitiesDataSource.kt
@@ -76,6 +76,7 @@ class OCLocalCapabilitiesDataSource(
filesSharingPublicMultiple = CapabilityBooleanType.fromValue(filesSharingPublicMultiple),
filesSharingPublicSupportsUploadOnly = CapabilityBooleanType.fromValue(filesSharingPublicSupportsUploadOnly),
filesSharingResharing = CapabilityBooleanType.fromValue(filesSharingResharing),
+ filesSharingSearchMinLength = filesSharingSearchMinLength,
filesSharingFederationOutgoing = CapabilityBooleanType.fromValue(filesSharingFederationOutgoing),
filesSharingFederationIncoming = CapabilityBooleanType.fromValue(filesSharingFederationIncoming),
filesSharingUserProfilePicture = CapabilityBooleanType.fromValue(filesSharingUserProfilePicture),
@@ -112,6 +113,7 @@ class OCLocalCapabilitiesDataSource(
filesSharingPublicMultiple = filesSharingPublicMultiple.value,
filesSharingPublicSupportsUploadOnly = filesSharingPublicSupportsUploadOnly.value,
filesSharingResharing = filesSharingResharing.value,
+ filesSharingSearchMinLength = filesSharingSearchMinLength,
filesSharingFederationOutgoing = filesSharingFederationOutgoing.value,
filesSharingFederationIncoming = filesSharingFederationIncoming.value,
filesSharingUserProfilePicture = filesSharingUserProfilePicture.value,
diff --git a/owncloudData/src/main/java/com/owncloud/android/data/capabilities/datasources/mapper/RemoteCapabilityMapper.kt b/owncloudData/src/main/java/com/owncloud/android/data/capabilities/datasources/mapper/RemoteCapabilityMapper.kt
index 4280a9b01bb..d946b8087ee 100644
--- a/owncloudData/src/main/java/com/owncloud/android/data/capabilities/datasources/mapper/RemoteCapabilityMapper.kt
+++ b/owncloudData/src/main/java/com/owncloud/android/data/capabilities/datasources/mapper/RemoteCapabilityMapper.kt
@@ -59,6 +59,7 @@ class RemoteCapabilityMapper : RemoteMapper {
filesSharingPublicSupportsUploadOnly =
CapabilityBooleanType.fromValue(remote.filesSharingPublicSupportsUploadOnly.value),
filesSharingResharing = CapabilityBooleanType.fromValue(remote.filesSharingResharing.value),
+ filesSharingSearchMinLength = remote.filesSharingSearchMinLength,
filesSharingFederationOutgoing =
CapabilityBooleanType.fromValue(remote.filesSharingFederationOutgoing.value),
filesSharingFederationIncoming =
@@ -105,6 +106,7 @@ class RemoteCapabilityMapper : RemoteMapper {
filesSharingPublicSupportsUploadOnly =
RemoteCapabilityBooleanType.fromValue(model.filesSharingPublicSupportsUploadOnly.value)!!,
filesSharingResharing = RemoteCapabilityBooleanType.fromValue(model.filesSharingResharing.value)!!,
+ filesSharingSearchMinLength = model.filesSharingSearchMinLength,
filesSharingFederationOutgoing =
RemoteCapabilityBooleanType.fromValue(model.filesSharingFederationOutgoing.value)!!,
filesSharingFederationIncoming =
diff --git a/owncloudData/src/main/java/com/owncloud/android/data/capabilities/db/OCCapabilityEntity.kt b/owncloudData/src/main/java/com/owncloud/android/data/capabilities/db/OCCapabilityEntity.kt
index d44bf2324de..17ac4903abf 100644
--- a/owncloudData/src/main/java/com/owncloud/android/data/capabilities/db/OCCapabilityEntity.kt
+++ b/owncloudData/src/main/java/com/owncloud/android/data/capabilities/db/OCCapabilityEntity.kt
@@ -49,6 +49,7 @@ import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.CAPABILITIES_SHA
import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_SUPPORTS_UPLOAD_ONLY
import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_UPLOAD
import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.CAPABILITIES_SHARING_RESHARING
+import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.CAPABILITIES_SHARING_SEARCH_MIN_LENGTH
import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.CAPABILITIES_SHARING_USER_PROFILE_PICTURE
import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.CAPABILITIES_SPACES_PREFIX
import com.owncloud.android.data.ProviderMeta.ProviderTableMeta.CAPABILITIES_TABLE_NAME
@@ -108,6 +109,8 @@ data class OCCapabilityEntity(
val filesSharingPublicSupportsUploadOnly: Int,
@ColumnInfo(name = CAPABILITIES_SHARING_RESHARING, defaultValue = capabilityBooleanTypeUnknownString)
val filesSharingResharing: Int,
+ @ColumnInfo(name = CAPABILITIES_SHARING_SEARCH_MIN_LENGTH)
+ val filesSharingSearchMinLength: Int?,
@ColumnInfo(name = CAPABILITIES_SHARING_FEDERATION_OUTGOING, defaultValue = capabilityBooleanTypeUnknownString)
val filesSharingFederationOutgoing: Int,
@ColumnInfo(name = CAPABILITIES_SHARING_FEDERATION_INCOMING, defaultValue = capabilityBooleanTypeUnknownString)
@@ -155,6 +158,9 @@ data class OCCapabilityEntity(
it.getInt(it.getColumnIndexOrThrow(CAPABILITIES_SHARING_PUBLIC_MULTIPLE)),
it.getInt(it.getColumnIndexOrThrow(CAPABILITIES_SHARING_PUBLIC_SUPPORTS_UPLOAD_ONLY)),
it.getInt(it.getColumnIndexOrThrow(CAPABILITIES_SHARING_RESHARING)),
+ it.getColumnIndex(CAPABILITIES_SHARING_SEARCH_MIN_LENGTH).takeUnless { index -> index < 0 }?.let { index ->
+ if (it.isNull(index)) null else it.getInt(index)
+ },
it.getInt(it.getColumnIndexOrThrow(CAPABILITIES_SHARING_FEDERATION_OUTGOING)),
it.getInt(it.getColumnIndexOrThrow(CAPABILITIES_SHARING_FEDERATION_INCOMING)),
it.getInt(it.getColumnIndexOrThrow(CAPABILITIES_SHARING_USER_PROFILE_PICTURE)),
diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/capabilities/model/OCCapability.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/capabilities/model/OCCapability.kt
index cf92de4a637..d7a8cc39587 100644
--- a/owncloudDomain/src/main/java/com/owncloud/android/domain/capabilities/model/OCCapability.kt
+++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/capabilities/model/OCCapability.kt
@@ -44,6 +44,7 @@ data class OCCapability(
val filesSharingPublicMultiple: CapabilityBooleanType,
val filesSharingPublicSupportsUploadOnly: CapabilityBooleanType,
val filesSharingResharing: CapabilityBooleanType,
+ val filesSharingSearchMinLength: Int?,
val filesSharingFederationOutgoing: CapabilityBooleanType,
val filesSharingFederationIncoming: CapabilityBooleanType,
val filesSharingUserProfilePicture: CapabilityBooleanType,
@@ -69,6 +70,13 @@ data class OCCapability(
fun isSpacesProjectsAllowed(): Boolean = spaces?.projects == true
+ fun getFilesSharingSearchMinLength(): Int =
+ filesSharingSearchMinLength?.takeIf { it > 0 } ?: DEFAULT_FILES_SHARING_SEARCH_MIN_LENGTH
+
+ companion object {
+ const val DEFAULT_FILES_SHARING_SEARCH_MIN_LENGTH = 3
+ }
+
data class AppProviders(
val enabled: Boolean,
val version: String,
diff --git a/owncloudDomain/src/test/java/com/owncloud/android/domain/capabilities/model/OCCapabilityTest.kt b/owncloudDomain/src/test/java/com/owncloud/android/domain/capabilities/model/OCCapabilityTest.kt
index 064ae3c411d..aa19027a34c 100644
--- a/owncloudDomain/src/test/java/com/owncloud/android/domain/capabilities/model/OCCapabilityTest.kt
+++ b/owncloudDomain/src/test/java/com/owncloud/android/domain/capabilities/model/OCCapabilityTest.kt
@@ -82,4 +82,22 @@ class OCCapabilityTest {
val item2 = OC_CAPABILITY.copy(filesAppProviders = null)
assertFalse(item2.isOpenInWebAllowed())
}
+
+ @Test
+ fun `getFilesSharingSearchMinLength returns capability value when positive`() {
+ val item = OC_CAPABILITY.copy(filesSharingSearchMinLength = 5)
+
+ assertEquals(5, item.getFilesSharingSearchMinLength())
+ }
+
+ @Test
+ fun `getFilesSharingSearchMinLength returns default when null or invalid`() {
+ val itemWithNull = OC_CAPABILITY.copy(filesSharingSearchMinLength = null)
+ val itemWithZero = OC_CAPABILITY.copy(filesSharingSearchMinLength = 0)
+ val itemWithNegative = OC_CAPABILITY.copy(filesSharingSearchMinLength = -1)
+
+ assertEquals(OCCapability.DEFAULT_FILES_SHARING_SEARCH_MIN_LENGTH, itemWithNull.getFilesSharingSearchMinLength())
+ assertEquals(OCCapability.DEFAULT_FILES_SHARING_SEARCH_MIN_LENGTH, itemWithZero.getFilesSharingSearchMinLength())
+ assertEquals(OCCapability.DEFAULT_FILES_SHARING_SEARCH_MIN_LENGTH, itemWithNegative.getFilesSharingSearchMinLength())
+ }
}
diff --git a/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCCapability.kt b/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCCapability.kt
index 8f12534fb75..81394cfca4a 100644
--- a/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCCapability.kt
+++ b/owncloudTestUtil/src/main/java/com/owncloud/android/testutil/OCCapability.kt
@@ -46,6 +46,7 @@ val OC_CAPABILITY =
filesSharingPublicMultiple = CapabilityBooleanType.FALSE,
filesSharingPublicSupportsUploadOnly = CapabilityBooleanType.FALSE,
filesSharingResharing = CapabilityBooleanType.FALSE,
+ filesSharingSearchMinLength = 3,
filesSharingFederationOutgoing = CapabilityBooleanType.FALSE,
filesSharingFederationIncoming = CapabilityBooleanType.FALSE,
filesSharingUserProfilePicture = CapabilityBooleanType.FALSE,