forked from GitHub-Mirror/riotX-android
Start sending message : introduce WorkManager. WIP - have to clean
This commit is contained in:
parent
b2bb89ac94
commit
f050574728
Binary file not shown.
@ -50,6 +50,13 @@ class RoomDetailFragment : RiotFragment() {
|
|||||||
room.loadRoomMembersIfNeeded()
|
room.loadRoomMembersIfNeeded()
|
||||||
room.liveTimeline().observe(this, Observer { renderEvents(it) })
|
room.liveTimeline().observe(this, Observer { renderEvents(it) })
|
||||||
room.roomSummary.observe(this, Observer { renderRoomSummary(it) })
|
room.roomSummary.observe(this, Observer { renderRoomSummary(it) })
|
||||||
|
sendButton.setOnClickListener {
|
||||||
|
val textMessage = composerEditText.text.toString()
|
||||||
|
if (textMessage.isNotBlank()) {
|
||||||
|
composerEditText.text = null
|
||||||
|
room.sendTextMessage(textMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupToolbar() {
|
private fun setupToolbar() {
|
||||||
|
BIN
app/src/main/res/drawable-hdpi/ic_send_white.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_send_white.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 335 B |
BIN
app/src/main/res/drawable-mdpi/ic_send_white.png
Normal file
BIN
app/src/main/res/drawable-mdpi/ic_send_white.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 257 B |
BIN
app/src/main/res/drawable-xhdpi/ic_send_white.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_send_white.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 423 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_send_white.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_send_white.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 550 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_send_white.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_send_white.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 728 B |
@ -73,9 +73,53 @@
|
|||||||
android:id="@+id/recyclerView"
|
android:id="@+id/recyclerView"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toTopOf="@+id/composerDivider"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/composerDivider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@color/pale_grey"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/composerLayout" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/composerLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/sendButton"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:src="@drawable/ic_send_white"
|
||||||
|
android:tint="?attr/colorAccent"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_centerVertical="true" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/composerEditText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toLeftOf="@id/sendButton"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:hint="Send a message"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:nextFocusLeft="@id/composerEditText"
|
||||||
|
android:nextFocusUp="@id/composerEditText"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
@ -75,6 +75,9 @@ dependencies {
|
|||||||
// Paging
|
// Paging
|
||||||
implementation "android.arch.paging:runtime:1.0.1"
|
implementation "android.arch.paging:runtime:1.0.1"
|
||||||
|
|
||||||
|
// Work
|
||||||
|
implementation "android.arch.work:work-runtime-ktx:1.0.0-alpha10"
|
||||||
|
|
||||||
// FP
|
// FP
|
||||||
implementation "io.arrow-kt:arrow-core:$arrow_version"
|
implementation "io.arrow-kt:arrow-core:$arrow_version"
|
||||||
implementation "io.arrow-kt:arrow-instances-core:$arrow_version"
|
implementation "io.arrow-kt:arrow-instances-core:$arrow_version"
|
||||||
|
@ -6,12 +6,14 @@ import com.squareup.moshi.JsonClass
|
|||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||||
import im.vector.matrix.android.internal.legacy.util.JsonUtils
|
import im.vector.matrix.android.internal.legacy.util.JsonUtils
|
||||||
|
|
||||||
|
typealias Content = Map<String, Any>
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class Event(
|
data class Event(
|
||||||
@Json(name = "type") val type: String,
|
@Json(name = "type") val type: String,
|
||||||
@Json(name = "event_id") val eventId: String?,
|
@Json(name = "event_id") val eventId: String?,
|
||||||
@Json(name = "content") val content: Map<String, Any>? = null,
|
@Json(name = "content") val content: Content? = null,
|
||||||
@Json(name = "prev_content") val prevContent: Map<String, Any>? = null,
|
@Json(name = "prev_content") val prevContent: Content? = null,
|
||||||
@Json(name = "origin_server_ts") val originServerTs: Long? = null,
|
@Json(name = "origin_server_ts") val originServerTs: Long? = null,
|
||||||
@Json(name = "sender") val sender: String? = null,
|
@Json(name = "sender") val sender: String? = null,
|
||||||
@Json(name = "state_key") val stateKey: String? = null,
|
@Json(name = "state_key") val stateKey: String? = null,
|
||||||
@ -39,7 +41,7 @@ data class Event(
|
|||||||
return toModel(prevContent)
|
return toModel(prevContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T> toModel(data: Map<String, Any>?): T? {
|
inline fun <reified T> toModel(data: Content?): T? {
|
||||||
val moshi = MoshiProvider.providesMoshi()
|
val moshi = MoshiProvider.providesMoshi()
|
||||||
val moshiAdapter = moshi.adapter(T::class.java)
|
val moshiAdapter = moshi.adapter(T::class.java)
|
||||||
return moshiAdapter.fromJsonValue(data)
|
return moshiAdapter.fromJsonValue(data)
|
||||||
|
@ -5,7 +5,7 @@ import im.vector.matrix.android.api.session.room.model.MyMembership
|
|||||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
|
|
||||||
interface Room : TimelineHolder {
|
interface Room : TimelineHolder, SendService {
|
||||||
|
|
||||||
val roomId: String
|
val roomId: String
|
||||||
|
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
package im.vector.matrix.android.api.session.room
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
|
|
||||||
|
interface SendService {
|
||||||
|
|
||||||
|
fun sendTextMessage(text: String): Cancelable
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -7,6 +7,7 @@ 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.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.TimelineHolder
|
import im.vector.matrix.android.api.session.room.TimelineHolder
|
||||||
import im.vector.matrix.android.api.session.room.model.Membership
|
import im.vector.matrix.android.api.session.room.model.Membership
|
||||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||||
@ -28,11 +29,11 @@ internal data class DefaultRoom(
|
|||||||
override val myMembership: MyMembership
|
override val myMembership: MyMembership
|
||||||
) : Room, KoinComponent {
|
) : Room, KoinComponent {
|
||||||
|
|
||||||
|
|
||||||
private val loadRoomMembersRequest by inject<LoadRoomMembersRequest>()
|
private val loadRoomMembersRequest by inject<LoadRoomMembersRequest>()
|
||||||
private val syncTokenStore by inject<SyncTokenStore>()
|
private val syncTokenStore by inject<SyncTokenStore>()
|
||||||
private val monarchy by inject<Monarchy>()
|
private val monarchy by inject<Monarchy>()
|
||||||
private val timelineHolder by inject<TimelineHolder>(parameters = { parametersOf(roomId) })
|
private val timelineHolder by inject<TimelineHolder>(parameters = { parametersOf(roomId) })
|
||||||
|
private val sendService by inject<SendService>(parameters = { parametersOf(roomId) })
|
||||||
|
|
||||||
override val roomSummary: LiveData<RoomSummary> by lazy {
|
override val roomSummary: LiveData<RoomSummary> by lazy {
|
||||||
val liveData = monarchy
|
val liveData = monarchy
|
||||||
@ -66,4 +67,8 @@ internal data class DefaultRoom(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun sendTextMessage(text: String): Cancelable {
|
||||||
|
return sendService.sendTextMessage(text)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,12 +1,14 @@
|
|||||||
package im.vector.matrix.android.internal.session.room
|
package im.vector.matrix.android.internal.session.room
|
||||||
|
|
||||||
|
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
|
||||||
import im.vector.matrix.android.internal.session.room.members.RoomMembersResponse
|
import im.vector.matrix.android.internal.session.room.members.RoomMembersResponse
|
||||||
|
import im.vector.matrix.android.internal.session.room.send.SendResponse
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEvent
|
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEvent
|
||||||
import kotlinx.coroutines.Deferred
|
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Response
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.PUT
|
||||||
import retrofit2.http.Path
|
import retrofit2.http.Path
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
|
||||||
@ -46,4 +48,20 @@ internal interface RoomAPI {
|
|||||||
): Call<RoomMembersResponse>
|
): Call<RoomMembersResponse>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an event to a room.
|
||||||
|
*
|
||||||
|
* @param txId the transaction Id
|
||||||
|
* @param roomId the room id
|
||||||
|
* @param eventType the event type
|
||||||
|
* @param content the event content
|
||||||
|
*/
|
||||||
|
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/send/{eventType}/{txId}")
|
||||||
|
fun send(@Path("txId") txId: String,
|
||||||
|
@Path("roomId") roomId: String,
|
||||||
|
@Path("eventType") eventType: String,
|
||||||
|
@Body content: MessageContent
|
||||||
|
): Call<SendResponse>
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,12 +1,13 @@
|
|||||||
package im.vector.matrix.android.internal.session.room
|
package im.vector.matrix.android.internal.session.room
|
||||||
|
|
||||||
|
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.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.timeline.DefaultTimelineHolder
|
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineHolder
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationRequest
|
import im.vector.matrix.android.internal.session.room.timeline.PaginationRequest
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.TimelineBoundaryCallback
|
import im.vector.matrix.android.internal.session.room.timeline.TimelineBoundaryCallback
|
||||||
import org.koin.core.parameter.parametersOf
|
|
||||||
import org.koin.dsl.context.ModuleDefinition
|
import org.koin.dsl.context.ModuleDefinition
|
||||||
import org.koin.dsl.module.Module
|
import org.koin.dsl.module.Module
|
||||||
import org.koin.dsl.module.module
|
import org.koin.dsl.module.module
|
||||||
@ -31,14 +32,16 @@ class RoomModule : Module {
|
|||||||
PaginationRequest(get(), get(), get(), get())
|
PaginationRequest(get(), get(), get(), get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
factory {
|
factory {
|
||||||
val roomId: String = it[0]
|
val roomId: String = it[0]
|
||||||
TimelineBoundaryCallback(roomId, get(), get(), Executors.newSingleThreadExecutor())
|
val timelineBoundaryCallback = TimelineBoundaryCallback(roomId, get(), get(), Executors.newSingleThreadExecutor())
|
||||||
|
DefaultTimelineHolder(roomId, get(), timelineBoundaryCallback) as TimelineHolder
|
||||||
}
|
}
|
||||||
|
|
||||||
factory {
|
factory {
|
||||||
val roomId: String = it[0]
|
val roomId: String = it[0]
|
||||||
DefaultTimelineHolder(roomId, get(), get(parameters = { parametersOf(roomId) })) as TimelineHolder
|
DefaultSendService(roomId) as SendService
|
||||||
}
|
}
|
||||||
|
|
||||||
}.invoke()
|
}.invoke()
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package im.vector.matrix.android.internal.session.room.send
|
||||||
|
|
||||||
|
import androidx.work.BackoffPolicy
|
||||||
|
import androidx.work.Constraints
|
||||||
|
import androidx.work.Data
|
||||||
|
import androidx.work.ExistingWorkPolicy
|
||||||
|
import androidx.work.NetworkType
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import im.vector.matrix.android.api.session.room.SendService
|
||||||
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
|
import im.vector.matrix.android.internal.util.CancelableWork
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
private const val SEND_WORK_NAME = "SEND_WORK_NAME"
|
||||||
|
|
||||||
|
internal class DefaultSendService(private val roomId: String) : SendService {
|
||||||
|
|
||||||
|
private val sendConstraints = Constraints.Builder()
|
||||||
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
override fun sendTextMessage(text: String): Cancelable {
|
||||||
|
|
||||||
|
val data = mapOf(
|
||||||
|
"roomId" to roomId,
|
||||||
|
"text" to text
|
||||||
|
)
|
||||||
|
val workData = Data.Builder().putAll(data).build()
|
||||||
|
|
||||||
|
val sendWork = OneTimeWorkRequestBuilder<SendContentWorker>()
|
||||||
|
.setConstraints(sendConstraints)
|
||||||
|
.setInputData(workData)
|
||||||
|
.setBackoffCriteria(BackoffPolicy.LINEAR, 10_000, TimeUnit.MILLISECONDS)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val work = WorkManager.getInstance()
|
||||||
|
.beginUniqueWork(SEND_WORK_NAME, ExistingWorkPolicy.APPEND, sendWork)
|
||||||
|
.enqueue()
|
||||||
|
|
||||||
|
return CancelableWork(work)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package im.vector.matrix.android.internal.session.room.send
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.Worker
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
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.network.executeRequest
|
||||||
|
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||||
|
import org.koin.standalone.KoinComponent
|
||||||
|
import org.koin.standalone.inject
|
||||||
|
|
||||||
|
internal class SendContentWorker(context: Context, params: WorkerParameters)
|
||||||
|
: Worker(context, params), KoinComponent {
|
||||||
|
|
||||||
|
private val roomAPI by inject<RoomAPI>()
|
||||||
|
|
||||||
|
override fun doWork(): Result {
|
||||||
|
|
||||||
|
val roomId = inputData.getString("roomId")
|
||||||
|
val text = inputData.getString("text")
|
||||||
|
|
||||||
|
val fakeId = roomId + "-" + System.currentTimeMillis()
|
||||||
|
|
||||||
|
if (roomId == null || text == null) {
|
||||||
|
return Result.FAILURE
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = executeRequest<SendResponse> {
|
||||||
|
apiCall = roomAPI.send(fakeId, roomId, EventType.MESSAGE, MessageContent(MessageType.MSGTYPE_TEXT, text))
|
||||||
|
}
|
||||||
|
return result.fold({ Result.RETRY }, { Result.SUCCESS })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package im.vector.matrix.android.internal.session.room.send
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
internal data class SendResponse(
|
||||||
|
@Json(name = "event_id") val eventId: String
|
||||||
|
)
|
@ -0,0 +1,13 @@
|
|||||||
|
package im.vector.matrix.android.internal.util
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
|
||||||
|
internal class CancelableWork(private val work: ListenableFuture<Void>) : Cancelable {
|
||||||
|
|
||||||
|
override fun cancel() {
|
||||||
|
work.cancel(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user