wip, passing the image urls down to the matrix client layer
This commit is contained in:
parent
92ad630e45
commit
6fed8a35ce
|
@ -0,0 +1,29 @@
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<option name="composableFile" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
|
@ -44,6 +44,7 @@ import app.dapk.st.matrix.sync.internal.room.MessageDecrypter
|
||||||
import app.dapk.st.messenger.MessengerActivity
|
import app.dapk.st.messenger.MessengerActivity
|
||||||
import app.dapk.st.messenger.MessengerModule
|
import app.dapk.st.messenger.MessengerModule
|
||||||
import app.dapk.st.navigator.IntentFactory
|
import app.dapk.st.navigator.IntentFactory
|
||||||
|
import app.dapk.st.navigator.MessageAttachment
|
||||||
import app.dapk.st.notifications.NotificationsModule
|
import app.dapk.st.notifications.NotificationsModule
|
||||||
import app.dapk.st.olm.DeviceKeyFactory
|
import app.dapk.st.olm.DeviceKeyFactory
|
||||||
import app.dapk.st.olm.OlmPersistenceWrapper
|
import app.dapk.st.olm.OlmPersistenceWrapper
|
||||||
|
@ -93,6 +94,11 @@ internal class AppModule(context: Application, logger: MatrixLogger) {
|
||||||
override fun home(context: Context) = Intent(context, MainActivity::class.java)
|
override fun home(context: Context) = Intent(context, MainActivity::class.java)
|
||||||
override fun messenger(context: Context, roomId: RoomId) = MessengerActivity.newInstance(context, roomId)
|
override fun messenger(context: Context, roomId: RoomId) = MessengerActivity.newInstance(context, roomId)
|
||||||
override fun messengerShortcut(context: Context, roomId: RoomId) = MessengerActivity.newShortcutInstance(context, roomId)
|
override fun messengerShortcut(context: Context, roomId: RoomId) = MessengerActivity.newShortcutInstance(context, roomId)
|
||||||
|
override fun messengerAttachments(context: Context, roomId: RoomId, attachments: List<MessageAttachment>) = MessengerActivity.newMessageAttachment(
|
||||||
|
context,
|
||||||
|
roomId,
|
||||||
|
attachments
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
val featureModules = FeatureModules(
|
val featureModules = FeatureModules(
|
||||||
|
@ -236,6 +242,7 @@ internal class MatrixModules(
|
||||||
val result = serviceProvider.cryptoService().encrypt(
|
val result = serviceProvider.cryptoService().encrypt(
|
||||||
roomId = when (message) {
|
roomId = when (message) {
|
||||||
is MessageService.Message.TextMessage -> message.roomId
|
is MessageService.Message.TextMessage -> message.roomId
|
||||||
|
is MessageService.Message.ImageMessage -> message.roomId
|
||||||
},
|
},
|
||||||
credentials = credentialsStore.credentials()!!,
|
credentials = credentialsStore.credentials()!!,
|
||||||
when (message) {
|
when (message) {
|
||||||
|
@ -250,6 +257,7 @@ internal class MatrixModules(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
is MessageService.Message.ImageMessage -> TODO()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package app.dapk.st.core
|
||||||
|
|
||||||
|
sealed interface MimeType {
|
||||||
|
object Image: MimeType
|
||||||
|
}
|
|
@ -33,11 +33,13 @@ class LocalEchoPersistence(
|
||||||
inMemoryEchos.value = echos.groupBy {
|
inMemoryEchos.value = echos.groupBy {
|
||||||
when (val message = it.message) {
|
when (val message = it.message) {
|
||||||
is MessageService.Message.TextMessage -> message.roomId
|
is MessageService.Message.TextMessage -> message.roomId
|
||||||
|
is MessageService.Message.ImageMessage -> message.roomId
|
||||||
}
|
}
|
||||||
}.mapValues {
|
}.mapValues {
|
||||||
it.value.associateBy {
|
it.value.associateBy {
|
||||||
when (val message = it.message) {
|
when (val message = it.message) {
|
||||||
is MessageService.Message.TextMessage -> message.localId
|
is MessageService.Message.TextMessage -> message.localId
|
||||||
|
is MessageService.Message.ImageMessage -> message.localId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,7 @@ class DirectoryUseCase(
|
||||||
lastMessage = LastMessage(
|
lastMessage = LastMessage(
|
||||||
content = when (val message = latestEcho.message) {
|
content = when (val message = latestEcho.message) {
|
||||||
is MessageService.Message.TextMessage -> message.content.body
|
is MessageService.Message.TextMessage -> message.content.body
|
||||||
|
is MessageService.Message.ImageMessage -> "\uD83D\uDCF7"
|
||||||
},
|
},
|
||||||
utcTimestamp = latestEcho.timestampUtc,
|
utcTimestamp = latestEcho.timestampUtc,
|
||||||
author = member,
|
author = member,
|
||||||
|
|
|
@ -19,6 +19,7 @@ internal class LocalEchoMapper(private val metaMapper: MetaMapper) {
|
||||||
meta = metaMapper.toMeta(this)
|
meta = metaMapper.toMeta(this)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
is MessageService.Message.ImageMessage -> TODO()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,10 @@ import androidx.activity.compose.setContent
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material.Surface
|
import androidx.compose.material.Surface
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import app.dapk.st.core.DapkActivity
|
import app.dapk.st.core.*
|
||||||
import app.dapk.st.core.module
|
|
||||||
import app.dapk.st.core.viewModel
|
|
||||||
import app.dapk.st.design.components.SmallTalkTheme
|
import app.dapk.st.design.components.SmallTalkTheme
|
||||||
import app.dapk.st.matrix.common.RoomId
|
import app.dapk.st.matrix.common.RoomId
|
||||||
|
import app.dapk.st.navigator.MessageAttachment
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
class MessengerActivity : DapkActivity() {
|
class MessengerActivity : DapkActivity() {
|
||||||
|
@ -34,15 +33,22 @@ class MessengerActivity : DapkActivity() {
|
||||||
putExtra("shortcut_key", roomId.value)
|
putExtra("shortcut_key", roomId.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun newMessageAttachment(context: Context, roomId: RoomId, attachments: List<MessageAttachment>): Intent {
|
||||||
|
return Intent(context, MessengerActivity::class.java).apply {
|
||||||
|
putExtra("key", MessagerActivityPayload(roomId.value, attachments))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val payload = readPayload<MessagerActivityPayload>()
|
val payload = readPayload<MessagerActivityPayload>()
|
||||||
|
log(AppLogTag.ERROR_NON_FATAL, payload)
|
||||||
setContent {
|
setContent {
|
||||||
SmallTalkTheme {
|
SmallTalkTheme {
|
||||||
Surface(Modifier.fillMaxSize()) {
|
Surface(Modifier.fillMaxSize()) {
|
||||||
MessengerScreen(RoomId(payload.roomId), viewModel, navigator)
|
MessengerScreen(RoomId(payload.roomId), payload.attachments, viewModel, navigator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +57,8 @@ class MessengerActivity : DapkActivity() {
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class MessagerActivityPayload(
|
data class MessagerActivityPayload(
|
||||||
val roomId: String
|
val roomId: String,
|
||||||
|
val attachments: List<MessageAttachment>? = null
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
fun <T : Parcelable> Activity.readPayload(): T = intent.getParcelableExtra("key") ?: intent.getStringExtra("shortcut_key")!!.let {
|
fun <T : Parcelable> Activity.readPayload(): T = intent.getParcelableExtra("key") ?: intent.getStringExtra("shortcut_key")!!.let {
|
||||||
|
|
|
@ -28,6 +28,7 @@ import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.*
|
import androidx.compose.ui.unit.*
|
||||||
|
import androidx.core.net.toUri
|
||||||
import app.dapk.st.core.Lce
|
import app.dapk.st.core.Lce
|
||||||
import app.dapk.st.core.LifecycleEffect
|
import app.dapk.st.core.LifecycleEffect
|
||||||
import app.dapk.st.core.StartObserving
|
import app.dapk.st.core.StartObserving
|
||||||
|
@ -39,18 +40,19 @@ import app.dapk.st.matrix.sync.MessageMeta
|
||||||
import app.dapk.st.matrix.sync.RoomEvent
|
import app.dapk.st.matrix.sync.RoomEvent
|
||||||
import app.dapk.st.matrix.sync.RoomEvent.Message
|
import app.dapk.st.matrix.sync.RoomEvent.Message
|
||||||
import app.dapk.st.matrix.sync.RoomState
|
import app.dapk.st.matrix.sync.RoomState
|
||||||
|
import app.dapk.st.navigator.MessageAttachment
|
||||||
import app.dapk.st.navigator.Navigator
|
import app.dapk.st.navigator.Navigator
|
||||||
import coil.compose.rememberAsyncImagePainter
|
import coil.compose.rememberAsyncImagePainter
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun MessengerScreen(roomId: RoomId, viewModel: MessengerViewModel, navigator: Navigator) {
|
internal fun MessengerScreen(roomId: RoomId, attachments: List<MessageAttachment>?, viewModel: MessengerViewModel, navigator: Navigator) {
|
||||||
val state = viewModel.state
|
val state = viewModel.state
|
||||||
|
|
||||||
viewModel.ObserveEvents()
|
viewModel.ObserveEvents()
|
||||||
LifecycleEffect(
|
LifecycleEffect(
|
||||||
onStart = { viewModel.post(MessengerAction.OnMessengerVisible(roomId)) },
|
onStart = { viewModel.post(MessengerAction.OnMessengerVisible(roomId, attachments)) },
|
||||||
onStop = { viewModel.post(MessengerAction.OnMessengerGone) }
|
onStop = { viewModel.post(MessengerAction.OnMessengerGone) }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -70,12 +72,19 @@ internal fun MessengerScreen(roomId: RoomId, viewModel: MessengerViewModel, navi
|
||||||
Room(state.roomState)
|
Room(state.roomState)
|
||||||
when (state.composerState) {
|
when (state.composerState) {
|
||||||
is ComposerState.Text -> {
|
is ComposerState.Text -> {
|
||||||
Composer(
|
TextComposer(
|
||||||
state.composerState.value,
|
state.composerState,
|
||||||
onTextChange = { viewModel.post(MessengerAction.ComposerTextUpdate(it)) },
|
onTextChange = { viewModel.post(MessengerAction.ComposerTextUpdate(it)) },
|
||||||
onSend = { viewModel.post(MessengerAction.ComposerSendText) },
|
onSend = { viewModel.post(MessengerAction.ComposerSendText) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
is ComposerState.Attachments -> {
|
||||||
|
AttachmentComposer(
|
||||||
|
state.composerState,
|
||||||
|
onSend = { viewModel.post(MessengerAction.ComposerSendText) },
|
||||||
|
onCancel = { viewModel.post(MessengerAction.ComposerClear) }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -524,7 +533,7 @@ private fun RowScope.SendStatus(message: RoomEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Composer(message: String, onTextChange: (String) -> Unit, onSend: () -> Unit) {
|
private fun TextComposer(state: ComposerState.Text, onTextChange: (String) -> Unit, onSend: () -> Unit) {
|
||||||
Row(
|
Row(
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
@ -541,12 +550,12 @@ private fun Composer(message: String, onTextChange: (String) -> Unit, onSend: ()
|
||||||
contentAlignment = Alignment.TopStart,
|
contentAlignment = Alignment.TopStart,
|
||||||
) {
|
) {
|
||||||
Box(Modifier.padding(14.dp)) {
|
Box(Modifier.padding(14.dp)) {
|
||||||
if (message.isEmpty()) {
|
if (state.value.isEmpty()) {
|
||||||
Text("Message")
|
Text("Message")
|
||||||
}
|
}
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
value = message,
|
value = state.value,
|
||||||
onValueChange = { onTextChange(it) },
|
onValueChange = { onTextChange(it) },
|
||||||
cursorBrush = SolidColor(MaterialTheme.colors.primary),
|
cursorBrush = SolidColor(MaterialTheme.colors.primary),
|
||||||
textStyle = LocalTextStyle.current.copy(color = LocalContentColor.current.copy(LocalContentAlpha.current)),
|
textStyle = LocalTextStyle.current.copy(color = LocalContentColor.current.copy(LocalContentAlpha.current)),
|
||||||
|
@ -557,10 +566,10 @@ private fun Composer(message: String, onTextChange: (String) -> Unit, onSend: ()
|
||||||
Spacer(modifier = Modifier.width(6.dp))
|
Spacer(modifier = Modifier.width(6.dp))
|
||||||
var size by remember { mutableStateOf(IntSize(0, 0)) }
|
var size by remember { mutableStateOf(IntSize(0, 0)) }
|
||||||
IconButton(
|
IconButton(
|
||||||
enabled = message.isNotEmpty(),
|
enabled = state.value.isNotEmpty(),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.background(if (message.isEmpty()) Color.DarkGray else MaterialTheme.colors.primary)
|
.background(if (state.value.isEmpty()) Color.DarkGray else MaterialTheme.colors.primary)
|
||||||
.run {
|
.run {
|
||||||
if (size.height == 0 || size.width == 0) {
|
if (size.height == 0 || size.width == 0) {
|
||||||
this
|
this
|
||||||
|
@ -584,3 +593,65 @@ private fun Composer(message: String, onTextChange: (String) -> Unit, onSend: ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun AttachmentComposer(state: ComposerState.Attachments, onSend: () -> Unit, onCancel: () -> Unit) {
|
||||||
|
Row(
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 12.dp, vertical = 8.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(IntrinsicSize.Min), verticalAlignment = Alignment.Bottom
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.Bottom)
|
||||||
|
.weight(1f)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.background(MaterialTheme.colors.onSurface.copy(alpha = TextFieldDefaults.BackgroundOpacity), RoundedCornerShape(24.dp)),
|
||||||
|
contentAlignment = Alignment.TopStart,
|
||||||
|
) {
|
||||||
|
Box(Modifier.padding(14.dp)) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
Image(
|
||||||
|
modifier = Modifier.size(50.dp, 50.dp),
|
||||||
|
painter = rememberAsyncImagePainter(
|
||||||
|
model = ImageRequest.Builder(context)
|
||||||
|
.data(state.values.first().uri.value.toUri())
|
||||||
|
.build()
|
||||||
|
),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(6.dp))
|
||||||
|
var size by remember { mutableStateOf(IntSize(0, 0)) }
|
||||||
|
IconButton(
|
||||||
|
enabled = true,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(MaterialTheme.colors.primary)
|
||||||
|
.run {
|
||||||
|
if (size.height == 0 || size.width == 0) {
|
||||||
|
this
|
||||||
|
.onSizeChanged {
|
||||||
|
size = it
|
||||||
|
}
|
||||||
|
.fillMaxHeight()
|
||||||
|
} else {
|
||||||
|
with(LocalDensity.current) {
|
||||||
|
size(size.width.toDp(), size.height.toDp())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onClick = onSend,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Send,
|
||||||
|
contentDescription = "",
|
||||||
|
tint = MaterialTheme.colors.onPrimary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package app.dapk.st.messenger
|
||||||
|
|
||||||
import app.dapk.st.core.Lce
|
import app.dapk.st.core.Lce
|
||||||
import app.dapk.st.matrix.common.RoomId
|
import app.dapk.st.matrix.common.RoomId
|
||||||
|
import app.dapk.st.navigator.MessageAttachment
|
||||||
|
|
||||||
data class MessengerScreenState(
|
data class MessengerScreenState(
|
||||||
val roomId: RoomId?,
|
val roomId: RoomId?,
|
||||||
|
@ -17,4 +18,8 @@ sealed interface ComposerState {
|
||||||
val value: String,
|
val value: String,
|
||||||
) : ComposerState
|
) : ComposerState
|
||||||
|
|
||||||
|
data class Attachments(
|
||||||
|
val values: List<MessageAttachment>,
|
||||||
|
) : ComposerState
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import app.dapk.st.matrix.message.MessageService
|
||||||
import app.dapk.st.matrix.room.RoomService
|
import app.dapk.st.matrix.room.RoomService
|
||||||
import app.dapk.st.matrix.sync.RoomEvent
|
import app.dapk.st.matrix.sync.RoomEvent
|
||||||
import app.dapk.st.matrix.sync.RoomStore
|
import app.dapk.st.matrix.sync.RoomStore
|
||||||
|
import app.dapk.st.navigator.MessageAttachment
|
||||||
import app.dapk.st.viewmodel.DapkViewModel
|
import app.dapk.st.viewmodel.DapkViewModel
|
||||||
import app.dapk.st.viewmodel.MutableStateFactory
|
import app.dapk.st.viewmodel.MutableStateFactory
|
||||||
import app.dapk.st.viewmodel.defaultStateFactory
|
import app.dapk.st.viewmodel.defaultStateFactory
|
||||||
|
@ -46,18 +47,19 @@ internal class MessengerViewModel(
|
||||||
MessengerAction.OnMessengerGone -> syncJob?.cancel()
|
MessengerAction.OnMessengerGone -> syncJob?.cancel()
|
||||||
is MessengerAction.ComposerTextUpdate -> updateState { copy(composerState = ComposerState.Text(action.newValue)) }
|
is MessengerAction.ComposerTextUpdate -> updateState { copy(composerState = ComposerState.Text(action.newValue)) }
|
||||||
MessengerAction.ComposerSendText -> sendMessage()
|
MessengerAction.ComposerSendText -> sendMessage()
|
||||||
|
MessengerAction.ComposerClear -> updateState { copy(composerState = ComposerState.Text("")) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun start(action: MessengerAction.OnMessengerVisible) {
|
private fun start(action: MessengerAction.OnMessengerVisible) {
|
||||||
updateState { copy(roomId = action.roomId) }
|
updateState { copy(roomId = action.roomId, composerState = action.attachments?.let { ComposerState.Attachments(it) } ?: composerState) }
|
||||||
syncJob = viewModelScope.launch {
|
syncJob = viewModelScope.launch {
|
||||||
roomStore.markRead(action.roomId)
|
roomStore.markRead(action.roomId)
|
||||||
|
|
||||||
val credentials = credentialsStore.credentials()!!
|
val credentials = credentialsStore.credentials()!!
|
||||||
var lastKnownReadEvent: EventId? = null
|
var lastKnownReadEvent: EventId? = null
|
||||||
observeTimeline.invoke(action.roomId, credentials.userId).distinctUntilChanged().onEach { state ->
|
observeTimeline.invoke(action.roomId, credentials.userId).distinctUntilChanged().onEach { state ->
|
||||||
state.lastestMessageEventFromOthers(self = credentials.userId)?.let {
|
state.latestMessageEventFromOthers(self = credentials.userId)?.let {
|
||||||
if (lastKnownReadEvent != it) {
|
if (lastKnownReadEvent != it) {
|
||||||
updateRoomReadStateAsync(latestReadEvent = it, state)
|
updateRoomReadStateAsync(latestReadEvent = it, state)
|
||||||
lastKnownReadEvent = it
|
lastKnownReadEvent = it
|
||||||
|
@ -98,12 +100,32 @@ internal class MessengerViewModel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is ComposerState.Attachments -> {
|
||||||
|
val copy = composerState.copy()
|
||||||
|
updateState { copy(composerState = ComposerState.Text("")) }
|
||||||
|
|
||||||
|
state.roomState.takeIfContent()?.let { content ->
|
||||||
|
val roomState = content.roomState
|
||||||
|
viewModelScope.launch {
|
||||||
|
messageService.scheduleMessage(
|
||||||
|
MessageService.Message.ImageMessage(
|
||||||
|
MessageService.Message.Content.ImageContent(uri = copy.values.first().uri.value),
|
||||||
|
roomId = roomState.roomOverview.roomId,
|
||||||
|
sendEncrypted = roomState.roomOverview.isEncrypted,
|
||||||
|
localId = localIdFactory.create(),
|
||||||
|
timestampUtc = clock.millis(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MessengerState.lastestMessageEventFromOthers(self: UserId) = this.roomState.events
|
private fun MessengerState.latestMessageEventFromOthers(self: UserId) = this.roomState.events
|
||||||
.filterIsInstance<RoomEvent.Message>()
|
.filterIsInstance<RoomEvent.Message>()
|
||||||
.filterNot { it.author.id == self }
|
.filterNot { it.author.id == self }
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
|
@ -112,6 +134,7 @@ private fun MessengerState.lastestMessageEventFromOthers(self: UserId) = this.ro
|
||||||
sealed interface MessengerAction {
|
sealed interface MessengerAction {
|
||||||
data class ComposerTextUpdate(val newValue: String) : MessengerAction
|
data class ComposerTextUpdate(val newValue: String) : MessengerAction
|
||||||
object ComposerSendText : MessengerAction
|
object ComposerSendText : MessengerAction
|
||||||
data class OnMessengerVisible(val roomId: RoomId) : MessengerAction
|
object ComposerClear : MessengerAction
|
||||||
|
data class OnMessengerVisible(val roomId: RoomId, val attachments: List<MessageAttachment>?) : MessengerAction
|
||||||
object OnMessengerGone : MessengerAction
|
object OnMessengerGone : MessengerAction
|
||||||
}
|
}
|
|
@ -36,7 +36,7 @@ class RoomSettingsActivity : DapkActivity() {
|
||||||
setContent {
|
setContent {
|
||||||
SmallTalkTheme {
|
SmallTalkTheme {
|
||||||
Surface(Modifier.fillMaxSize()) {
|
Surface(Modifier.fillMaxSize()) {
|
||||||
MessengerScreen(RoomId(payload.roomId), viewModel, navigator)
|
// MessengerScreen(RoomId(payload.roomId), payload.attachments, viewModel, navigator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
applyAndroidLibraryModule(project)
|
applyAndroidLibraryModule(project)
|
||||||
|
apply plugin: 'kotlin-parcelize'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":core")
|
implementation project(":core")
|
||||||
|
|
|
@ -3,7 +3,13 @@ package app.dapk.st.navigator
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
|
import app.dapk.st.core.AndroidUri
|
||||||
|
import app.dapk.st.core.MimeType
|
||||||
import app.dapk.st.matrix.common.RoomId
|
import app.dapk.st.matrix.common.RoomId
|
||||||
|
import kotlinx.parcelize.Parceler
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
@ -29,8 +35,9 @@ interface Navigator {
|
||||||
activity.navigateUpTo(intentFactory.home(activity))
|
activity.navigateUpTo(intentFactory.home(activity))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toMessenger(roomId: RoomId) {
|
fun toMessenger(roomId: RoomId, attachments: List<MessageAttachment>) {
|
||||||
intentFactory.messenger(activity, roomId)
|
val intent = intentFactory.messengerAttachments(activity, roomId, attachments)
|
||||||
|
activity.startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toFilePicker(requestCode: Int) {
|
fun toFilePicker(requestCode: Int) {
|
||||||
|
@ -47,6 +54,7 @@ interface IntentFactory {
|
||||||
fun home(context: Context): Intent
|
fun home(context: Context): Intent
|
||||||
fun messenger(context: Context, roomId: RoomId): Intent
|
fun messenger(context: Context, roomId: RoomId): Intent
|
||||||
fun messengerShortcut(context: Context, roomId: RoomId): Intent
|
fun messengerShortcut(context: Context, roomId: RoomId): Intent
|
||||||
|
fun messengerAttachments(context: Context, roomId: RoomId, attachments: List<MessageAttachment>): Intent
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,3 +73,24 @@ private class DefaultNavigator(activity: Activity, intentFactory: IntentFactory)
|
||||||
override val navigate: Navigator.Dsl = Navigator.Dsl(activity, intentFactory)
|
override val navigate: Navigator.Dsl = Navigator.Dsl(activity, intentFactory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class MessageAttachment(val uri: AndroidUri, val type: MimeType) : Parcelable {
|
||||||
|
private companion object : Parceler<MessageAttachment> {
|
||||||
|
override fun create(parcel: Parcel): MessageAttachment {
|
||||||
|
val uri = AndroidUri(parcel.readString()!!)
|
||||||
|
val type = when(parcel.readString()!!) {
|
||||||
|
"mimetype-image" -> MimeType.Image
|
||||||
|
else -> throw IllegalStateException()
|
||||||
|
}
|
||||||
|
return MessageAttachment(uri, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun MessageAttachment.write(parcel: Parcel, flags: Int) {
|
||||||
|
parcel.writeString(uri.value)
|
||||||
|
when (type) {
|
||||||
|
MimeType.Image -> parcel.writeString("mimetype-image")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,4 +9,5 @@ dependencies {
|
||||||
implementation project(':matrix:services:message')
|
implementation project(':matrix:services:message')
|
||||||
implementation project(":core")
|
implementation project(":core")
|
||||||
implementation project(":design-library")
|
implementation project(":design-library")
|
||||||
|
implementation project(":features:navigator")
|
||||||
}
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package app.dapk.st.share
|
||||||
|
|
||||||
|
import app.dapk.st.matrix.room.RoomService
|
||||||
|
import app.dapk.st.matrix.sync.SyncService
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
|
||||||
|
class FetchRoomsUseCase(
|
||||||
|
private val syncSyncService: SyncService,
|
||||||
|
private val roomService: RoomService,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun bar(): List<Item> {
|
||||||
|
return syncSyncService.overview().first().map {
|
||||||
|
Item(
|
||||||
|
it.roomId,
|
||||||
|
it.roomAvatarUrl,
|
||||||
|
it.roomName ?: "",
|
||||||
|
roomService.findMembersSummary(it.roomId).map { it.displayName ?: it.id.value }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,11 +19,11 @@ class ShareEntryActivity : DapkActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val urisToShare = intent.readSendUrisOrNull() ?: throw IllegalArgumentException("")
|
val urisToShare = intent.readSendUrisOrNull() ?: throw IllegalArgumentException("Expected deeplink uris but they were missing")
|
||||||
setContent {
|
setContent {
|
||||||
SmallTalkTheme {
|
SmallTalkTheme {
|
||||||
Surface(Modifier.fillMaxSize()) {
|
Surface(Modifier.fillMaxSize()) {
|
||||||
ShareEntryScreen(viewModel)
|
ShareEntryScreen(navigator, viewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,37 +11,36 @@ import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import app.dapk.st.core.LifecycleEffect
|
import app.dapk.st.core.LifecycleEffect
|
||||||
|
import app.dapk.st.core.MimeType
|
||||||
import app.dapk.st.core.StartObserving
|
import app.dapk.st.core.StartObserving
|
||||||
import app.dapk.st.core.components.CenteredLoading
|
import app.dapk.st.core.components.CenteredLoading
|
||||||
import app.dapk.st.design.components.CircleishAvatar
|
import app.dapk.st.design.components.CircleishAvatar
|
||||||
import app.dapk.st.design.components.GenericEmpty
|
import app.dapk.st.design.components.GenericEmpty
|
||||||
import app.dapk.st.design.components.GenericError
|
import app.dapk.st.design.components.GenericError
|
||||||
import app.dapk.st.design.components.Toolbar
|
import app.dapk.st.design.components.Toolbar
|
||||||
import app.dapk.st.matrix.common.RoomId
|
import app.dapk.st.navigator.MessageAttachment
|
||||||
|
import app.dapk.st.navigator.Navigator
|
||||||
import app.dapk.st.share.DirectoryScreenState.*
|
import app.dapk.st.share.DirectoryScreenState.*
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ShareEntryScreen(viewModel: ShareEntryViewModel) {
|
fun ShareEntryScreen(navigator: Navigator, viewModel: ShareEntryViewModel) {
|
||||||
val state = viewModel.state
|
val state = viewModel.state
|
||||||
|
viewModel.ObserveEvents(navigator)
|
||||||
val listState: LazyListState = rememberLazyListState(
|
|
||||||
initialFirstVisibleItemIndex = 0,
|
|
||||||
)
|
|
||||||
|
|
||||||
viewModel.ObserveEvents(listState)
|
|
||||||
|
|
||||||
LifecycleEffect(
|
LifecycleEffect(
|
||||||
onStart = { viewModel.start() },
|
onStart = { viewModel.start() },
|
||||||
onStop = { viewModel.stop() }
|
onStop = { viewModel.stop() }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val listState: LazyListState = rememberLazyListState(
|
||||||
|
initialFirstVisibleItemIndex = 0,
|
||||||
|
)
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
Toolbar(title = "Send to...")
|
Toolbar(title = "Send to...")
|
||||||
when (state) {
|
when (state) {
|
||||||
|
@ -50,18 +49,21 @@ fun ShareEntryScreen(viewModel: ShareEntryViewModel) {
|
||||||
is Error -> GenericError {
|
is Error -> GenericError {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
is Content -> Content(listState, state)
|
is Content -> Content(listState, state) {
|
||||||
|
viewModel.onRoomSelected(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ShareEntryViewModel.ObserveEvents(listState: LazyListState) {
|
private fun ShareEntryViewModel.ObserveEvents(navigator: Navigator) {
|
||||||
val context = LocalContext.current
|
|
||||||
StartObserving {
|
StartObserving {
|
||||||
this@ObserveEvents.events.launch {
|
this@ObserveEvents.events.launch {
|
||||||
when (it) {
|
when (it) {
|
||||||
is DirectoryEvent.SelectRoom -> TODO()
|
is DirectoryEvent.SelectRoom -> {
|
||||||
|
navigator.navigate.toMessenger(it.item.id, it.uris.map { MessageAttachment(it, MimeType.Image) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,33 +71,27 @@ private fun ShareEntryViewModel.ObserveEvents(listState: LazyListState) {
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Content(listState: LazyListState, state: Content) {
|
private fun Content(listState: LazyListState, state: Content, onClick: (Item) -> Unit) {
|
||||||
val context = LocalContext.current
|
|
||||||
val navigateToRoom = { roomId: RoomId ->
|
|
||||||
// todo
|
|
||||||
// context.startActivity(MessengerActivity.newInstance(context, roomId))
|
|
||||||
}
|
|
||||||
LazyColumn(Modifier.fillMaxSize(), state = listState, contentPadding = PaddingValues(top = 72.dp)) {
|
LazyColumn(Modifier.fillMaxSize(), state = listState, contentPadding = PaddingValues(top = 72.dp)) {
|
||||||
items(
|
items(
|
||||||
items = state.items,
|
items = state.items,
|
||||||
key = { it.id.value },
|
key = { it.id.value },
|
||||||
) {
|
) {
|
||||||
DirectoryItem(it, onClick = navigateToRoom)
|
DirectoryItem(it, onClick = onClick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DirectoryItem(item: Item, onClick: (RoomId) -> Unit) {
|
private fun DirectoryItem(item: Item, onClick: (Item) -> Unit) {
|
||||||
val roomName = item.roomName
|
val roomName = item.roomName
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
.height(IntrinsicSize.Min)
|
.height(IntrinsicSize.Min)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable {
|
.clickable { onClick(item) }
|
||||||
onClick(item.id)
|
) {
|
||||||
}) {
|
|
||||||
Row(Modifier.padding(20.dp)) {
|
Row(Modifier.padding(20.dp)) {
|
||||||
val secondaryText = MaterialTheme.colors.onBackground.copy(alpha = 0.5f)
|
val secondaryText = MaterialTheme.colors.onBackground.copy(alpha = 0.5f)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package app.dapk.st.share
|
package app.dapk.st.share
|
||||||
|
|
||||||
|
import app.dapk.st.core.AndroidUri
|
||||||
import app.dapk.st.matrix.common.AvatarUrl
|
import app.dapk.st.matrix.common.AvatarUrl
|
||||||
import app.dapk.st.matrix.common.RoomId
|
import app.dapk.st.matrix.common.RoomId
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ sealed interface DirectoryScreenState {
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface DirectoryEvent {
|
sealed interface DirectoryEvent {
|
||||||
data class SelectRoom(val item: Item) : DirectoryEvent
|
data class SelectRoom(val item: Item, val uris: List<AndroidUri>) : DirectoryEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Item(val id: RoomId, val roomAvatarUrl: AvatarUrl?, val roomName: String, val members: List<String>)
|
data class Item(val id: RoomId, val roomAvatarUrl: AvatarUrl?, val roomName: String, val members: List<String>)
|
||||||
|
|
|
@ -3,15 +3,10 @@ package app.dapk.st.share
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import app.dapk.st.core.AndroidUri
|
import app.dapk.st.core.AndroidUri
|
||||||
import app.dapk.st.matrix.common.RoomId
|
|
||||||
import app.dapk.st.matrix.message.MessageService
|
|
||||||
import app.dapk.st.matrix.room.RoomService
|
|
||||||
import app.dapk.st.matrix.sync.SyncService
|
|
||||||
import app.dapk.st.viewmodel.DapkViewModel
|
import app.dapk.st.viewmodel.DapkViewModel
|
||||||
import app.dapk.st.viewmodel.MutableStateFactory
|
import app.dapk.st.viewmodel.MutableStateFactory
|
||||||
import app.dapk.st.viewmodel.defaultStateFactory
|
import app.dapk.st.viewmodel.defaultStateFactory
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class ShareEntryViewModel(
|
class ShareEntryViewModel(
|
||||||
|
@ -22,6 +17,7 @@ class ShareEntryViewModel(
|
||||||
factory,
|
factory,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private var urisToShare: List<AndroidUri>? = null
|
||||||
private var syncJob: Job? = null
|
private var syncJob: Job? = null
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
|
@ -34,31 +30,14 @@ class ShareEntryViewModel(
|
||||||
syncJob?.cancel()
|
syncJob?.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun sendAttachment() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun withUris(urisToShare: List<Uri>) {
|
fun withUris(urisToShare: List<Uri>) {
|
||||||
// TODO("Not yet implemented")
|
this.urisToShare = urisToShare.map { AndroidUri(it.toString()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onRoomSelected(item: Item) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
_events.emit(DirectoryEvent.SelectRoom(item, uris = urisToShare ?: throw IllegalArgumentException("Not uris set")))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class FetchRoomsUseCase(
|
|
||||||
private val syncSyncService: SyncService,
|
|
||||||
private val roomService: RoomService,
|
|
||||||
) {
|
|
||||||
|
|
||||||
suspend fun bar(): List<Item> {
|
|
||||||
return syncSyncService.overview().first().map {
|
|
||||||
Item(
|
|
||||||
it.roomId,
|
|
||||||
it.roomAvatarUrl,
|
|
||||||
it.roomName ?: "",
|
|
||||||
roomService.findMembersSummary(it.roomId).map { it.displayName ?: it.id.value }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -14,5 +14,6 @@ enum class EventType(val value: String) {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class MessageType(val value: String) {
|
enum class MessageType(val value: String) {
|
||||||
TEXT("m.text")
|
TEXT("m.text"),
|
||||||
|
IMAGE("m.image"),
|
||||||
}
|
}
|
|
@ -46,6 +46,16 @@ interface MessageService : MatrixService {
|
||||||
@SerialName("timestamp") val timestampUtc: Long,
|
@SerialName("timestamp") val timestampUtc: Long,
|
||||||
) : Message()
|
) : Message()
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("image_message")
|
||||||
|
data class ImageMessage(
|
||||||
|
@SerialName("content") val content: Content.ImageContent,
|
||||||
|
@SerialName("send_encrypted") val sendEncrypted: Boolean,
|
||||||
|
@SerialName("room_id") val roomId: RoomId,
|
||||||
|
@SerialName("local_id") val localId: String,
|
||||||
|
@SerialName("timestamp") val timestampUtc: Long,
|
||||||
|
) : Message()
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
sealed class Content {
|
sealed class Content {
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@ -53,6 +63,12 @@ interface MessageService : MatrixService {
|
||||||
@SerialName("body") val body: String,
|
@SerialName("body") val body: String,
|
||||||
@SerialName("msgtype") val type: String = MessageType.TEXT.value,
|
@SerialName("msgtype") val type: String = MessageType.TEXT.value,
|
||||||
) : Content()
|
) : Content()
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ImageContent(
|
||||||
|
@SerialName("uri") val uri: String,
|
||||||
|
@SerialName("msgtype") val type: String = MessageType.IMAGE.value,
|
||||||
|
) : Content()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,16 +82,19 @@ interface MessageService : MatrixService {
|
||||||
@Transient
|
@Transient
|
||||||
val timestampUtc = when (message) {
|
val timestampUtc = when (message) {
|
||||||
is Message.TextMessage -> message.timestampUtc
|
is Message.TextMessage -> message.timestampUtc
|
||||||
|
is Message.ImageMessage -> message.timestampUtc
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
val roomId = when (message) {
|
val roomId = when (message) {
|
||||||
is Message.TextMessage -> message.roomId
|
is Message.TextMessage -> message.roomId
|
||||||
|
is Message.ImageMessage -> message.roomId
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
val localId = when (message) {
|
val localId = when (message) {
|
||||||
is Message.TextMessage -> message.localId
|
is Message.TextMessage -> message.localId
|
||||||
|
is Message.ImageMessage -> message.localId
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
|
|
@ -13,6 +13,7 @@ import java.net.SocketException
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
|
|
||||||
private const val MATRIX_MESSAGE_TASK_TYPE = "matrix-text-message"
|
private const val MATRIX_MESSAGE_TASK_TYPE = "matrix-text-message"
|
||||||
|
private const val MATRIX_IMAGE_MESSAGE_TASK_TYPE = "matrix-image-message"
|
||||||
|
|
||||||
internal class DefaultMessageService(
|
internal class DefaultMessageService(
|
||||||
httpClient: MatrixHttpClient,
|
httpClient: MatrixHttpClient,
|
||||||
|
@ -50,6 +51,7 @@ internal class DefaultMessageService(
|
||||||
localEchoStore.markSending(message)
|
localEchoStore.markSending(message)
|
||||||
val localId = when (message) {
|
val localId = when (message) {
|
||||||
is MessageService.Message.TextMessage -> message.localId
|
is MessageService.Message.TextMessage -> message.localId
|
||||||
|
is MessageService.Message.ImageMessage -> message.localId
|
||||||
}
|
}
|
||||||
backgroundScheduler.schedule(key = localId, message.toTask())
|
backgroundScheduler.schedule(key = localId, message.toTask())
|
||||||
}
|
}
|
||||||
|
@ -68,6 +70,10 @@ internal class DefaultMessageService(
|
||||||
Json.encodeToString(MessageService.Message.TextMessage.serializer(), this)
|
Json.encodeToString(MessageService.Message.TextMessage.serializer(), this)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
is MessageService.Message.ImageMessage -> BackgroundScheduler.Task(
|
||||||
|
type = MATRIX_IMAGE_MESSAGE_TASK_TYPE,
|
||||||
|
Json.encodeToString(MessageService.Message.ImageMessage.serializer(), this)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,36 @@ internal class SendMessageUseCase(
|
||||||
}
|
}
|
||||||
httpClient.execute(request).eventId
|
httpClient.execute(request).eventId
|
||||||
}
|
}
|
||||||
|
is MessageService.Message.ImageMessage -> {
|
||||||
|
// upload image, then send message
|
||||||
|
// POST /_matrix/media/v3/upload
|
||||||
|
// message.content.uri
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {
|
||||||
|
"content": {
|
||||||
|
"body": "filename.jpg",
|
||||||
|
"info": {
|
||||||
|
"h": 398,
|
||||||
|
"mimetype": "image/jpeg",
|
||||||
|
"size": 31037,
|
||||||
|
"w": 394
|
||||||
|
},
|
||||||
|
"msgtype": "m.image",
|
||||||
|
"url": "mxc://example.org/JWEIFJgwEIhweiWJE"
|
||||||
|
},
|
||||||
|
"event_id": "$143273582443PhrSn:example.org",
|
||||||
|
"origin_server_ts": 1432735824653,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ internal fun sendRequest(roomId: RoomId, eventType: EventType, txId: String, con
|
||||||
method = MatrixHttpClient.Method.PUT,
|
method = MatrixHttpClient.Method.PUT,
|
||||||
body = when (content) {
|
body = when (content) {
|
||||||
is Message.Content.TextContent -> jsonBody(Message.Content.TextContent.serializer(), content, MatrixHttpClient.jsonWithDefaults)
|
is Message.Content.TextContent -> jsonBody(Message.Content.TextContent.serializer(), content, MatrixHttpClient.jsonWithDefaults)
|
||||||
|
is Message.Content.ImageContent -> jsonBody(Message.Content.ImageContent.serializer(), content, MatrixHttpClient.jsonWithDefaults)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,7 @@ class TestMatrix(
|
||||||
val result = serviceProvider.cryptoService().encrypt(
|
val result = serviceProvider.cryptoService().encrypt(
|
||||||
roomId = when (message) {
|
roomId = when (message) {
|
||||||
is MessageService.Message.TextMessage -> message.roomId
|
is MessageService.Message.TextMessage -> message.roomId
|
||||||
|
is MessageService.Message.ImageMessage -> message.roomId
|
||||||
},
|
},
|
||||||
credentials = storeModule.credentialsStore().credentials()!!,
|
credentials = storeModule.credentialsStore().credentials()!!,
|
||||||
when (message) {
|
when (message) {
|
||||||
|
@ -128,6 +129,7 @@ class TestMatrix(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
is MessageService.Message.ImageMessage -> TODO()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue