Skip to content

Commit df8e9ec

Browse files
Merge pull request #1263 from nextcloud/feature/live-photo-impl
Feature Live Photo
2 parents e34a5df + b3f2a36 commit df8e9ec

File tree

6 files changed

+168
-1
lines changed

6 files changed

+168
-1
lines changed

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,51 @@ class ReadFileRemoteOperationIT : AbstractIT() {
4747
assertEquals(remotePath, (result.data[0] as RemoteFile).remotePath)
4848
}
4949

50+
@Test
51+
fun testLivePhoto() {
52+
testOnlyOnServer(NextcloudVersion.nextcloud_28)
53+
54+
val movieFile = createFile("sample")
55+
val movieFilePath = "/sampleMovie.mov"
56+
assertTrue(
57+
UploadFileRemoteOperation(movieFile, movieFilePath, "video/mov", RANDOM_MTIME)
58+
.execute(client).isSuccess
59+
)
60+
61+
val livePhoto = createFile("sample")
62+
val livePhotoPath = "/samplePic.jpg"
63+
assertTrue(
64+
UploadFileRemoteOperation(livePhoto, livePhotoPath, "image/jpeg", RANDOM_MTIME)
65+
.execute(client).isSuccess
66+
)
67+
68+
// link them
69+
assertTrue(
70+
LinkLivePhotoRemoteOperation(
71+
livePhotoPath,
72+
movieFilePath
73+
).execute(client).isSuccess
74+
)
75+
76+
assertTrue(
77+
LinkLivePhotoRemoteOperation(
78+
movieFilePath,
79+
livePhotoPath
80+
).execute(client).isSuccess
81+
)
82+
83+
val movieFileResult = ReadFileRemoteOperation(movieFilePath).execute(client)
84+
assertTrue(movieFileResult.isSuccess)
85+
val movieRemoteFile = movieFileResult.data[0] as RemoteFile
86+
87+
val livePhotoResult = ReadFileRemoteOperation(livePhotoPath).execute(client)
88+
assertTrue(livePhotoResult.isSuccess)
89+
val livePhotoRemoteFile = livePhotoResult.data[0] as RemoteFile
90+
91+
assertEquals(livePhotoRemoteFile.livePhoto, movieRemoteFile.remotePath)
92+
assertTrue(movieRemoteFile.hidden)
93+
}
94+
5095
@Test
5196
fun readRemoteFile() {
5297
// create file

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) {
102102
var tags = arrayOfNulls<String>(0)
103103
var imageDimension: ImageDimension? = null
104104
var geoLocation: GeoLocation? = null
105+
var hidden = false
106+
private set
107+
var livePhoto: String? = null
108+
private set
105109

106110
private val gson = Gson()
107111

@@ -461,6 +465,21 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) {
461465
GeoLocation(latitude, longitude)
462466
}
463467

468+
// NC metadata live photo property: <nc:metadata-files-live-photo/>
469+
prop = propSet[EXTENDED_PROPERTY_METADATA_LIVE_PHOTO, ncNamespace]
470+
if (prop != null && prop.value != null) {
471+
livePhoto = prop.value.toString()
472+
}
473+
474+
// NC has hidden property <nc:hidden>
475+
prop = propSet[EXTENDED_PROPERTY_HIDDEN, ncNamespace]
476+
hidden =
477+
if (prop != null) {
478+
java.lang.Boolean.valueOf(prop.value.toString())
479+
} else {
480+
false
481+
}
482+
464483
parseLockProperties(ncNamespace, propSet)
465484
} else {
466485
Log_OC.e("WebdavEntry", "General error, no status for webdav response")
@@ -619,6 +638,9 @@ class WebdavEntry constructor(ms: MultiStatusResponse, splitElement: String) {
619638
const val EXTENDED_PROPERTY_METADATA_SIZE = "file-metadata-size"
620639
const val EXTENDED_PROPERTY_METADATA_GPS = "file-metadata-gps"
621640

641+
const val EXTENDED_PROPERTY_HIDDEN = "hidden"
642+
const val EXTENDED_PROPERTY_METADATA_LIVE_PHOTO = "metadata-files-live-photo"
643+
622644
const val EXTENDED_PROPERTY_METADATA_PHOTOS_SIZE = "metadata-photos-size"
623645
const val EXTENDED_PROPERTY_METADATA_PHOTOS_GPS = "metadata-photos-gps"
624646
const val TRASHBIN_FILENAME = "trashbin-filename"

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ public static DavPropertyNameSet getAllPropSet() {
130130
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_GPS, ncNamespace);
131131
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_PHOTOS_SIZE, ncNamespace);
132132
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_PHOTOS_GPS, ncNamespace);
133+
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_LIVE_PHOTO, ncNamespace);
134+
propSet.add(WebdavEntry.EXTENDED_PROPERTY_HIDDEN, ncNamespace);
133135

134136
return propSet;
135137
}
@@ -173,6 +175,8 @@ public static DavPropertyNameSet getFilePropSet() {
173175
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_GPS, ncNamespace);
174176
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_PHOTOS_SIZE, ncNamespace);
175177
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_PHOTOS_GPS, ncNamespace);
178+
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_LIVE_PHOTO, ncNamespace);
179+
propSet.add(WebdavEntry.EXTENDED_PROPERTY_HIDDEN, ncNamespace);
176180

177181
return propSet;
178182
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/* Nextcloud Android Library is available under MIT license
2+
*
3+
* @author Tobias Kaminsky
4+
* Copyright (C) 2018 Tobias Kaminsky
5+
* Copyright (C) 2018 Nextcloud GmbH
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*
26+
*/
27+
28+
package com.owncloud.android.lib.resources.files
29+
30+
import com.owncloud.android.lib.common.OwnCloudClient
31+
import com.owncloud.android.lib.common.network.WebdavEntry
32+
import com.owncloud.android.lib.common.operations.RemoteOperation
33+
import com.owncloud.android.lib.common.operations.RemoteOperationResult
34+
import org.apache.commons.httpclient.HttpStatus
35+
import org.apache.jackrabbit.webdav.client.methods.PropPatchMethod
36+
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet
37+
import org.apache.jackrabbit.webdav.property.DavPropertySet
38+
import org.apache.jackrabbit.webdav.property.DefaultDavProperty
39+
import org.apache.jackrabbit.webdav.xml.Namespace
40+
import java.io.IOException
41+
42+
/**
43+
* Links live photos
44+
*/
45+
class LinkLivePhotoRemoteOperation(
46+
private val path: String,
47+
private val linkedFileName: String
48+
) : RemoteOperation<Void>() {
49+
@Deprecated("Deprecated in Java")
50+
override fun run(client: OwnCloudClient): RemoteOperationResult<Void> {
51+
var result: RemoteOperationResult<Void>
52+
lateinit var propPatchMethod: PropPatchMethod
53+
val newProps = DavPropertySet()
54+
val removeProperties = DavPropertyNameSet()
55+
val readMarkerProperty =
56+
DefaultDavProperty(
57+
"nc:metadata-files-live-photo",
58+
linkedFileName,
59+
Namespace.getNamespace(WebdavEntry.NAMESPACE_NC)
60+
)
61+
newProps.add(readMarkerProperty)
62+
63+
val commentsPath = client.getFilesDavUri(path)
64+
try {
65+
propPatchMethod = PropPatchMethod(commentsPath, newProps, removeProperties)
66+
val status = client.executeMethod(propPatchMethod)
67+
val isSuccess =
68+
status == HttpStatus.SC_NO_CONTENT || status == HttpStatus.SC_OK || status == HttpStatus.SC_MULTI_STATUS
69+
result =
70+
if (isSuccess) {
71+
RemoteOperationResult<Void>(true, status, propPatchMethod.responseHeaders)
72+
} else {
73+
client.exhaustResponse(propPatchMethod.responseBodyAsStream)
74+
RemoteOperationResult<Void>(false, status, propPatchMethod.responseHeaders)
75+
}
76+
} catch (e: IOException) {
77+
result = RemoteOperationResult<Void>(e)
78+
} finally {
79+
propPatchMethod.releaseConnection()
80+
}
81+
return result
82+
}
83+
}

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ class RemoteFile : Parcelable, Serializable {
7070
var tags: Array<String?>? = null
7171
var imageDimension: ImageDimension? = null
7272
var geoLocation: GeoLocation? = null
73+
var hidden = false
74+
var livePhoto: String? = null
7375

7476
constructor() {
7577
resetData()
@@ -85,7 +87,7 @@ class RemoteFile : Parcelable, Serializable {
8587
*/
8688
constructor(path: String?) {
8789
resetData()
88-
require(!(path == null || path.isEmpty() || !path.startsWith(FileUtils.PATH_SEPARATOR))) {
90+
require(!(path.isNullOrEmpty() || !path.startsWith(FileUtils.PATH_SEPARATOR))) {
8991
"Trying to create a OCFile with a non valid remote path: $path"
9092
}
9193
remotePath = path
@@ -123,6 +125,8 @@ class RemoteFile : Parcelable, Serializable {
123125
tags = we.tags
124126
imageDimension = we.imageDimension
125127
geoLocation = we.geoLocation
128+
livePhoto = we.livePhoto
129+
hidden = we.hidden
126130
}
127131

128132
/**
@@ -153,6 +157,8 @@ class RemoteFile : Parcelable, Serializable {
153157
lockTimeout = 0
154158
lockToken = null
155159
tags = null
160+
hidden = false
161+
livePhoto = null
156162
}
157163

158164
/**
@@ -191,6 +197,8 @@ class RemoteFile : Parcelable, Serializable {
191197
lockTimestamp = source.readLong()
192198
lockTimeout = source.readLong()
193199
lockToken = source.readString()
200+
livePhoto = source.readString()
201+
hidden = source.readInt() == 1
194202
}
195203

196204
override fun describeContents(): Int {
@@ -227,6 +235,8 @@ class RemoteFile : Parcelable, Serializable {
227235
dest.writeLong(lockTimestamp)
228236
dest.writeLong(lockTimeout)
229237
dest.writeString(lockToken)
238+
dest.writeString(livePhoto)
239+
dest.writeInt(if (hidden) 1 else 0)
230240
}
231241

232242
companion object {

library/src/main/java/com/owncloud/android/lib/resources/status/NextcloudVersion.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ class NextcloudVersion : OwnCloudVersion {
4444

4545
@JvmField
4646
val nextcloud_27 = NextcloudVersion(0x1B000000) // 27.0
47+
48+
@JvmField
49+
val nextcloud_28 = NextcloudVersion(0x1C000000) // 28.0
4750
}
4851

4952
constructor(string: String) : super(string)

0 commit comments

Comments
 (0)