Skip to content

Commit 40fea7d

Browse files
Merge pull request #1622 from nextcloud/tagColor
Feature - Add Tag Color
2 parents e399f10 + 0b31cc6 commit 40fea7d

7 files changed

Lines changed: 128 additions & 24 deletions

File tree

library/src/androidTest/java/com/owncloud/android/lib/resources/files/ReadFolderRemoteOperationIT.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ class ReadFolderRemoteOperationIT : AbstractIT() {
9494
assertEquals(remotePath + "1.txt", remoteFile.remotePath)
9595
assertEquals(2, remoteFile.tags?.size)
9696

97-
remoteFile.tags?.sort()
98-
assertEquals(tag1, remoteFile.tags?.get(0))
99-
assertEquals(tag2, remoteFile.tags?.get(1))
97+
remoteFile.tags?.sortBy { it?.name }
98+
assertEquals(tag1, remoteFile.tags?.get(0)?.name)
99+
assertEquals(tag2, remoteFile.tags?.get(1)?.name)
100100
}
101101
}

library/src/androidTest/java/com/owncloud/android/lib/resources/tags/GetTagsRemoteOperationIT.kt

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,20 @@ package com.owncloud.android.lib.resources.tags
99

1010
import com.nextcloud.test.RandomStringGenerator
1111
import com.owncloud.android.AbstractIT
12+
import com.owncloud.android.lib.common.network.WebdavEntry
13+
import com.owncloud.android.lib.resources.files.CreateFolderRemoteOperation
14+
import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation
15+
import com.owncloud.android.lib.resources.files.ReadFolderRemoteOperation
16+
import com.owncloud.android.lib.resources.files.model.RemoteFile
17+
import com.owncloud.android.lib.resources.status.NextcloudVersion
1218
import junit.framework.TestCase.assertEquals
1319
import junit.framework.TestCase.assertTrue
20+
import org.apache.commons.httpclient.HttpStatus
21+
import org.apache.jackrabbit.webdav.client.methods.PropPatchMethod
22+
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet
23+
import org.apache.jackrabbit.webdav.property.DavPropertySet
24+
import org.apache.jackrabbit.webdav.property.DefaultDavProperty
25+
import org.apache.jackrabbit.webdav.xml.Namespace
1426
import org.junit.Test
1527

1628
class GetTagsRemoteOperationIT : AbstractIT() {
@@ -19,7 +31,10 @@ class GetTagsRemoteOperationIT : AbstractIT() {
1931
}
2032

2133
@Test
34+
@Suppress("LongMethod")
2235
fun list() {
36+
testOnlyOnServer(NextcloudVersion.nextcloud_31)
37+
2338
var sut = GetTagsRemoteOperation().execute(client)
2439
assertTrue(sut.isSuccess)
2540

@@ -31,8 +46,66 @@ class GetTagsRemoteOperationIT : AbstractIT() {
3146
.isSuccess
3247
)
3348

49+
assertTrue(
50+
CreateTagRemoteOperation(RandomStringGenerator.make(TAG_LENGTH))
51+
.execute(nextcloudClient)
52+
.isSuccess
53+
)
54+
3455
sut = GetTagsRemoteOperation().execute(client)
3556
assertTrue(sut.isSuccess)
36-
assertEquals(count + 1, sut.resultData.size)
57+
assertEquals(count + 2, sut.resultData.size)
58+
59+
// add color to one tag
60+
val plainColor = "ff00ff"
61+
val colorWithHex = "#$plainColor"
62+
val tag1 = sut.resultData.first()
63+
val tag2 = sut.resultData[1]
64+
val newProps = DavPropertySet()
65+
newProps.add(
66+
DefaultDavProperty(
67+
"nc:color",
68+
plainColor,
69+
Namespace.getNamespace(WebdavEntry.NAMESPACE_NC)
70+
)
71+
)
72+
val propPatchMethod =
73+
PropPatchMethod(
74+
client.baseUri.toString() + "/remote.php/dav/systemtags/" + tag1.id,
75+
newProps,
76+
DavPropertyNameSet()
77+
)
78+
assertTrue(client.executeMethod(propPatchMethod) == HttpStatus.SC_MULTI_STATUS)
79+
80+
sut = GetTagsRemoteOperation().execute(client)
81+
82+
assertEquals(colorWithHex, sut.resultData.find { it.id == tag1.id }?.color)
83+
84+
// add colored tag to file
85+
val tagFolder = "/coloredFolder/"
86+
assertTrue(CreateFolderRemoteOperation(tagFolder, true).execute(client).isSuccess)
87+
val folderMetadata = ReadFileRemoteOperation(tagFolder).execute(client)
88+
assertTrue(
89+
PutTagRemoteOperation(
90+
tag1.id,
91+
(folderMetadata.data[0] as RemoteFile).localId
92+
).execute(nextcloudClient).isSuccess
93+
)
94+
assertTrue(
95+
PutTagRemoteOperation(
96+
tag2.id,
97+
(folderMetadata.data[0] as RemoteFile).localId
98+
).execute(nextcloudClient).isSuccess
99+
)
100+
101+
// read metadata
102+
val rootMetadata = ReadFolderRemoteOperation("/").execute(client)
103+
val tags =
104+
(rootMetadata.data as ArrayList<RemoteFile>)
105+
.find { it.remotePath == tagFolder }
106+
?.tags
107+
assertEquals(2, tags?.size)
108+
assertEquals(colorWithHex, tags?.first()?.color)
109+
assertEquals(null, tags?.get(1)?.color)
37110
}
38111
}

library/src/main/java/com/owncloud/android/lib/common/network/WebdavEntry.kt

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.owncloud.android.lib.resources.files.model.GeoLocation
2121
import com.owncloud.android.lib.resources.files.model.ImageDimension
2222
import com.owncloud.android.lib.resources.shares.ShareType
2323
import com.owncloud.android.lib.resources.shares.ShareeUser
24+
import com.owncloud.android.lib.resources.tags.Tag
2425
import org.apache.jackrabbit.webdav.MultiStatusResponse
2526
import org.apache.jackrabbit.webdav.property.DavProperty
2627
import org.apache.jackrabbit.webdav.property.DavPropertyName
@@ -90,7 +91,7 @@ class WebdavEntry constructor(
9091
private set
9192
var lockToken: String? = null
9293
private set
93-
var tags = arrayOfNulls<String>(0)
94+
var tags = emptyArray<Tag?>()
9495
var imageDimension: ImageDimension? = null
9596
var geoLocation: GeoLocation? = null
9697
var hidden = false
@@ -393,24 +394,23 @@ class WebdavEntry constructor(
393394
}
394395

395396
prop = propSet[EXTENDED_PROPERTY_SYSTEM_TAGS, ncNamespace]
396-
if (prop != null && prop.value != null) {
397-
if (prop.value is ArrayList<*>) {
398-
val list = prop.value as ArrayList<*>
399-
val tempList: MutableList<String> = ArrayList(list.size)
400-
for (i in list.indices) {
401-
val element = list[i] as Element
402-
tempList.add(element.firstChild.textContent)
403-
}
404-
tags = tempList.toTypedArray()
405-
} else {
406-
// single item or empty
407-
val element = prop.value as Element
408-
val value = element.firstChild.textContent
397+
if (prop?.value != null) {
398+
tags =
399+
when (prop.value) {
400+
is ArrayList<*> ->
401+
(prop.value as ArrayList<*>)
402+
.filterIsInstance<Element>()
403+
.map { parseTag(it) }
404+
.toTypedArray()
405+
406+
is Element -> {
407+
val element = (prop.value as Element)
408+
val tag = parseTag(element)
409+
arrayOf(tag)
410+
}
409411

410-
if (value != null) {
411-
tags = arrayOf(value)
412+
else -> emptyArray()
412413
}
413-
}
414414
}
415415

416416
// NC metadata size property <nc:file-metadata-size>
@@ -485,6 +485,18 @@ class WebdavEntry constructor(
485485
}
486486
}
487487

488+
private fun parseTag(element: Element): Tag {
489+
val name = element.firstChild.textContent
490+
491+
val color =
492+
if (element.getAttribute("nc:color").isNotEmpty()) {
493+
"#" + element.getAttribute("nc:color")
494+
} else {
495+
null
496+
}
497+
return Tag(remoteId ?: "", name, color)
498+
}
499+
488500
private fun parseLockProperties(
489501
ncNamespace: Namespace,
490502
propSet: DavPropertySet
@@ -659,6 +671,7 @@ class WebdavEntry constructor(
659671
const val EXTENDED_PROPERTY_LOCK_TIMEOUT = "lock-timeout"
660672
const val EXTENDED_PROPERTY_LOCK_TOKEN = "lock-token"
661673
const val EXTENDED_PROPERTY_SYSTEM_TAGS = "system-tags"
674+
const val EXTENDED_PROPERTY_SYSTEM_TAGS_COLOR = "color"
662675

663676
// v27
664677
const val EXTENDED_PROPERTY_METADATA_SIZE = "file-metadata-size"

library/src/main/java/com/owncloud/android/lib/common/network/WebdavUtils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ public static DavPropertyNameSet getAllPropSet() {
117117
propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_TIMEOUT, ncNamespace);
118118
propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_TOKEN, ncNamespace);
119119
propSet.add(WebdavEntry.EXTENDED_PROPERTY_SYSTEM_TAGS, ncNamespace);
120+
propSet.add(WebdavEntry.EXTENDED_PROPERTY_SYSTEM_TAGS_COLOR, ncNamespace);
120121
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_SIZE, ncNamespace);
121122
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_GPS, ncNamespace);
122123
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_PHOTOS_SIZE, ncNamespace);

library/src/main/java/com/owncloud/android/lib/resources/files/model/RemoteFile.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.owncloud.android.lib.common.network.WebdavEntry.MountType
1414
import com.owncloud.android.lib.resources.files.FileUtils
1515
import com.owncloud.android.lib.resources.files.model.FileLockType.Companion.fromValue
1616
import com.owncloud.android.lib.resources.shares.ShareeUser
17+
import com.owncloud.android.lib.resources.tags.Tag
1718
import java.io.Serializable
1819

1920
/**
@@ -53,7 +54,7 @@ class RemoteFile :
5354
var lockOwnerEditor: String? = null
5455
var lockTimeout: Long = 0
5556
var lockToken: String? = null
56-
var tags: Array<String?>? = null
57+
var tags: Array<Tag?>? = null
5758
var imageDimension: ImageDimension? = null
5859
var geoLocation: GeoLocation? = null
5960
var hidden = false

library/src/main/java/com/owncloud/android/lib/resources/tags/GetTagsRemoteOperation.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ package com.owncloud.android.lib.resources.tags
99

1010
import com.owncloud.android.lib.common.OwnCloudClient
1111
import com.owncloud.android.lib.common.network.WebdavEntry.Companion.EXTENDED_PROPERTY_NAME_REMOTE_ID
12+
import com.owncloud.android.lib.common.network.WebdavEntry.Companion.EXTENDED_PROPERTY_SYSTEM_TAGS_COLOR
13+
import com.owncloud.android.lib.common.network.WebdavEntry.Companion.NAMESPACE_NC
1214
import com.owncloud.android.lib.common.network.WebdavEntry.Companion.NAMESPACE_OC
1315
import com.owncloud.android.lib.common.network.WebdavEntry.Companion.SHAREES_DISPLAY_NAME
1416
import com.owncloud.android.lib.common.operations.RemoteOperation
@@ -18,15 +20,18 @@ import org.apache.jackrabbit.webdav.client.methods.PropFindMethod
1820
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet
1921
import org.apache.jackrabbit.webdav.xml.Namespace
2022

23+
@Suppress("NestedBlockDepth")
2124
class GetTagsRemoteOperation : RemoteOperation<List<Tag>>() {
2225
@Deprecated("Deprecated in Java")
2326
override fun run(client: OwnCloudClient): RemoteOperationResult<List<Tag>> {
2427
val ocNamespace = Namespace.getNamespace(NAMESPACE_OC)
28+
val ncNamespace = Namespace.getNamespace(NAMESPACE_NC)
2529

2630
val propSet =
2731
DavPropertyNameSet().apply {
2832
add(EXTENDED_PROPERTY_NAME_REMOTE_ID, ocNamespace)
2933
add(SHAREES_DISPLAY_NAME, ocNamespace)
34+
add(EXTENDED_PROPERTY_SYSTEM_TAGS_COLOR, ncNamespace)
3035
}
3136

3237
val propFindMethod =
@@ -55,7 +60,17 @@ class GetTagsRemoteOperation : RemoteOperation<List<Tag>>() {
5560
.get(SHAREES_DISPLAY_NAME, ocNamespace)
5661
.value as String
5762

58-
result.add(Tag(id, name))
63+
var color =
64+
it
65+
.getProperties(HttpStatus.SC_OK)
66+
.get(EXTENDED_PROPERTY_SYSTEM_TAGS_COLOR, ncNamespace)
67+
?.value as String?
68+
69+
if (color != null) {
70+
color = "#$color"
71+
}
72+
73+
result.add(Tag(id, name, color))
5974
}
6075
}
6176

library/src/main/java/com/owncloud/android/lib/resources/tags/Tag.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ package com.owncloud.android.lib.resources.tags
99

1010
data class Tag(
1111
val id: String,
12-
val name: String
12+
val name: String,
13+
val color: String?
1314
)

0 commit comments

Comments
 (0)