forked from GitHub-Mirror/riotX-android
Send media: first working implementation. Then, need to fix local echo and handle other types than image.
This commit is contained in:
parent
18591d0287
commit
c47eeb9cec
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.matrix.android.api.session.content
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class ContentAttachmentData(
|
||||||
|
val size: Long = 0,
|
||||||
|
val duration: Long = 0,
|
||||||
|
val date: Long = 0,
|
||||||
|
val height: Long = 0,
|
||||||
|
val width: Long = 0,
|
||||||
|
val name: String? = null,
|
||||||
|
val path: String? = null,
|
||||||
|
val mimeType: String? = null
|
||||||
|
) : Parcelable
|
@ -19,7 +19,7 @@ package im.vector.matrix.android.api.session.room.send
|
|||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
import im.vector.matrix.android.internal.session.room.media.MediaAttachment
|
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface defines methods to send events in a room. It's implemented at the room level.
|
* This interface defines methods to send events in a room. It's implemented at the room level.
|
||||||
@ -34,6 +34,6 @@ interface SendService {
|
|||||||
*/
|
*/
|
||||||
fun sendTextMessage(text: String, callback: MatrixCallback<Event>): Cancelable
|
fun sendTextMessage(text: String, callback: MatrixCallback<Event>): Cancelable
|
||||||
|
|
||||||
fun sendMedia(attachment: MediaAttachment, callback: MatrixCallback<Event>): Cancelable
|
fun sendMedia(attachment: ContentAttachmentData, callback: MatrixCallback<Event>): Cancelable
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.matrix.android.internal.session.content
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class ContentUploadResponse(
|
||||||
|
@Json(name = "content_uri") val contentUri: String
|
||||||
|
)
|
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.matrix.android.internal.session.content
|
||||||
|
|
||||||
|
import arrow.core.Try
|
||||||
|
import arrow.core.Try.Companion.raise
|
||||||
|
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||||
|
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||||
|
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||||
|
import okhttp3.HttpUrl
|
||||||
|
import okhttp3.MediaType
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
|
||||||
|
internal class ContentUploader(private val okHttpClient: OkHttpClient,
|
||||||
|
private val sessionParams: SessionParams) {
|
||||||
|
|
||||||
|
private val moshi = MoshiProvider.providesMoshi()
|
||||||
|
private val responseAdapter = moshi.adapter(ContentUploadResponse::class.java)
|
||||||
|
|
||||||
|
fun uploadFile(attachment: ContentAttachmentData): Try<ContentUploadResponse> {
|
||||||
|
if (attachment.path == null || attachment.mimeType == null) {
|
||||||
|
return raise(RuntimeException())
|
||||||
|
}
|
||||||
|
val file = File(attachment.path)
|
||||||
|
val urlString = sessionParams.homeServerConnectionConfig.homeServerUri.toString() + URI_PREFIX_CONTENT_API + "upload"
|
||||||
|
|
||||||
|
val urlBuilder = HttpUrl.parse(urlString)?.newBuilder()
|
||||||
|
?: return raise(RuntimeException())
|
||||||
|
|
||||||
|
val httpUrl = urlBuilder
|
||||||
|
.addQueryParameter(
|
||||||
|
"filename", attachment.name
|
||||||
|
).build()
|
||||||
|
|
||||||
|
val requestBody = RequestBody.create(
|
||||||
|
MediaType.parse(attachment.mimeType),
|
||||||
|
file
|
||||||
|
)
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(httpUrl)
|
||||||
|
.post(requestBody)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return Try {
|
||||||
|
okHttpClient.newCall(request).execute().use { response ->
|
||||||
|
if (!response.isSuccessful) {
|
||||||
|
throw IOException()
|
||||||
|
} else {
|
||||||
|
response.body()?.source()?.let {
|
||||||
|
responseAdapter.fromJson(it)
|
||||||
|
}
|
||||||
|
?: throw IOException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.matrix.android.internal.session.content
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.Worker
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
|
import im.vector.matrix.android.api.session.events.model.toContent
|
||||||
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
||||||
|
import im.vector.matrix.android.internal.di.MatrixKoinComponent
|
||||||
|
import im.vector.matrix.android.internal.session.room.send.SendEventWorker
|
||||||
|
import im.vector.matrix.android.internal.util.WorkerParamsFactory
|
||||||
|
import org.koin.standalone.inject
|
||||||
|
|
||||||
|
internal class UploadContentWorker(context: Context, params: WorkerParameters)
|
||||||
|
: Worker(context, params), MatrixKoinComponent {
|
||||||
|
|
||||||
|
private val mediaUploader by inject<ContentUploader>()
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
internal data class Params(
|
||||||
|
val roomId: String,
|
||||||
|
val event: Event,
|
||||||
|
val attachment: ContentAttachmentData
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun doWork(): Result {
|
||||||
|
val params = WorkerParamsFactory.fromData<Params>(inputData)
|
||||||
|
?: return Result.failure()
|
||||||
|
|
||||||
|
return mediaUploader
|
||||||
|
.uploadFile(params.attachment)
|
||||||
|
.fold({ handleFailure() }, { handleSuccess(params, it) })
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleFailure(): Result {
|
||||||
|
return Result.retry()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSuccess(params: Params, contentUploadResponse: ContentUploadResponse): Result {
|
||||||
|
val event = updateEvent(params.event, contentUploadResponse.contentUri)
|
||||||
|
val sendParams = SendEventWorker.Params(params.roomId, event)
|
||||||
|
return Result.success(WorkerParamsFactory.toData(sendParams))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateEvent(event: Event, url: String): Event {
|
||||||
|
val messageContent: MessageContent = event.content.toModel() ?: return event
|
||||||
|
val updatedContent = when (messageContent) {
|
||||||
|
is MessageImageContent -> messageContent.update(url)
|
||||||
|
else -> messageContent
|
||||||
|
}
|
||||||
|
return event.copy(content = updatedContent.toContent())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MessageImageContent.update(url: String): MessageImageContent {
|
||||||
|
return copy(url = url)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,6 @@ import androidx.work.OneTimeWorkRequestBuilder
|
|||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
|
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
|
||||||
import im.vector.matrix.android.internal.database.model.GroupEntity
|
import im.vector.matrix.android.internal.database.model.GroupEntity
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.util.WorkerParamsFactory
|
import im.vector.matrix.android.internal.util.WorkerParamsFactory
|
||||||
|
@ -23,7 +23,7 @@ import im.vector.matrix.android.internal.session.room.members.RoomMemberExtracto
|
|||||||
import im.vector.matrix.android.internal.session.room.read.DefaultReadService
|
import im.vector.matrix.android.internal.session.room.read.DefaultReadService
|
||||||
import im.vector.matrix.android.internal.session.room.read.SetReadMarkersTask
|
import im.vector.matrix.android.internal.session.room.read.SetReadMarkersTask
|
||||||
import im.vector.matrix.android.internal.session.room.send.DefaultSendService
|
import im.vector.matrix.android.internal.session.room.send.DefaultSendService
|
||||||
import im.vector.matrix.android.internal.session.room.send.EventFactory
|
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineService
|
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineService
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask
|
import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationTask
|
import im.vector.matrix.android.internal.session.room.timeline.PaginationTask
|
||||||
@ -35,7 +35,7 @@ internal class RoomFactory(private val loadRoomMembersTask: LoadRoomMembersTask,
|
|||||||
private val paginationTask: PaginationTask,
|
private val paginationTask: PaginationTask,
|
||||||
private val contextOfEventTask: GetContextOfEventTask,
|
private val contextOfEventTask: GetContextOfEventTask,
|
||||||
private val setReadMarkersTask: SetReadMarkersTask,
|
private val setReadMarkersTask: SetReadMarkersTask,
|
||||||
private val eventFactory: EventFactory,
|
private val eventFactory: LocalEchoEventFactory,
|
||||||
private val taskExecutor: TaskExecutor) {
|
private val taskExecutor: TaskExecutor) {
|
||||||
|
|
||||||
fun instantiate(roomId: String): Room {
|
fun instantiate(roomId: String): Room {
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
package im.vector.matrix.android.internal.session.room
|
package im.vector.matrix.android.internal.session.room
|
||||||
|
|
||||||
import im.vector.matrix.android.internal.session.DefaultSession
|
import im.vector.matrix.android.internal.session.DefaultSession
|
||||||
import im.vector.matrix.android.internal.session.room.media.MediaUploader
|
import im.vector.matrix.android.internal.session.content.ContentUploader
|
||||||
import im.vector.matrix.android.internal.session.room.members.DefaultLoadRoomMembersTask
|
import im.vector.matrix.android.internal.session.room.members.DefaultLoadRoomMembersTask
|
||||||
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask
|
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask
|
||||||
import im.vector.matrix.android.internal.session.room.read.DefaultSetReadMarkersTask
|
import im.vector.matrix.android.internal.session.room.read.DefaultSetReadMarkersTask
|
||||||
import im.vector.matrix.android.internal.session.room.read.SetReadMarkersTask
|
import im.vector.matrix.android.internal.session.room.read.SetReadMarkersTask
|
||||||
import im.vector.matrix.android.internal.session.room.send.EventFactory
|
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.*
|
import im.vector.matrix.android.internal.session.room.timeline.*
|
||||||
import org.koin.dsl.module.module
|
import org.koin.dsl.module.module
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
@ -58,11 +58,11 @@ class RoomModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
EventFactory(get())
|
LocalEchoEventFactory(get())
|
||||||
}
|
}
|
||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
MediaUploader(get(), get())
|
ContentUploader(get(), get())
|
||||||
}
|
}
|
||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
package im.vector.matrix.android.internal.session.room.media
|
package im.vector.matrix.android.internal.session.room.media
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
|
||||||
@ -30,7 +29,6 @@ data class MediaAttachment(
|
|||||||
val height: Long = 0,
|
val height: Long = 0,
|
||||||
val width: Long = 0,
|
val width: Long = 0,
|
||||||
val name: String? = null,
|
val name: String? = null,
|
||||||
val thumbnail: Uri? = null,
|
|
||||||
val path: String? = null,
|
val path: String? = null,
|
||||||
val mimeType: String? = null
|
val mimeType: String? = null
|
||||||
) : Parcelable
|
) : Parcelable
|
@ -20,11 +20,13 @@ package im.vector.matrix.android.internal.session.room.media
|
|||||||
|
|
||||||
import arrow.core.Try
|
import arrow.core.Try
|
||||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||||
|
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||||
import im.vector.matrix.android.internal.session.content.URI_PREFIX_CONTENT_API
|
import im.vector.matrix.android.internal.session.content.URI_PREFIX_CONTENT_API
|
||||||
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.MediaType
|
import okhttp3.MediaType
|
||||||
|
import okhttp3.MultipartBody
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
@ -32,21 +34,28 @@ import java.io.IOException
|
|||||||
internal class MediaUploader(private val okHttpClient: OkHttpClient,
|
internal class MediaUploader(private val okHttpClient: OkHttpClient,
|
||||||
private val sessionParams: SessionParams) {
|
private val sessionParams: SessionParams) {
|
||||||
|
|
||||||
fun uploadFile(attachment: MediaAttachment): Try<String> {
|
fun uploadFile(attachment: ContentAttachmentData): Try<String> {
|
||||||
if (attachment.path == null || attachment.mimeType == null) {
|
if (attachment.path == null || attachment.mimeType == null) {
|
||||||
return Try.raise(RuntimeException())
|
return Try.raise(RuntimeException())
|
||||||
}
|
}
|
||||||
val urlString = sessionParams.homeServerConnectionConfig.homeServerUri.toString() + URI_PREFIX_CONTENT_API + "upload"
|
|
||||||
val file = File(attachment.path)
|
val file = File(attachment.path)
|
||||||
|
val urlString = sessionParams.homeServerConnectionConfig.homeServerUri.toString() + URI_PREFIX_CONTENT_API + "upload"
|
||||||
|
|
||||||
// create RequestBody instance from file
|
val urlBuilder = HttpUrl.parse(urlString)?.newBuilder()
|
||||||
val requestFile = RequestBody.create(
|
?: return Try.raise(RuntimeException())
|
||||||
|
|
||||||
|
val httpUrl = urlBuilder
|
||||||
|
.addQueryParameter(
|
||||||
|
"filename", attachment.name
|
||||||
|
).build()
|
||||||
|
|
||||||
|
val requestBody = MultipartBody.create(
|
||||||
MediaType.parse(attachment.mimeType),
|
MediaType.parse(attachment.mimeType),
|
||||||
file
|
file
|
||||||
)
|
)
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(urlString)
|
.url(httpUrl)
|
||||||
.post(requestFile)
|
.post(requestBody)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return okHttpClient.newCall(request).execute().use { response ->
|
return okHttpClient.newCall(request).execute().use { response ->
|
||||||
|
@ -23,17 +23,19 @@ import androidx.work.Worker
|
|||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import im.vector.matrix.android.internal.di.MatrixKoinComponent
|
import im.vector.matrix.android.internal.di.MatrixKoinComponent
|
||||||
|
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||||
|
import im.vector.matrix.android.internal.session.content.ContentUploader
|
||||||
import im.vector.matrix.android.internal.util.WorkerParamsFactory
|
import im.vector.matrix.android.internal.util.WorkerParamsFactory
|
||||||
import org.koin.standalone.inject
|
import org.koin.standalone.inject
|
||||||
|
|
||||||
internal class UploadMediaWorker(context: Context, params: WorkerParameters)
|
internal class UploadMediaWorker(context: Context, params: WorkerParameters)
|
||||||
: Worker(context, params), MatrixKoinComponent {
|
: Worker(context, params), MatrixKoinComponent {
|
||||||
|
|
||||||
private val mediaUploader by inject<MediaUploader>()
|
private val mediaUploader by inject<ContentUploader>()
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class Params(
|
internal data class Params(
|
||||||
val attachment: MediaAttachment
|
val attachment: ContentAttachmentData
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
|
@ -35,7 +35,9 @@ internal class EventsPruner(monarchy: Monarchy) :
|
|||||||
override val query = Monarchy.Query<EventEntity> { EventEntity.where(it, type = EventType.REDACTION) }
|
override val query = Monarchy.Query<EventEntity> { EventEntity.where(it, type = EventType.REDACTION) }
|
||||||
|
|
||||||
override fun processChanges(inserted: List<EventEntity>, updated: List<EventEntity>, deleted: List<EventEntity>) {
|
override fun processChanges(inserted: List<EventEntity>, updated: List<EventEntity>, deleted: List<EventEntity>) {
|
||||||
val redactionEvents = inserted.map { it.asDomain() }
|
val redactionEvents = inserted
|
||||||
|
.mapNotNull { it.asDomain().redacts }
|
||||||
|
|
||||||
val pruneEventWorkerParams = PruneEventWorker.Params(redactionEvents)
|
val pruneEventWorkerParams = PruneEventWorker.Params(redactionEvents)
|
||||||
val workData = WorkerParamsFactory.toData(pruneEventWorkerParams)
|
val workData = WorkerParamsFactory.toData(pruneEventWorkerParams)
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ import androidx.work.Worker
|
|||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.internal.database.mapper.ContentMapper
|
import im.vector.matrix.android.internal.database.mapper.ContentMapper
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||||
@ -37,8 +36,8 @@ internal class PruneEventWorker(context: Context,
|
|||||||
) : Worker(context, workerParameters), MatrixKoinComponent {
|
) : Worker(context, workerParameters), MatrixKoinComponent {
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class Params(
|
internal class Params(
|
||||||
val redactionEvents: List<Event>
|
val eventIdsToRedact: List<String>
|
||||||
)
|
)
|
||||||
|
|
||||||
private val monarchy by inject<Monarchy>()
|
private val monarchy by inject<Monarchy>()
|
||||||
@ -48,18 +47,19 @@ internal class PruneEventWorker(context: Context,
|
|||||||
?: return Result.failure()
|
?: return Result.failure()
|
||||||
|
|
||||||
val result = monarchy.tryTransactionSync { realm ->
|
val result = monarchy.tryTransactionSync { realm ->
|
||||||
params.redactionEvents.forEach { event ->
|
params.eventIdsToRedact.forEach { eventId ->
|
||||||
pruneEvent(realm, event)
|
pruneEvent(realm, eventId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result.fold({ Result.retry() }, { Result.success() })
|
return result.fold({ Result.retry() }, { Result.success() })
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pruneEvent(realm: Realm, redactionEvent: Event?) {
|
private fun pruneEvent(realm: Realm, eventIdToRedact: String) {
|
||||||
if (redactionEvent == null || redactionEvent.redacts.isNullOrEmpty()) {
|
if (eventIdToRedact.isEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val eventToPrune = EventEntity.where(realm, eventId = redactionEvent.redacts).findFirst()
|
|
||||||
|
val eventToPrune = EventEntity.where(realm, eventId = eventIdToRedact).findFirst()
|
||||||
?: return
|
?: return
|
||||||
|
|
||||||
val allowedKeys = computeAllowedKeys(eventToPrune.type)
|
val allowedKeys = computeAllowedKeys(eventToPrune.type)
|
||||||
|
@ -16,17 +16,23 @@
|
|||||||
|
|
||||||
package im.vector.matrix.android.internal.session.room.send
|
package im.vector.matrix.android.internal.session.room.send
|
||||||
|
|
||||||
import androidx.work.*
|
import androidx.work.BackoffPolicy
|
||||||
|
import androidx.work.Constraints
|
||||||
|
import androidx.work.ExistingWorkPolicy
|
||||||
|
import androidx.work.NetworkType
|
||||||
|
import androidx.work.OneTimeWorkRequest
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
import com.zhuinden.monarchy.Monarchy
|
import com.zhuinden.monarchy.Monarchy
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.room.send.SendService
|
import im.vector.matrix.android.api.session.room.send.SendService
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
import im.vector.matrix.android.internal.database.helper.add
|
import im.vector.matrix.android.internal.database.helper.add
|
||||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||||
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
||||||
import im.vector.matrix.android.internal.session.room.media.MediaAttachment
|
import im.vector.matrix.android.internal.session.content.UploadContentWorker
|
||||||
import im.vector.matrix.android.internal.session.room.media.UploadMediaWorker
|
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
|
||||||
import im.vector.matrix.android.internal.util.CancelableWork
|
import im.vector.matrix.android.internal.util.CancelableWork
|
||||||
import im.vector.matrix.android.internal.util.WorkerParamsFactory
|
import im.vector.matrix.android.internal.util.WorkerParamsFactory
|
||||||
@ -35,18 +41,19 @@ import java.util.concurrent.TimeUnit
|
|||||||
|
|
||||||
private const val SEND_WORK = "SEND_WORK"
|
private const val SEND_WORK = "SEND_WORK"
|
||||||
private const val BACKOFF_DELAY = 10_000L
|
private const val BACKOFF_DELAY = 10_000L
|
||||||
|
|
||||||
private val WORK_CONSTRAINTS = Constraints.Builder()
|
private val WORK_CONSTRAINTS = Constraints.Builder()
|
||||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
internal class DefaultSendService(private val roomId: String,
|
internal class DefaultSendService(private val roomId: String,
|
||||||
private val eventFactory: EventFactory,
|
private val eventFactory: LocalEchoEventFactory,
|
||||||
private val monarchy: Monarchy) : SendService {
|
private val monarchy: Monarchy) : SendService {
|
||||||
|
|
||||||
|
|
||||||
override fun sendTextMessage(text: String, callback: MatrixCallback<Event>): Cancelable {
|
override fun sendTextMessage(text: String, callback: MatrixCallback<Event>): Cancelable {
|
||||||
val event = eventFactory.createTextEvent(roomId, text)
|
val event = eventFactory.createTextEvent(roomId, text)
|
||||||
saveLiveEvent(event)
|
saveLocalEcho(event)
|
||||||
val sendWork = createSendEventWork(event)
|
val sendWork = createSendEventWork(event)
|
||||||
WorkManager.getInstance()
|
WorkManager.getInstance()
|
||||||
.beginUniqueWork(SEND_WORK, ExistingWorkPolicy.APPEND, sendWork)
|
.beginUniqueWork(SEND_WORK, ExistingWorkPolicy.APPEND, sendWork)
|
||||||
@ -55,12 +62,12 @@ internal class DefaultSendService(private val roomId: String,
|
|||||||
return CancelableWork(sendWork.id)
|
return CancelableWork(sendWork.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendMedia(attachment: MediaAttachment, callback: MatrixCallback<Event>): Cancelable {
|
override fun sendMedia(attachment: ContentAttachmentData, callback: MatrixCallback<Event>): Cancelable {
|
||||||
// Create an event with the media file path
|
// Create an event with the media file path
|
||||||
val event = eventFactory.createImageEvent(roomId, attachment)
|
val event = eventFactory.createMediaEvent(roomId, attachment).also {
|
||||||
saveLiveEvent(event)
|
saveLocalEcho(it)
|
||||||
|
}
|
||||||
val uploadWork = createUploadMediaWork(attachment)
|
val uploadWork = createUploadMediaWork(event, attachment)
|
||||||
val sendWork = createSendEventWork(event)
|
val sendWork = createSendEventWork(event)
|
||||||
|
|
||||||
WorkManager.getInstance()
|
WorkManager.getInstance()
|
||||||
@ -70,7 +77,7 @@ internal class DefaultSendService(private val roomId: String,
|
|||||||
return CancelableWork(sendWork.id)
|
return CancelableWork(sendWork.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveLiveEvent(event: Event) {
|
private fun saveLocalEcho(event: Event) {
|
||||||
monarchy.tryTransactionAsync { realm ->
|
monarchy.tryTransactionAsync { realm ->
|
||||||
val chunkEntity = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
|
val chunkEntity = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
|
||||||
?: return@tryTransactionAsync
|
?: return@tryTransactionAsync
|
||||||
@ -89,11 +96,11 @@ internal class DefaultSendService(private val roomId: String,
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createUploadMediaWork(attachment: MediaAttachment): OneTimeWorkRequest {
|
private fun createUploadMediaWork(event: Event, attachment: ContentAttachmentData): OneTimeWorkRequest {
|
||||||
val uploadMediaWorkerParams = UploadMediaWorker.Params(attachment)
|
val uploadMediaWorkerParams = UploadContentWorker.Params(roomId, event, attachment)
|
||||||
val uploadWorkData = WorkerParamsFactory.toData(uploadMediaWorkerParams)
|
val uploadWorkData = WorkerParamsFactory.toData(uploadMediaWorkerParams)
|
||||||
|
|
||||||
return OneTimeWorkRequestBuilder<UploadMediaWorker>()
|
return OneTimeWorkRequestBuilder<UploadContentWorker>()
|
||||||
.setConstraints(WORK_CONSTRAINTS)
|
.setConstraints(WORK_CONSTRAINTS)
|
||||||
.setInputData(uploadWorkData)
|
.setInputData(uploadWorkData)
|
||||||
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS)
|
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS)
|
||||||
|
@ -17,38 +17,38 @@
|
|||||||
package im.vector.matrix.android.internal.session.room.send
|
package im.vector.matrix.android.internal.session.room.send
|
||||||
|
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
import im.vector.matrix.android.api.auth.data.Credentials
|
||||||
|
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.events.model.toContent
|
import im.vector.matrix.android.api.session.events.model.toContent
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.room.model.message.ImageInfo
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageType
|
import im.vector.matrix.android.api.session.room.model.message.MessageType
|
||||||
import im.vector.matrix.android.internal.session.room.media.MediaAttachment
|
|
||||||
|
|
||||||
internal class EventFactory(private val credentials: Credentials) {
|
internal class LocalEchoEventFactory(private val credentials: Credentials) {
|
||||||
|
|
||||||
fun createTextEvent(roomId: String, text: String): Event {
|
fun createTextEvent(roomId: String, text: String): Event {
|
||||||
val content = MessageTextContent(type = MessageType.MSGTYPE_TEXT, body = text)
|
val content = MessageTextContent(type = MessageType.MSGTYPE_TEXT, body = text)
|
||||||
return createEvent(roomId, content)
|
return createEvent(roomId, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createImageEvent(roomId: String, attachment: MediaAttachment): Event {
|
fun createMediaEvent(roomId: String, attachment: ContentAttachmentData): Event {
|
||||||
val content = MessageImageContent(
|
val content = MessageImageContent(
|
||||||
type = MessageType.MSGTYPE_IMAGE,
|
type = MessageType.MSGTYPE_IMAGE,
|
||||||
body = attachment.name ?: "image",
|
body = attachment.name ?: "image",
|
||||||
|
info = ImageInfo(
|
||||||
|
mimeType = attachment.mimeType ?: "image/png",
|
||||||
|
width = attachment.width.toInt(),
|
||||||
|
height = attachment.height.toInt(),
|
||||||
|
size = attachment.size.toInt()
|
||||||
|
),
|
||||||
url = attachment.path
|
url = attachment.path
|
||||||
)
|
)
|
||||||
return createEvent(roomId, content)
|
return createEvent(roomId, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateImageEvent(event: Event, url: String): Event {
|
private fun createEvent(roomId: String, content: Any? = null): Event {
|
||||||
val imageContent = event.content.toModel<MessageImageContent>() ?: return event
|
|
||||||
val updatedContent = imageContent.copy(url = url)
|
|
||||||
return event.copy(content = updatedContent.toContent())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createEvent(roomId: String, content: Any? = null): Event {
|
|
||||||
return Event(
|
return Event(
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
originServerTs = dummyOriginServerTs(),
|
originServerTs = dummyOriginServerTs(),
|
@ -49,16 +49,17 @@ internal class SendEventWorker(context: Context, params: WorkerParameters)
|
|||||||
val params = WorkerParamsFactory.fromData<Params>(inputData)
|
val params = WorkerParamsFactory.fromData<Params>(inputData)
|
||||||
?: return Result.failure()
|
?: return Result.failure()
|
||||||
|
|
||||||
if (params.event.eventId == null) {
|
val event = params.event
|
||||||
|
if (event.eventId == null) {
|
||||||
return Result.failure()
|
return Result.failure()
|
||||||
}
|
}
|
||||||
|
|
||||||
val result = executeRequest<SendResponse> {
|
val result = executeRequest<SendResponse> {
|
||||||
apiCall = roomAPI.send(
|
apiCall = roomAPI.send(
|
||||||
params.event.eventId,
|
event.eventId,
|
||||||
params.roomId,
|
params.roomId,
|
||||||
params.event.type,
|
event.type,
|
||||||
params.event.content
|
event.content
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
result.flatMap { sendResponse ->
|
result.flatMap { sendResponse ->
|
||||||
@ -69,6 +70,4 @@ internal class SendEventWorker(context: Context, params: WorkerParameters)
|
|||||||
}
|
}
|
||||||
return result.fold({ Result.retry() }, { Result.success() })
|
return result.fold({ Result.retry() }, { Result.success() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import com.jakewharton.rxrelay2.BehaviorRelay
|
|||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.internal.session.room.media.MediaAttachment
|
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||||
import im.vector.matrix.rx.rx
|
import im.vector.matrix.rx.rx
|
||||||
import im.vector.riotredesign.core.platform.RiotViewModel
|
import im.vector.riotredesign.core.platform.RiotViewModel
|
||||||
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
||||||
@ -81,14 +81,13 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
|||||||
private fun handleSendMedia(action: RoomDetailActions.SendMedia) {
|
private fun handleSendMedia(action: RoomDetailActions.SendMedia) {
|
||||||
val attachment = action.mediaFiles.firstOrNull()
|
val attachment = action.mediaFiles.firstOrNull()
|
||||||
?.let {
|
?.let {
|
||||||
MediaAttachment(
|
ContentAttachmentData(
|
||||||
it.size,
|
it.size,
|
||||||
it.duration,
|
it.duration,
|
||||||
it.date,
|
it.date,
|
||||||
it.height,
|
it.height,
|
||||||
it.width,
|
it.width,
|
||||||
it.name,
|
it.name,
|
||||||
it.thumbnail,
|
|
||||||
it.path,
|
it.path,
|
||||||
it.mimeType
|
it.mimeType
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user