forked from GitHub-Mirror/riotX-android
Send messages : add local echo. Maybe add directly to the pagedlist if possible
This commit is contained in:
parent
e4c23b757e
commit
660ba5436b
@ -8,7 +8,9 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import im.vector.matrix.android.api.Matrix
|
import im.vector.matrix.android.api.Matrix
|
||||||
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.room.Room
|
import im.vector.matrix.android.api.session.room.Room
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
@ -58,7 +60,9 @@ class RoomDetailFragment : RiotFragment() {
|
|||||||
val textMessage = composerEditText.text.toString()
|
val textMessage = composerEditText.text.toString()
|
||||||
if (textMessage.isNotBlank()) {
|
if (textMessage.isNotBlank()) {
|
||||||
composerEditText.text = null
|
composerEditText.text = null
|
||||||
room.sendTextMessage(textMessage)
|
room.sendTextMessage(textMessage, object : MatrixCallback<Event> {
|
||||||
|
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ class TimelineEventController(private val roomId: String,
|
|||||||
|
|
||||||
val item = when (event.root.type) {
|
val item = when (event.root.type) {
|
||||||
EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, addDaySeparator, date)
|
EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, addDaySeparator, date)
|
||||||
else -> textItemFactory.create(event)
|
else -> textItemFactory.create(event)
|
||||||
}
|
}
|
||||||
item
|
item
|
||||||
?.onBind { timeline?.loadAround(index) }
|
?.onBind { timeline?.loadAround(index) }
|
||||||
|
@ -6,7 +6,7 @@ import com.squareup.moshi.Types
|
|||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||||
import java.lang.reflect.ParameterizedType
|
import java.lang.reflect.ParameterizedType
|
||||||
|
|
||||||
typealias Content = Map<String, Any>
|
typealias Content = Map<String, @JvmSuppressWildcards Any>
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class Event(
|
data class Event(
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package im.vector.matrix.android.api.session.room
|
package im.vector.matrix.android.api.session.room
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
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
|
||||||
|
|
||||||
interface SendService {
|
interface SendService {
|
||||||
|
|
||||||
fun sendTextMessage(text: String): Cancelable
|
fun sendTextMessage(text: String, callback: MatrixCallback<Event>): Cancelable
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package im.vector.matrix.android.api.session.room.send
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.auth.data.Credentials
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Content
|
||||||
|
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.room.model.MessageContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.MessageType
|
||||||
|
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||||
|
|
||||||
|
internal class EventFactory(private val credentials: Credentials) {
|
||||||
|
|
||||||
|
private val moshi = MoshiProvider.providesMoshi()
|
||||||
|
|
||||||
|
fun createTextEvent(roomId: String, text: String): Event {
|
||||||
|
val content = MessageContent(type = MessageType.MSGTYPE_TEXT, body = text)
|
||||||
|
|
||||||
|
return Event(
|
||||||
|
roomId = roomId,
|
||||||
|
originServerTs = dummyOriginServerTs(),
|
||||||
|
sender = credentials.userId,
|
||||||
|
eventId = dummyEventId(roomId),
|
||||||
|
type = EventType.MESSAGE,
|
||||||
|
content = toContent(content)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dummyOriginServerTs(): Long {
|
||||||
|
return System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dummyEventId(roomId: String): String {
|
||||||
|
return roomId + "-" + dummyOriginServerTs()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private inline fun <reified T> toContent(data: T?): Content? {
|
||||||
|
val moshiAdapter = moshi.adapter(T::class.java)
|
||||||
|
val jsonValue = moshiAdapter.toJsonValue(data)
|
||||||
|
return jsonValue as? Content?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -35,6 +35,10 @@ internal fun ChunkEntity.addAll(events: List<Event>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun ChunkEntity.updateDisplayIndexes() {
|
||||||
|
events.forEachIndexed { index, eventEntity -> eventEntity.displayIndex = index }
|
||||||
|
}
|
||||||
|
|
||||||
internal fun ChunkEntity.addOrUpdate(event: Event,
|
internal fun ChunkEntity.addOrUpdate(event: Event,
|
||||||
direction: PaginationDirection,
|
direction: PaginationDirection,
|
||||||
stateIndexOffset: Int = 0) {
|
stateIndexOffset: Int = 0) {
|
||||||
@ -69,7 +73,7 @@ internal fun ChunkEntity.addOrUpdate(event: Event,
|
|||||||
|
|
||||||
internal fun ChunkEntity.lastStateIndex(direction: PaginationDirection, defaultValue: Int = 0): Int {
|
internal fun ChunkEntity.lastStateIndex(direction: PaginationDirection, defaultValue: Int = 0): Int {
|
||||||
return when (direction) {
|
return when (direction) {
|
||||||
PaginationDirection.FORWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.DESCENDING).findFirst()?.stateIndex
|
PaginationDirection.FORWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.DESCENDING).findFirst()?.stateIndex
|
||||||
PaginationDirection.BACKWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.ASCENDING).findFirst()?.stateIndex
|
PaginationDirection.BACKWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.ASCENDING).findFirst()?.stateIndex
|
||||||
} ?: defaultValue
|
} ?: defaultValue
|
||||||
}
|
}
|
@ -13,7 +13,7 @@ internal fun RoomEntity.deleteOnCascade(chunkEntity: ChunkEntity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun RoomEntity.addOrUpdate(chunkEntity: ChunkEntity) {
|
internal fun RoomEntity.addOrUpdate(chunkEntity: ChunkEntity) {
|
||||||
chunkEntity.events.forEachIndexed { index, eventEntity -> eventEntity.displayIndex = index }
|
chunkEntity.updateDisplayIndexes()
|
||||||
if (!chunks.contains(chunkEntity)) {
|
if (!chunks.contains(chunkEntity)) {
|
||||||
chunks.add(chunkEntity)
|
chunks.add(chunkEntity)
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,10 @@ internal class SessionModule(private val sessionParams: SessionParams) : Module
|
|||||||
|
|
||||||
override fun invoke(): ModuleDefinition = module(override = true) {
|
override fun invoke(): ModuleDefinition = module(override = true) {
|
||||||
|
|
||||||
|
scope(DefaultSession.SCOPE) {
|
||||||
|
sessionParams
|
||||||
|
}
|
||||||
|
|
||||||
scope(DefaultSession.SCOPE) {
|
scope(DefaultSession.SCOPE) {
|
||||||
RealmConfiguration.Builder()
|
RealmConfiguration.Builder()
|
||||||
.name(sessionParams.credentials.userId)
|
.name(sessionParams.credentials.userId)
|
||||||
|
@ -6,6 +6,7 @@ import android.arch.paging.PagedList
|
|||||||
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.events.model.EnrichedEvent
|
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.room.Room
|
import im.vector.matrix.android.api.session.room.Room
|
||||||
import im.vector.matrix.android.api.session.room.SendService
|
import im.vector.matrix.android.api.session.room.SendService
|
||||||
import im.vector.matrix.android.api.session.room.TimelineHolder
|
import im.vector.matrix.android.api.session.room.TimelineHolder
|
||||||
@ -61,14 +62,14 @@ internal data class DefaultRoom(
|
|||||||
|
|
||||||
private fun areAllMembersLoaded(): Boolean {
|
private fun areAllMembersLoaded(): Boolean {
|
||||||
return monarchy
|
return monarchy
|
||||||
.fetchAllCopiedSync { RoomEntity.where(it, roomId) }
|
.fetchAllCopiedSync { RoomEntity.where(it, roomId) }
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
?.areAllMembersLoaded ?: false
|
?.areAllMembersLoaded ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun sendTextMessage(text: String): Cancelable {
|
override fun sendTextMessage(text: String, callback: MatrixCallback<Event>): Cancelable {
|
||||||
return sendService.sendTextMessage(text)
|
return sendService.sendTextMessage(text, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package im.vector.matrix.android.internal.session.room
|
package im.vector.matrix.android.internal.session.room
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Content
|
||||||
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.model.MessageContent
|
import im.vector.matrix.android.api.session.room.model.MessageContent
|
||||||
import im.vector.matrix.android.internal.network.NetworkConstants
|
import im.vector.matrix.android.internal.network.NetworkConstants
|
||||||
@ -62,7 +63,7 @@ internal interface RoomAPI {
|
|||||||
fun send(@Path("txId") txId: String,
|
fun send(@Path("txId") txId: String,
|
||||||
@Path("roomId") roomId: String,
|
@Path("roomId") roomId: String,
|
||||||
@Path("eventType") eventType: String,
|
@Path("eventType") eventType: String,
|
||||||
@Body content: MessageContent
|
@Body content: Content?
|
||||||
): Call<SendResponse>
|
): Call<SendResponse>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package im.vector.matrix.android.internal.session.room
|
package im.vector.matrix.android.internal.session.room
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||||
import im.vector.matrix.android.api.session.room.SendService
|
import im.vector.matrix.android.api.session.room.SendService
|
||||||
import im.vector.matrix.android.api.session.room.TimelineHolder
|
import im.vector.matrix.android.api.session.room.TimelineHolder
|
||||||
|
import im.vector.matrix.android.api.session.room.send.EventFactory
|
||||||
import im.vector.matrix.android.internal.session.DefaultSession
|
import im.vector.matrix.android.internal.session.DefaultSession
|
||||||
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersRequest
|
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersRequest
|
||||||
import im.vector.matrix.android.internal.session.room.send.DefaultSendService
|
import im.vector.matrix.android.internal.session.room.send.DefaultSendService
|
||||||
@ -39,9 +41,14 @@ class RoomModule : Module {
|
|||||||
DefaultTimelineHolder(roomId, get(), timelineBoundaryCallback) as TimelineHolder
|
DefaultTimelineHolder(roomId, get(), timelineBoundaryCallback) as TimelineHolder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope(DefaultSession.SCOPE) {
|
||||||
|
val sessionParams = get<SessionParams>()
|
||||||
|
EventFactory(sessionParams.credentials)
|
||||||
|
}
|
||||||
|
|
||||||
factory {
|
factory {
|
||||||
val roomId: String = it[0]
|
val roomId: String = it[0]
|
||||||
DefaultSendService(roomId) as SendService
|
DefaultSendService(roomId, get(), get()) as SendService
|
||||||
}
|
}
|
||||||
|
|
||||||
}.invoke()
|
}.invoke()
|
||||||
|
@ -1,23 +1,43 @@
|
|||||||
package im.vector.matrix.android.internal.session.room.send
|
package im.vector.matrix.android.internal.session.room.send
|
||||||
|
|
||||||
import androidx.work.*
|
import androidx.work.*
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.room.SendService
|
import im.vector.matrix.android.api.session.room.SendService
|
||||||
|
import im.vector.matrix.android.api.session.room.send.EventFactory
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
|
import im.vector.matrix.android.internal.database.helper.addOrUpdate
|
||||||
|
import im.vector.matrix.android.internal.database.helper.updateDisplayIndexes
|
||||||
|
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||||
|
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
||||||
|
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
|
||||||
|
import im.vector.matrix.android.internal.util.tryTransactionAsync
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
private const val SEND_WORK = "SEND_WORK"
|
private const val SEND_WORK = "SEND_WORK"
|
||||||
|
|
||||||
internal class DefaultSendService(private val roomId: String) : SendService {
|
internal class DefaultSendService(private val roomId: String,
|
||||||
|
private val eventFactory: EventFactory,
|
||||||
|
private val monarchy: Monarchy) : SendService {
|
||||||
|
|
||||||
private val sendConstraints = Constraints.Builder()
|
private val sendConstraints = Constraints.Builder()
|
||||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
override fun sendTextMessage(text: String): Cancelable {
|
override fun sendTextMessage(text: String, callback: MatrixCallback<Event>): Cancelable {
|
||||||
|
val event = eventFactory.createTextEvent(roomId, text)
|
||||||
|
|
||||||
val sendContentWorkerParams = SendEventWorker.Params(roomId, text)
|
monarchy.tryTransactionAsync { realm ->
|
||||||
|
val chunkEntity = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
|
||||||
|
?: return@tryTransactionAsync
|
||||||
|
chunkEntity.addOrUpdate(event, PaginationDirection.FORWARDS)
|
||||||
|
chunkEntity.updateDisplayIndexes()
|
||||||
|
}
|
||||||
|
|
||||||
|
val sendContentWorkerParams = SendEventWorker.Params(roomId, event)
|
||||||
val workData = WorkerParamsFactory.toData(sendContentWorkerParams)
|
val workData = WorkerParamsFactory.toData(sendContentWorkerParams)
|
||||||
|
|
||||||
val sendWork = OneTimeWorkRequestBuilder<SendEventWorker>()
|
val sendWork = OneTimeWorkRequestBuilder<SendEventWorker>()
|
||||||
|
@ -4,12 +4,14 @@ import android.content.Context
|
|||||||
import androidx.work.Worker
|
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.api.session.events.model.EventType
|
import com.zhuinden.monarchy.Monarchy
|
||||||
import im.vector.matrix.android.api.session.room.model.MessageContent
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.room.model.MessageType
|
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||||
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||||
import im.vector.matrix.android.internal.util.WorkerParamsFactory
|
import im.vector.matrix.android.internal.util.WorkerParamsFactory
|
||||||
|
import im.vector.matrix.android.internal.util.tryTransactionSync
|
||||||
import org.koin.standalone.KoinComponent
|
import org.koin.standalone.KoinComponent
|
||||||
import org.koin.standalone.inject
|
import org.koin.standalone.inject
|
||||||
|
|
||||||
@ -20,25 +22,35 @@ internal class SendEventWorker(context: Context, params: WorkerParameters)
|
|||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class Params(
|
internal data class Params(
|
||||||
val roomId: String,
|
val roomId: String,
|
||||||
val text: String
|
val event: Event
|
||||||
)
|
)
|
||||||
|
|
||||||
private val roomAPI by inject<RoomAPI>()
|
private val roomAPI by inject<RoomAPI>()
|
||||||
|
private val monarchy by inject<Monarchy>()
|
||||||
|
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
|
|
||||||
val sendWorkerParameters = WorkerParamsFactory.fromData<Params>(inputData)
|
val params = WorkerParamsFactory.fromData<Params>(inputData)
|
||||||
?: return Result.FAILURE
|
?: return Result.FAILURE
|
||||||
|
|
||||||
val fakeId = sendWorkerParameters.roomId + "-" + System.currentTimeMillis()
|
if (params.event.eventId == null) {
|
||||||
|
return Result.FAILURE
|
||||||
|
}
|
||||||
|
|
||||||
val result = executeRequest<SendResponse> {
|
val result = executeRequest<SendResponse> {
|
||||||
apiCall = roomAPI.send(
|
apiCall = roomAPI.send(
|
||||||
fakeId,
|
params.event.eventId,
|
||||||
sendWorkerParameters.roomId,
|
params.roomId,
|
||||||
EventType.MESSAGE,
|
params.event.type,
|
||||||
MessageContent(MessageType.MSGTYPE_TEXT, sendWorkerParameters.text)
|
params.event.content
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
result.flatMap { sendResponse ->
|
||||||
|
monarchy.tryTransactionSync { realm ->
|
||||||
|
val dummyEventEntity = EventEntity.where(realm, params.event.eventId).findFirst()
|
||||||
|
dummyEventEntity?.eventId = sendResponse.eventId
|
||||||
|
}
|
||||||
|
}
|
||||||
return result.fold({ Result.RETRY }, { Result.SUCCESS })
|
return result.fold({ Result.RETRY }, { Result.SUCCESS })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user