mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 10:25:35 +03:00
Widget: handle sticker
This commit is contained in:
parent
dbe4c0c8e4
commit
4b37ede8c2
34 changed files with 384 additions and 277 deletions
|
@ -18,9 +18,28 @@ package im.vector.matrix.android.api.session.integrationmanager
|
||||||
|
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
|
import im.vector.matrix.android.internal.session.integrationmanager.IntegrationManager
|
||||||
|
|
||||||
interface IntegrationManagerService {
|
interface IntegrationManagerService {
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun onIsEnabledChanged(enabled: Boolean) {
|
||||||
|
//No-op
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onConfigurationChanged(config: IntegrationManagerConfig) {
|
||||||
|
//No-op
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onWidgetPermissionsChanged(widgets: Map<String, Boolean>) {
|
||||||
|
//No-op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addListener(listener: Listener)
|
||||||
|
|
||||||
|
fun removeListener(listener: Listener)
|
||||||
|
|
||||||
fun getOrderedConfigs(): List<IntegrationManagerConfig>
|
fun getOrderedConfigs(): List<IntegrationManagerConfig>
|
||||||
|
|
||||||
fun getPreferredConfig(): IntegrationManagerConfig
|
fun getPreferredConfig(): IntegrationManagerConfig
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package im.vector.matrix.android.api.session.room.send
|
package im.vector.matrix.android.api.session.room.send
|
||||||
|
|
||||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||||
|
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.message.MessageType
|
import im.vector.matrix.android.api.session.room.model.message.MessageType
|
||||||
import im.vector.matrix.android.api.session.room.model.message.OptionItem
|
import im.vector.matrix.android.api.session.room.model.message.OptionItem
|
||||||
|
@ -28,6 +29,14 @@ import im.vector.matrix.android.api.util.Cancelable
|
||||||
*/
|
*/
|
||||||
interface SendService {
|
interface SendService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to send a generic event asynchronously. If you want to send a state event, please use [StateService] instead.
|
||||||
|
* @param eventType the type of the event
|
||||||
|
* @param content the optional body as a json dict.
|
||||||
|
* @return a [Cancelable]
|
||||||
|
*/
|
||||||
|
fun sendEvent(eventType: String, content: Content?): Cancelable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to send a text message asynchronously.
|
* Method to send a text message asynchronously.
|
||||||
* The text to send can be a Spannable and contains special spans (MatrixItemSpan) that will be translated
|
* The text to send can be a Spannable and contains special spans (MatrixItemSpan) that will be translated
|
||||||
|
|
|
@ -24,6 +24,14 @@ import javax.inject.Inject
|
||||||
|
|
||||||
internal class DefaultIntegrationManagerService @Inject constructor(private val integrationManager: IntegrationManager) : IntegrationManagerService {
|
internal class DefaultIntegrationManagerService @Inject constructor(private val integrationManager: IntegrationManager) : IntegrationManagerService {
|
||||||
|
|
||||||
|
override fun addListener(listener: IntegrationManagerService.Listener) {
|
||||||
|
integrationManager.addListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeListener(listener: IntegrationManagerService.Listener) {
|
||||||
|
integrationManager.removeListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getOrderedConfigs(): List<IntegrationManagerConfig> {
|
override fun getOrderedConfigs(): List<IntegrationManagerConfig> {
|
||||||
return integrationManager.getOrderedConfigs()
|
return integrationManager.getOrderedConfigs()
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import im.vector.matrix.android.R
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
import im.vector.matrix.android.api.session.integrationmanager.IntegrationManagerConfig
|
import im.vector.matrix.android.api.session.integrationmanager.IntegrationManagerConfig
|
||||||
|
import im.vector.matrix.android.api.session.integrationmanager.IntegrationManagerService
|
||||||
import im.vector.matrix.android.api.session.widgets.model.WidgetContent
|
import im.vector.matrix.android.api.session.widgets.model.WidgetContent
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
import im.vector.matrix.android.api.util.NoOpCancellable
|
import im.vector.matrix.android.api.util.NoOpCancellable
|
||||||
|
@ -59,27 +60,14 @@ internal class IntegrationManager @Inject constructor(private val taskExecutor:
|
||||||
private val accountDataDataSource: AccountDataDataSource,
|
private val accountDataDataSource: AccountDataDataSource,
|
||||||
private val configExtractor: IntegrationManagerConfigExtractor) {
|
private val configExtractor: IntegrationManagerConfigExtractor) {
|
||||||
|
|
||||||
interface Listener {
|
|
||||||
fun onIsEnabledChanged(enabled: Boolean) {
|
|
||||||
//No-op
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onConfigurationChanged(config: IntegrationManagerConfig) {
|
|
||||||
//No-op
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onWidgetPermissionsChanged(widgets: Map<String, Boolean>) {
|
|
||||||
//No-op
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val currentConfigs = ArrayList<IntegrationManagerConfig>()
|
private val currentConfigs = ArrayList<IntegrationManagerConfig>()
|
||||||
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry }
|
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry }
|
||||||
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner)
|
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner)
|
||||||
|
|
||||||
private val listeners = HashSet<Listener>()
|
private val listeners = HashSet<IntegrationManagerService.Listener>()
|
||||||
fun addListener(listener: Listener) = synchronized(listeners) { listeners.add(listener) }
|
fun addListener(listener: IntegrationManagerService.Listener) = synchronized(listeners) { listeners.add(listener) }
|
||||||
fun removeListener(listener: Listener) = synchronized(listeners) { listeners.remove(listener) }
|
fun removeListener(listener: IntegrationManagerService.Listener) = synchronized(listeners) { listeners.remove(listener) }
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val defaultConfig = IntegrationManagerConfig(
|
val defaultConfig = IntegrationManagerConfig(
|
||||||
|
|
|
@ -33,6 +33,7 @@ import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
import im.vector.matrix.android.api.util.CancelableBag
|
import im.vector.matrix.android.api.util.CancelableBag
|
||||||
|
import im.vector.matrix.android.api.util.JsonDict
|
||||||
import im.vector.matrix.android.internal.di.SessionId
|
import im.vector.matrix.android.internal.di.SessionId
|
||||||
import im.vector.matrix.android.internal.di.WorkManagerProvider
|
import im.vector.matrix.android.internal.di.WorkManagerProvider
|
||||||
import im.vector.matrix.android.internal.session.content.UploadContentWorker
|
import im.vector.matrix.android.internal.session.content.UploadContentWorker
|
||||||
|
@ -67,6 +68,12 @@ internal class DefaultSendService @AssistedInject constructor(
|
||||||
|
|
||||||
private val workerFutureListenerExecutor = Executors.newSingleThreadExecutor()
|
private val workerFutureListenerExecutor = Executors.newSingleThreadExecutor()
|
||||||
|
|
||||||
|
override fun sendEvent(eventType: String, content: JsonDict?): Cancelable {
|
||||||
|
return localEchoEventFactory.createEvent(roomId, eventType, content)
|
||||||
|
.also { createLocalEcho(it) }
|
||||||
|
.let { sendEvent(it) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun sendTextMessage(text: CharSequence, msgType: String, autoMarkdown: Boolean): Cancelable {
|
override fun sendTextMessage(text: CharSequence, msgType: String, autoMarkdown: Boolean): Cancelable {
|
||||||
return localEchoEventFactory.createTextEvent(roomId, msgType, text, autoMarkdown)
|
return localEchoEventFactory.createTextEvent(roomId, msgType, text, autoMarkdown)
|
||||||
.also { createLocalEcho(it) }
|
.also { createLocalEcho(it) }
|
||||||
|
|
|
@ -23,6 +23,7 @@ import androidx.exifinterface.media.ExifInterface
|
||||||
import im.vector.matrix.android.R
|
import im.vector.matrix.android.R
|
||||||
import im.vector.matrix.android.api.permalinks.PermalinkFactory
|
import im.vector.matrix.android.api.permalinks.PermalinkFactory
|
||||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||||
|
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.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.events.model.LocalEcho
|
import im.vector.matrix.android.api.session.events.model.LocalEcho
|
||||||
|
@ -56,6 +57,7 @@ import im.vector.matrix.android.api.session.room.model.relation.RelationDefaultC
|
||||||
import im.vector.matrix.android.api.session.room.model.relation.ReplyToContent
|
import im.vector.matrix.android.api.session.room.model.relation.ReplyToContent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent
|
import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent
|
||||||
|
import im.vector.matrix.android.api.util.JsonDict
|
||||||
import im.vector.matrix.android.internal.di.UserId
|
import im.vector.matrix.android.internal.di.UserId
|
||||||
import im.vector.matrix.android.internal.extensions.subStringBetween
|
import im.vector.matrix.android.internal.extensions.subStringBetween
|
||||||
import im.vector.matrix.android.internal.session.content.ThumbnailExtractor
|
import im.vector.matrix.android.internal.session.content.ThumbnailExtractor
|
||||||
|
@ -95,7 +97,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
return createFormattedTextEvent(roomId, createTextContent(text, autoMarkdown), msgType)
|
return createFormattedTextEvent(roomId, createTextContent(text, autoMarkdown), msgType)
|
||||||
}
|
}
|
||||||
val content = MessageTextContent(msgType = msgType, body = text.toString())
|
val content = MessageTextContent(msgType = msgType, body = text.toString())
|
||||||
return createEvent(roomId, content)
|
return createMessageEvent(roomId, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createTextContent(text: CharSequence, autoMarkdown: Boolean): TextContent {
|
private fun createTextContent(text: CharSequence, autoMarkdown: Boolean): TextContent {
|
||||||
|
@ -129,7 +131,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
text != htmlText && htmlText != "<p>${text.trim()}</p>\n"
|
text != htmlText && htmlText != "<p>${text.trim()}</p>\n"
|
||||||
|
|
||||||
fun createFormattedTextEvent(roomId: String, textContent: TextContent, msgType: String): Event {
|
fun createFormattedTextEvent(roomId: String, textContent: TextContent, msgType: String): Event {
|
||||||
return createEvent(roomId, textContent.toMessageTextContent(msgType))
|
return createMessageEvent(roomId, textContent.toMessageTextContent(msgType))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createReplaceTextEvent(roomId: String,
|
fun createReplaceTextEvent(roomId: String,
|
||||||
|
@ -138,7 +140,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
newBodyAutoMarkdown: Boolean,
|
newBodyAutoMarkdown: Boolean,
|
||||||
msgType: String,
|
msgType: String,
|
||||||
compatibilityText: String): Event {
|
compatibilityText: String): Event {
|
||||||
return createEvent(roomId,
|
return createMessageEvent(roomId,
|
||||||
MessageTextContent(
|
MessageTextContent(
|
||||||
msgType = msgType,
|
msgType = msgType,
|
||||||
body = compatibilityText,
|
body = compatibilityText,
|
||||||
|
@ -153,7 +155,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
pollEventId: String,
|
pollEventId: String,
|
||||||
optionIndex: Int,
|
optionIndex: Int,
|
||||||
optionLabel: String): Event {
|
optionLabel: String): Event {
|
||||||
return createEvent(roomId,
|
return createMessageEvent(roomId,
|
||||||
MessagePollResponseContent(
|
MessagePollResponseContent(
|
||||||
body = optionLabel,
|
body = optionLabel,
|
||||||
relatesTo = RelationDefaultContent(
|
relatesTo = RelationDefaultContent(
|
||||||
|
@ -175,7 +177,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
append(it.value)
|
append(it.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return createEvent(
|
return createMessageEvent(
|
||||||
roomId,
|
roomId,
|
||||||
MessageOptionsContent(
|
MessageOptionsContent(
|
||||||
body = compatLabel,
|
body = compatLabel,
|
||||||
|
@ -211,7 +213,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
//
|
//
|
||||||
val replyFallback = buildReplyFallback(body, originalEvent.root.senderId ?: "", newBodyText)
|
val replyFallback = buildReplyFallback(body, originalEvent.root.senderId ?: "", newBodyText)
|
||||||
|
|
||||||
return createEvent(roomId,
|
return createMessageEvent(roomId,
|
||||||
MessageTextContent(
|
MessageTextContent(
|
||||||
msgType = msgType,
|
msgType = msgType,
|
||||||
body = compatibilityText,
|
body = compatibilityText,
|
||||||
|
@ -280,7 +282,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
),
|
),
|
||||||
url = attachment.queryUri.toString()
|
url = attachment.queryUri.toString()
|
||||||
)
|
)
|
||||||
return createEvent(roomId, content)
|
return createMessageEvent(roomId, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createVideoEvent(roomId: String, attachment: ContentAttachmentData): Event {
|
private fun createVideoEvent(roomId: String, attachment: ContentAttachmentData): Event {
|
||||||
|
@ -316,7 +318,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
),
|
),
|
||||||
url = attachment.queryUri.toString()
|
url = attachment.queryUri.toString()
|
||||||
)
|
)
|
||||||
return createEvent(roomId, content)
|
return createMessageEvent(roomId, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createAudioEvent(roomId: String, attachment: ContentAttachmentData): Event {
|
private fun createAudioEvent(roomId: String, attachment: ContentAttachmentData): Event {
|
||||||
|
@ -329,7 +331,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
),
|
),
|
||||||
url = attachment.queryUri.toString()
|
url = attachment.queryUri.toString()
|
||||||
)
|
)
|
||||||
return createEvent(roomId, content)
|
return createMessageEvent(roomId, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createFileEvent(roomId: String, attachment: ContentAttachmentData): Event {
|
private fun createFileEvent(roomId: String, attachment: ContentAttachmentData): Event {
|
||||||
|
@ -342,18 +344,22 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
),
|
),
|
||||||
url = attachment.queryUri.toString()
|
url = attachment.queryUri.toString()
|
||||||
)
|
)
|
||||||
return createEvent(roomId, content)
|
return createMessageEvent(roomId, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createEvent(roomId: String, content: Any? = null): Event {
|
private fun createMessageEvent(roomId: String, content: Any? = null): Event {
|
||||||
|
return createEvent(roomId, EventType.MESSAGE, content.toContent())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createEvent(roomId: String, type: String, content: Content?): Event {
|
||||||
val localId = LocalEcho.createLocalEchoId()
|
val localId = LocalEcho.createLocalEchoId()
|
||||||
return Event(
|
return Event(
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
originServerTs = dummyOriginServerTs(),
|
originServerTs = dummyOriginServerTs(),
|
||||||
senderId = userId,
|
senderId = userId,
|
||||||
eventId = localId,
|
eventId = localId,
|
||||||
type = EventType.MESSAGE,
|
type = type,
|
||||||
content = content.toContent(),
|
content = content,
|
||||||
unsignedData = UnsignedData(age = null, transactionId = localId)
|
unsignedData = UnsignedData(age = null, transactionId = localId)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -410,7 +416,7 @@ internal class LocalEchoEventFactory @Inject constructor(
|
||||||
formattedBody = replyFormatted,
|
formattedBody = replyFormatted,
|
||||||
relatesTo = RelationDefaultContent(null, null, ReplyToContent(eventId))
|
relatesTo = RelationDefaultContent(null, null, ReplyToContent(eventId))
|
||||||
)
|
)
|
||||||
return createEvent(roomId, content)
|
return createMessageEvent(roomId, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildReplyFallback(body: TextContent, originalSenderId: String?, newBodyText: String): String {
|
private fun buildReplyFallback(body: TextContent, originalSenderId: String?, newBodyText: String): String {
|
||||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.widgets
|
||||||
|
|
||||||
import im.vector.matrix.android.R
|
import im.vector.matrix.android.R
|
||||||
import im.vector.matrix.android.api.session.integrationmanager.IntegrationManagerConfig
|
import im.vector.matrix.android.api.session.integrationmanager.IntegrationManagerConfig
|
||||||
|
import im.vector.matrix.android.api.session.integrationmanager.IntegrationManagerService
|
||||||
import im.vector.matrix.android.api.session.widgets.WidgetURLFormatter
|
import im.vector.matrix.android.api.session.widgets.WidgetURLFormatter
|
||||||
import im.vector.matrix.android.internal.session.SessionScope
|
import im.vector.matrix.android.internal.session.SessionScope
|
||||||
import im.vector.matrix.android.internal.session.integrationmanager.IntegrationManager
|
import im.vector.matrix.android.internal.session.integrationmanager.IntegrationManager
|
||||||
|
@ -30,9 +31,9 @@ import javax.inject.Inject
|
||||||
internal class DefaultWidgetURLFormatter @Inject constructor(private val integrationManager: IntegrationManager,
|
internal class DefaultWidgetURLFormatter @Inject constructor(private val integrationManager: IntegrationManager,
|
||||||
private val getScalarTokenTask: GetScalarTokenTask,
|
private val getScalarTokenTask: GetScalarTokenTask,
|
||||||
private val stringProvider: StringProvider
|
private val stringProvider: StringProvider
|
||||||
) : IntegrationManager.Listener, WidgetURLFormatter {
|
) : IntegrationManagerService.Listener, WidgetURLFormatter {
|
||||||
|
|
||||||
private var currentConfig = integrationManager.getPreferredConfig()
|
private lateinit var currentConfig: IntegrationManagerConfig
|
||||||
private var whiteListedUrls: List<String> = emptyList()
|
private var whiteListedUrls: List<String> = emptyList()
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
|
@ -50,7 +51,7 @@ internal class DefaultWidgetURLFormatter @Inject constructor(private val integra
|
||||||
|
|
||||||
private fun setupWithConfiguration() {
|
private fun setupWithConfiguration() {
|
||||||
val preferredConfig = integrationManager.getPreferredConfig()
|
val preferredConfig = integrationManager.getPreferredConfig()
|
||||||
if (currentConfig != preferredConfig) {
|
if (!this::currentConfig.isInitialized || preferredConfig != currentConfig) {
|
||||||
currentConfig = preferredConfig
|
currentConfig = preferredConfig
|
||||||
val defaultWhiteList = stringProvider.getStringArray(R.array.integrations_widgets_urls).asList()
|
val defaultWhiteList = stringProvider.getStringArray(R.array.integrations_widgets_urls).asList()
|
||||||
whiteListedUrls = when (preferredConfig.kind) {
|
whiteListedUrls = when (preferredConfig.kind) {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.widgets.model.WidgetContent
|
||||||
|
|
||||||
data class Widget(
|
data class Widget(
|
||||||
val widgetContent: WidgetContent,
|
val widgetContent: WidgetContent,
|
||||||
val event: Event? = null
|
val event: Event? = null,
|
||||||
|
val widgetId: String? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -21,16 +21,16 @@ import javax.inject.Inject
|
||||||
|
|
||||||
internal class WidgetDependenciesHolder @Inject constructor(private val integrationManager: IntegrationManager,
|
internal class WidgetDependenciesHolder @Inject constructor(private val integrationManager: IntegrationManager,
|
||||||
private val widgetManager: WidgetManager,
|
private val widgetManager: WidgetManager,
|
||||||
private val widgetURLBuilder: DefaultWidgetURLFormatter) {
|
private val widgetURLFormatter: DefaultWidgetURLFormatter) {
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
integrationManager.start()
|
integrationManager.start()
|
||||||
widgetManager.start()
|
widgetManager.start()
|
||||||
widgetURLBuilder.start()
|
widgetURLFormatter.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stop() {
|
fun stop() {
|
||||||
widgetURLBuilder.stop()
|
widgetURLFormatter.stop()
|
||||||
widgetManager.stop()
|
widgetManager.stop()
|
||||||
integrationManager.stop()
|
integrationManager.stop()
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ 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.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
|
import im.vector.matrix.android.api.session.integrationmanager.IntegrationManagerService
|
||||||
import im.vector.matrix.android.api.session.room.model.PowerLevelsContent
|
import im.vector.matrix.android.api.session.room.model.PowerLevelsContent
|
||||||
import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper
|
import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper
|
||||||
import im.vector.matrix.android.api.session.widgets.WidgetService
|
import im.vector.matrix.android.api.session.widgets.WidgetService
|
||||||
|
@ -51,7 +52,7 @@ internal class WidgetManager @Inject constructor(private val integrationManager:
|
||||||
private val stateEventDataSource: StateEventDataSource,
|
private val stateEventDataSource: StateEventDataSource,
|
||||||
private val taskExecutor: TaskExecutor,
|
private val taskExecutor: TaskExecutor,
|
||||||
private val createWidgetTask: CreateWidgetTask,
|
private val createWidgetTask: CreateWidgetTask,
|
||||||
@UserId private val userId: String) : IntegrationManager.Listener {
|
@UserId private val userId: String) : IntegrationManagerService.Listener {
|
||||||
|
|
||||||
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry }
|
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry }
|
||||||
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner)
|
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner)
|
||||||
|
@ -114,7 +115,7 @@ internal class WidgetManager @Inject constructor(private val integrationManager:
|
||||||
}
|
}
|
||||||
// widgetEvent.stateKey = widget id
|
// widgetEvent.stateKey = widget id
|
||||||
if (widgetEvent.stateKey != null && !widgets.containsKey(widgetEvent.stateKey)) {
|
if (widgetEvent.stateKey != null && !widgets.containsKey(widgetEvent.stateKey)) {
|
||||||
val widget = Widget(widgetContent, widgetEvent)
|
val widget = Widget(widgetContent, widgetEvent, widgetEvent.stateKey)
|
||||||
widgets[widgetEvent.stateKey] = widget
|
widgets[widgetEvent.stateKey] = widget
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ internal fun UserAccountDataEvent.extractWidgetSequence(): Sequence<Widget> {
|
||||||
if (content == null) {
|
if (content == null) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
Widget(content, event)
|
Widget(content, event, event.stateKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,8 +102,7 @@ import im.vector.riotx.features.signout.soft.SoftLogoutFragment
|
||||||
import im.vector.riotx.features.terms.ReviewTermsFragment
|
import im.vector.riotx.features.terms.ReviewTermsFragment
|
||||||
import im.vector.riotx.features.userdirectory.KnownUsersFragment
|
import im.vector.riotx.features.userdirectory.KnownUsersFragment
|
||||||
import im.vector.riotx.features.userdirectory.UserDirectoryFragment
|
import im.vector.riotx.features.userdirectory.UserDirectoryFragment
|
||||||
import im.vector.riotx.features.widgets.admin.AdminWidgetFragment
|
import im.vector.riotx.features.widgets.WidgetFragment
|
||||||
import im.vector.riotx.features.widgets.room.RoomWidgetFragment
|
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
interface FragmentModule {
|
interface FragmentModule {
|
||||||
|
@ -515,11 +514,7 @@ interface FragmentModule {
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@FragmentKey(RoomWidgetFragment::class)
|
@FragmentKey(WidgetFragment::class)
|
||||||
fun bindRoomWidgetFragment(fragment: RoomWidgetFragment): Fragment
|
fun bindWidgetFragment(fragment: WidgetFragment): Fragment
|
||||||
|
|
||||||
@Binds
|
|
||||||
@IntoMap
|
|
||||||
@FragmentKey(AdminWidgetFragment::class)
|
|
||||||
fun bindAdminWidgetFragment(fragment: AdminWidgetFragment): Fragment
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package im.vector.riotx.features.attachments
|
package im.vector.riotx.features.attachments
|
||||||
|
|
||||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageStickerContent
|
||||||
import im.vector.riotx.multipicker.entity.MultiPickerAudioType
|
import im.vector.riotx.multipicker.entity.MultiPickerAudioType
|
||||||
import im.vector.riotx.multipicker.entity.MultiPickerBaseType
|
import im.vector.riotx.multipicker.entity.MultiPickerBaseType
|
||||||
import im.vector.riotx.multipicker.entity.MultiPickerContactType
|
import im.vector.riotx.multipicker.entity.MultiPickerContactType
|
||||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.riotx.features.home.room.detail
|
||||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
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.model.message.MessageFileContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageFileContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageStickerContent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||||
|
@ -26,6 +27,7 @@ import im.vector.riotx.core.platform.VectorViewModelAction
|
||||||
sealed class RoomDetailAction : VectorViewModelAction {
|
sealed class RoomDetailAction : VectorViewModelAction {
|
||||||
data class UserIsTyping(val isTyping: Boolean) : RoomDetailAction()
|
data class UserIsTyping(val isTyping: Boolean) : RoomDetailAction()
|
||||||
data class SaveDraft(val draft: String) : RoomDetailAction()
|
data class SaveDraft(val draft: String) : RoomDetailAction()
|
||||||
|
data class SendSticker(val stickerContent: MessageStickerContent) : RoomDetailAction()
|
||||||
data class SendMessage(val text: CharSequence, val autoMarkdown: Boolean) : RoomDetailAction()
|
data class SendMessage(val text: CharSequence, val autoMarkdown: Boolean) : RoomDetailAction()
|
||||||
data class SendMedia(val attachments: List<ContentAttachmentData>, val compressBeforeSending: Boolean) : RoomDetailAction()
|
data class SendMedia(val attachments: List<ContentAttachmentData>, val compressBeforeSending: Boolean) : RoomDetailAction()
|
||||||
data class TimelineEventTurnsVisible(val event: TimelineEvent) : RoomDetailAction()
|
data class TimelineEventTurnsVisible(val event: TimelineEvent) : RoomDetailAction()
|
||||||
|
@ -72,4 +74,6 @@ sealed class RoomDetailAction : VectorViewModelAction {
|
||||||
data class RequestVerification(val userId: String) : RoomDetailAction()
|
data class RequestVerification(val userId: String) : RoomDetailAction()
|
||||||
data class ResumeVerification(val transactionId: String, val otherUserId: String?) : RoomDetailAction()
|
data class ResumeVerification(val transactionId: String, val otherUserId: String?) : RoomDetailAction()
|
||||||
data class ReRequestKeys(val eventId: String) : RoomDetailAction()
|
data class ReRequestKeys(val eventId: String) : RoomDetailAction()
|
||||||
|
|
||||||
|
object SelectStickerAttachment : RoomDetailAction()
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import android.os.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.text.Spannable
|
import android.text.Spannable
|
||||||
import android.view.HapticFeedbackConstants
|
import android.view.HapticFeedbackConstants
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -65,6 +66,7 @@ import im.vector.matrix.android.api.permalinks.PermalinkFactory
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
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.toModel
|
||||||
import im.vector.matrix.android.api.session.file.FileService
|
import im.vector.matrix.android.api.session.file.FileService
|
||||||
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.message.MessageAudioContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageAudioContent
|
||||||
|
@ -72,6 +74,7 @@ import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageFileContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageFileContent
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageFormat
|
import im.vector.matrix.android.api.session.room.model.message.MessageFormat
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageImageInfoContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageImageInfoContent
|
||||||
|
import im.vector.matrix.android.api.session.room.model.message.MessageStickerContent
|
||||||
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.MessageVerificationRequestContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageVerificationRequestContent
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
|
||||||
|
@ -131,6 +134,7 @@ import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
|
||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
import im.vector.riotx.features.home.room.detail.composer.TextComposerView
|
import im.vector.riotx.features.home.room.detail.composer.TextComposerView
|
||||||
import im.vector.riotx.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet
|
import im.vector.riotx.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet
|
||||||
|
import im.vector.riotx.features.home.room.detail.sticker.StickerPickerConstants
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.action.EventSharedAction
|
import im.vector.riotx.features.home.room.detail.timeline.action.EventSharedAction
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.action.MessageActionsBottomSheet
|
import im.vector.riotx.features.home.room.detail.timeline.action.MessageActionsBottomSheet
|
||||||
|
@ -155,6 +159,7 @@ import im.vector.riotx.features.reactions.EmojiReactionPickerActivity
|
||||||
import im.vector.riotx.features.settings.VectorPreferences
|
import im.vector.riotx.features.settings.VectorPreferences
|
||||||
import im.vector.riotx.features.share.SharedData
|
import im.vector.riotx.features.share.SharedData
|
||||||
import im.vector.riotx.features.themes.ThemeUtils
|
import im.vector.riotx.features.themes.ThemeUtils
|
||||||
|
import im.vector.riotx.features.widgets.WidgetActivity
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
@ -300,10 +305,37 @@ class RoomDetailFragment @Inject constructor(
|
||||||
is RoomDetailViewEvents.DownloadFileState -> handleDownloadFileState(it)
|
is RoomDetailViewEvents.DownloadFileState -> handleDownloadFileState(it)
|
||||||
is RoomDetailViewEvents.JoinRoomCommandSuccess -> handleJoinedToAnotherRoom(it)
|
is RoomDetailViewEvents.JoinRoomCommandSuccess -> handleJoinedToAnotherRoom(it)
|
||||||
is RoomDetailViewEvents.SendMessageResult -> renderSendMessageResult(it)
|
is RoomDetailViewEvents.SendMessageResult -> renderSendMessageResult(it)
|
||||||
|
RoomDetailViewEvents.DisplayPromptForIntegrationManager -> displayPromptForIntegrationManager()
|
||||||
|
is RoomDetailViewEvents.OpenStickerPicker -> openStickerPicker(it)
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun openStickerPicker(event: RoomDetailViewEvents.OpenStickerPicker) {
|
||||||
|
navigator.openStickerPicker(this, roomDetailArgs.roomId, event.widget)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun displayPromptForIntegrationManager() {
|
||||||
|
// The Sticker picker widget is not installed yet. Propose the user to install it
|
||||||
|
val builder = AlertDialog.Builder(requireContext())
|
||||||
|
// Use the builder context
|
||||||
|
// Use the builder context
|
||||||
|
val v: View = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_no_sticker_pack, null)
|
||||||
|
builder
|
||||||
|
.setView(v)
|
||||||
|
.setPositiveButton(R.string.yes) { _, _->
|
||||||
|
// Open integration manager, to the sticker installation page
|
||||||
|
navigator.openIntegrationManager(
|
||||||
|
context = requireContext(),
|
||||||
|
roomId = roomDetailArgs.roomId,
|
||||||
|
integId = null,
|
||||||
|
screenId = "type_${StickerPickerConstants.WIDGET_NAME}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.no, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleJoinedToAnotherRoom(action: RoomDetailViewEvents.JoinRoomCommandSuccess) {
|
private fun handleJoinedToAnotherRoom(action: RoomDetailViewEvents.JoinRoomCommandSuccess) {
|
||||||
updateComposerText("")
|
updateComposerText("")
|
||||||
lockSendButton = false
|
lockSendButton = false
|
||||||
|
@ -530,6 +562,10 @@ class RoomDetailFragment @Inject constructor(
|
||||||
val (eventId, reaction) = EmojiReactionPickerActivity.getOutput(data) ?: return
|
val (eventId, reaction) = EmojiReactionPickerActivity.getOutput(data) ?: return
|
||||||
roomDetailViewModel.handle(RoomDetailAction.SendReaction(eventId, reaction))
|
roomDetailViewModel.handle(RoomDetailAction.SendReaction(eventId, reaction))
|
||||||
}
|
}
|
||||||
|
StickerPickerConstants.STICKER_PICKER_REQUEST_CODE -> {
|
||||||
|
val content = WidgetActivity.getOutput(data).toModel<MessageStickerContent>() ?: return
|
||||||
|
roomDetailViewModel.handle(RoomDetailAction.SendSticker(content))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1386,7 +1422,7 @@ class RoomDetailFragment @Inject constructor(
|
||||||
AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(this)
|
AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(this)
|
||||||
AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(this)
|
AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(this)
|
||||||
AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(this)
|
AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(this)
|
||||||
AttachmentTypeSelectorView.Type.STICKER -> vectorBaseActivity.notImplemented("Adding stickers")
|
AttachmentTypeSelectorView.Type.STICKER -> roomDetailViewModel.handle(RoomDetailAction.SelectStickerAttachment)
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package im.vector.riotx.features.home.room.detail
|
package im.vector.riotx.features.home.room.detail
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import im.vector.matrix.android.internal.session.widgets.Widget
|
||||||
import im.vector.riotx.core.platform.VectorViewEvents
|
import im.vector.riotx.core.platform.VectorViewEvents
|
||||||
import im.vector.riotx.features.command.Command
|
import im.vector.riotx.features.command.Command
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -49,6 +50,10 @@ sealed class RoomDetailViewEvents : VectorViewEvents {
|
||||||
|
|
||||||
abstract class SendMessageResult : RoomDetailViewEvents()
|
abstract class SendMessageResult : RoomDetailViewEvents()
|
||||||
|
|
||||||
|
object DisplayPromptForIntegrationManager: RoomDetailViewEvents()
|
||||||
|
|
||||||
|
data class OpenStickerPicker(val widget: Widget): RoomDetailViewEvents()
|
||||||
|
|
||||||
object MessageSent : SendMessageResult()
|
object MessageSent : SendMessageResult()
|
||||||
data class JoinRoomCommandSuccess(val roomId: String) : SendMessageResult()
|
data class JoinRoomCommandSuccess(val roomId: String) : SendMessageResult()
|
||||||
class SlashCommandError(val command: Command) : SendMessageResult()
|
class SlashCommandError(val command: Command) : SendMessageResult()
|
||||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.riotx.features.home.room.detail
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.annotation.IdRes
|
import androidx.annotation.IdRes
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.airbnb.mvrx.FragmentViewModelContext
|
import com.airbnb.mvrx.FragmentViewModelContext
|
||||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
|
@ -34,6 +35,7 @@ import im.vector.matrix.android.api.session.Session
|
||||||
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.isImageMessage
|
import im.vector.matrix.android.api.session.events.model.isImageMessage
|
||||||
import im.vector.matrix.android.api.session.events.model.isTextMessage
|
import im.vector.matrix.android.api.session.events.model.isTextMessage
|
||||||
|
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.events.model.toModel
|
||||||
import im.vector.matrix.android.api.session.file.FileService
|
import im.vector.matrix.android.api.session.file.FileService
|
||||||
import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilities
|
import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilities
|
||||||
|
@ -67,6 +69,7 @@ import im.vector.riotx.features.command.CommandParser
|
||||||
import im.vector.riotx.features.command.ParsedCommand
|
import im.vector.riotx.features.command.ParsedCommand
|
||||||
import im.vector.riotx.features.crypto.verification.SupportedVerificationMethodsProvider
|
import im.vector.riotx.features.crypto.verification.SupportedVerificationMethodsProvider
|
||||||
import im.vector.riotx.features.home.room.detail.composer.rainbow.RainbowGenerator
|
import im.vector.riotx.features.home.room.detail.composer.rainbow.RainbowGenerator
|
||||||
|
import im.vector.riotx.features.home.room.detail.sticker.StickerPickerActionHandler
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDisplayableEvents
|
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDisplayableEvents
|
||||||
import im.vector.riotx.features.home.room.typing.TypingHelper
|
import im.vector.riotx.features.home.room.typing.TypingHelper
|
||||||
import im.vector.riotx.features.settings.VectorPreferences
|
import im.vector.riotx.features.settings.VectorPreferences
|
||||||
|
@ -74,6 +77,7 @@ import io.reactivex.Observable
|
||||||
import io.reactivex.functions.BiFunction
|
import io.reactivex.functions.BiFunction
|
||||||
import io.reactivex.rxkotlin.subscribeBy
|
import io.reactivex.rxkotlin.subscribeBy
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.commonmark.parser.Parser
|
import org.commonmark.parser.Parser
|
||||||
import org.commonmark.renderer.html.HtmlRenderer
|
import org.commonmark.renderer.html.HtmlRenderer
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
@ -89,7 +93,8 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||||
private val typingHelper: TypingHelper,
|
private val typingHelper: TypingHelper,
|
||||||
private val rainbowGenerator: RainbowGenerator,
|
private val rainbowGenerator: RainbowGenerator,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider
|
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider,
|
||||||
|
private val stickerPickerActionHandler: StickerPickerActionHandler
|
||||||
) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState), Timeline.Listener {
|
) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState), Timeline.Listener {
|
||||||
|
|
||||||
private val room = session.getRoom(initialState.roomId)!!
|
private val room = session.getRoom(initialState.roomId)!!
|
||||||
|
@ -183,6 +188,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||||
is RoomDetailAction.SaveDraft -> handleSaveDraft(action)
|
is RoomDetailAction.SaveDraft -> handleSaveDraft(action)
|
||||||
is RoomDetailAction.SendMessage -> handleSendMessage(action)
|
is RoomDetailAction.SendMessage -> handleSendMessage(action)
|
||||||
is RoomDetailAction.SendMedia -> handleSendMedia(action)
|
is RoomDetailAction.SendMedia -> handleSendMedia(action)
|
||||||
|
is RoomDetailAction.SendSticker -> handleSendSticker(action)
|
||||||
is RoomDetailAction.TimelineEventTurnsVisible -> handleEventVisible(action)
|
is RoomDetailAction.TimelineEventTurnsVisible -> handleEventVisible(action)
|
||||||
is RoomDetailAction.TimelineEventTurnsInvisible -> handleEventInvisible(action)
|
is RoomDetailAction.TimelineEventTurnsInvisible -> handleEventInvisible(action)
|
||||||
is RoomDetailAction.LoadMoreTimelineEvents -> handleLoadMore(action)
|
is RoomDetailAction.LoadMoreTimelineEvents -> handleLoadMore(action)
|
||||||
|
@ -214,6 +220,18 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||||
is RoomDetailAction.RequestVerification -> handleRequestVerification(action)
|
is RoomDetailAction.RequestVerification -> handleRequestVerification(action)
|
||||||
is RoomDetailAction.ResumeVerification -> handleResumeRequestVerification(action)
|
is RoomDetailAction.ResumeVerification -> handleResumeRequestVerification(action)
|
||||||
is RoomDetailAction.ReRequestKeys -> handleReRequestKeys(action)
|
is RoomDetailAction.ReRequestKeys -> handleReRequestKeys(action)
|
||||||
|
is RoomDetailAction.SelectStickerAttachment -> handleSelectStickerAttachment()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSendSticker(action: RoomDetailAction.SendSticker) {
|
||||||
|
room.sendEvent(EventType.STICKER, action.stickerContent.toContent())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSelectStickerAttachment() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val viewEvent = stickerPickerActionHandler.handle()
|
||||||
|
_viewEvents.post(viewEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 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.riotx.features.home.room.detail.sticker
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.session.Session
|
||||||
|
import im.vector.riotx.features.home.room.detail.RoomDetailViewEvents
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class StickerPickerActionHandler @Inject constructor(private val session: Session) {
|
||||||
|
|
||||||
|
suspend fun handle(): RoomDetailViewEvents = withContext(Dispatchers.Default) {
|
||||||
|
// Search for the sticker picker widget in the user account
|
||||||
|
val stickerWidget = session.widgetService().getUserWidgets(setOf(StickerPickerConstants.WIDGET_NAME)).firstOrNull()
|
||||||
|
if (stickerWidget == null || stickerWidget.widgetContent.url.isNullOrBlank()) {
|
||||||
|
RoomDetailViewEvents.DisplayPromptForIntegrationManager
|
||||||
|
} else {
|
||||||
|
RoomDetailViewEvents.OpenStickerPicker(
|
||||||
|
widget = stickerWidget
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,8 +14,9 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.riotx.features.widgets.admin
|
package im.vector.riotx.features.home.room.detail.sticker
|
||||||
|
|
||||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
object StickerPickerConstants {
|
||||||
|
const val WIDGET_NAME = "m.stickerpicker"
|
||||||
sealed class AdminWidgetAction : VectorViewModelAction
|
const val STICKER_PICKER_REQUEST_CODE = 16000
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ import im.vector.matrix.android.api.session.crypto.verification.IncomingSasVerif
|
||||||
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom
|
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom
|
||||||
import im.vector.matrix.android.api.session.terms.TermsService
|
import im.vector.matrix.android.api.session.terms.TermsService
|
||||||
import im.vector.matrix.android.api.util.MatrixItem
|
import im.vector.matrix.android.api.util.MatrixItem
|
||||||
|
import im.vector.matrix.android.internal.session.widgets.Widget
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||||
import im.vector.riotx.core.error.fatalError
|
import im.vector.riotx.core.error.fatalError
|
||||||
|
@ -45,6 +46,7 @@ import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
|
||||||
import im.vector.riotx.features.debug.DebugMenuActivity
|
import im.vector.riotx.features.debug.DebugMenuActivity
|
||||||
import im.vector.riotx.features.home.room.detail.RoomDetailActivity
|
import im.vector.riotx.features.home.room.detail.RoomDetailActivity
|
||||||
import im.vector.riotx.features.home.room.detail.RoomDetailArgs
|
import im.vector.riotx.features.home.room.detail.RoomDetailArgs
|
||||||
|
import im.vector.riotx.features.home.room.detail.sticker.StickerPickerConstants
|
||||||
import im.vector.riotx.features.home.room.filtered.FilteredRoomsActivity
|
import im.vector.riotx.features.home.room.filtered.FilteredRoomsActivity
|
||||||
import im.vector.riotx.features.invite.InviteUsersToRoomActivity
|
import im.vector.riotx.features.invite.InviteUsersToRoomActivity
|
||||||
import im.vector.riotx.features.media.BigImageViewerActivity
|
import im.vector.riotx.features.media.BigImageViewerActivity
|
||||||
|
@ -66,6 +68,7 @@ import im.vector.riotx.features.widgets.WidgetActivity
|
||||||
import im.vector.riotx.features.widgets.WidgetArgsBuilder
|
import im.vector.riotx.features.widgets.WidgetArgsBuilder
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class DefaultNavigator @Inject constructor(
|
class DefaultNavigator @Inject constructor(
|
||||||
private val sessionHolder: ActiveSessionHolder,
|
private val sessionHolder: ActiveSessionHolder,
|
||||||
|
@ -224,6 +227,12 @@ class DefaultNavigator @Inject constructor(
|
||||||
fragment.startActivityForResult(intent, requestCode)
|
fragment.startActivityForResult(intent, requestCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openStickerPicker(fragment: Fragment, roomId: String, widget: Widget, requestCode: Int) {
|
||||||
|
val widgetArgs = widgetArgsBuilder.buildStickerPickerArgs(roomId, widget)
|
||||||
|
val intent = WidgetActivity.newIntent(fragment.requireContext(), widgetArgs)
|
||||||
|
fragment.startActivityForResult(intent, StickerPickerConstants.STICKER_PICKER_REQUEST_CODE)
|
||||||
|
}
|
||||||
|
|
||||||
override fun openIntegrationManager(context: Context, roomId: String, integId: String?, screenId: String?) {
|
override fun openIntegrationManager(context: Context, roomId: String, integId: String?, screenId: String?) {
|
||||||
val widgetArgs = widgetArgsBuilder.buildIntegrationManagerArgs(roomId, integId, screenId)
|
val widgetArgs = widgetArgsBuilder.buildIntegrationManagerArgs(roomId, integId, screenId)
|
||||||
context.startActivity(WidgetActivity.newIntent(context, widgetArgs))
|
context.startActivity(WidgetActivity.newIntent(context, widgetArgs))
|
||||||
|
|
|
@ -24,6 +24,8 @@ import androidx.fragment.app.Fragment
|
||||||
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom
|
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom
|
||||||
import im.vector.matrix.android.api.session.terms.TermsService
|
import im.vector.matrix.android.api.session.terms.TermsService
|
||||||
import im.vector.matrix.android.api.util.MatrixItem
|
import im.vector.matrix.android.api.util.MatrixItem
|
||||||
|
import im.vector.matrix.android.internal.session.widgets.Widget
|
||||||
|
import im.vector.riotx.features.home.room.detail.sticker.StickerPickerConstants
|
||||||
import im.vector.riotx.features.media.ImageContentRenderer
|
import im.vector.riotx.features.media.ImageContentRenderer
|
||||||
import im.vector.riotx.features.media.VideoContentRenderer
|
import im.vector.riotx.features.media.VideoContentRenderer
|
||||||
import im.vector.riotx.features.settings.VectorSettingsActivity
|
import im.vector.riotx.features.settings.VectorSettingsActivity
|
||||||
|
@ -80,6 +82,11 @@ interface Navigator {
|
||||||
token: String?,
|
token: String?,
|
||||||
requestCode: Int = ReviewTermsActivity.TERMS_REQUEST_CODE)
|
requestCode: Int = ReviewTermsActivity.TERMS_REQUEST_CODE)
|
||||||
|
|
||||||
|
fun openStickerPicker(fragment: Fragment,
|
||||||
|
roomId: String,
|
||||||
|
widget: Widget,
|
||||||
|
requestCode: Int = StickerPickerConstants.STICKER_PICKER_REQUEST_CODE)
|
||||||
|
|
||||||
fun openIntegrationManager(context: Context, roomId: String, integId: String?, screenId: String?)
|
fun openIntegrationManager(context: Context, roomId: String, integId: String?, screenId: String?)
|
||||||
|
|
||||||
fun openImageViewer(activity: Activity, mediaData: ImageContentRenderer.Data, view: View, options: ((MutableList<Pair<View, String>>) -> Unit)?)
|
fun openImageViewer(activity: Activity, mediaData: ImageContentRenderer.Data, view: View, options: ((MutableList<Pair<View, String>>) -> Unit)?)
|
||||||
|
|
|
@ -14,13 +14,13 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.riotx.features.widgets.room
|
package im.vector.riotx.features.widgets
|
||||||
|
|
||||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||||
|
|
||||||
sealed class RoomWidgetAction : VectorViewModelAction {
|
sealed class WidgetAction : VectorViewModelAction {
|
||||||
data class OnWebViewStartedToLoad(val url: String) : RoomWidgetAction()
|
data class OnWebViewStartedToLoad(val url: String) : WidgetAction()
|
||||||
data class OnWebViewLoadingError(val url: String, val isHttpError: Boolean, val errorCode: Int, val errorDescription: String) : RoomWidgetAction()
|
data class OnWebViewLoadingError(val url: String, val isHttpError: Boolean, val errorCode: Int, val errorDescription: String) : WidgetAction()
|
||||||
data class OnWebViewLoadingSuccess(val url: String) : RoomWidgetAction()
|
data class OnWebViewLoadingSuccess(val url: String) : WidgetAction()
|
||||||
object OnTermsReviewed: RoomWidgetAction()
|
object OnTermsReviewed: WidgetAction()
|
||||||
}
|
}
|
|
@ -19,17 +19,18 @@ package im.vector.riotx.features.widgets
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Content
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.extensions.addFragment
|
import im.vector.riotx.core.extensions.addFragment
|
||||||
import im.vector.riotx.core.platform.ToolbarConfigurable
|
import im.vector.riotx.core.platform.ToolbarConfigurable
|
||||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||||
import im.vector.riotx.features.widgets.room.RoomWidgetFragment
|
import java.io.Serializable
|
||||||
import im.vector.riotx.features.widgets.room.WidgetArgs
|
|
||||||
|
|
||||||
class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable {
|
class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
private const val EXTRA_RESULT = "EXTRA_RESULT"
|
||||||
private const val EXTRA_FRAGMENT_ARGS = "EXTRA_FRAGMENT_ARGS"
|
private const val EXTRA_FRAGMENT_ARGS = "EXTRA_FRAGMENT_ARGS"
|
||||||
|
|
||||||
fun newIntent(context: Context, args: WidgetArgs): Intent {
|
fun newIntent(context: Context, args: WidgetArgs): Intent {
|
||||||
|
@ -37,6 +38,17 @@ class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
putExtra(EXTRA_FRAGMENT_ARGS, args)
|
putExtra(EXTRA_FRAGMENT_ARGS, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun getOutput(intent: Intent): Content? {
|
||||||
|
return intent.extras?.getSerializable(EXTRA_RESULT) as? Content
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createResultIntent(content: Content): Intent {
|
||||||
|
return Intent().apply {
|
||||||
|
putExtra(EXTRA_RESULT, content as Serializable)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLayoutRes() = R.layout.activity_simple
|
override fun getLayoutRes() = R.layout.activity_simple
|
||||||
|
@ -45,7 +57,7 @@ class WidgetActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
val fragmentArgs: WidgetArgs = intent?.extras?.getParcelable(EXTRA_FRAGMENT_ARGS)
|
val fragmentArgs: WidgetArgs = intent?.extras?.getParcelable(EXTRA_FRAGMENT_ARGS)
|
||||||
?: return
|
?: return
|
||||||
addFragment(R.id.simpleFragmentContainer, RoomWidgetFragment::class.java, fragmentArgs)
|
addFragment(R.id.simpleFragmentContainer, WidgetFragment::class.java, fragmentArgs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,8 @@
|
||||||
|
|
||||||
package im.vector.riotx.features.widgets
|
package im.vector.riotx.features.widgets
|
||||||
|
|
||||||
|
import im.vector.matrix.android.internal.session.widgets.Widget
|
||||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||||
import im.vector.riotx.features.widgets.room.WidgetArgs
|
|
||||||
import im.vector.riotx.features.widgets.room.WidgetKind
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class WidgetArgsBuilder @Inject constructor(private val sessionHolder: ActiveSessionHolder) {
|
class WidgetArgsBuilder @Inject constructor(private val sessionHolder: ActiveSessionHolder) {
|
||||||
|
@ -35,7 +34,28 @@ class WidgetArgsBuilder @Inject constructor(private val sessionHolder: ActiveSes
|
||||||
"screen" to screenId,
|
"screen" to screenId,
|
||||||
"integ_id" to integId,
|
"integ_id" to integId,
|
||||||
"room_id" to roomId
|
"room_id" to roomId
|
||||||
).filterValues { it != null } as Map<String, String>
|
).filterNotNull()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun buildStickerPickerArgs(roomId: String, widget: Widget): WidgetArgs {
|
||||||
|
val widgetId = widget.widgetId
|
||||||
|
val baseUrl = widget.widgetContent.url ?: throw IllegalStateException()
|
||||||
|
return WidgetArgs(
|
||||||
|
baseUrl = baseUrl,
|
||||||
|
kind = WidgetKind.USER,
|
||||||
|
roomId = roomId,
|
||||||
|
widgetId = widgetId,
|
||||||
|
urlParams = mapOf(
|
||||||
|
"widgetId" to widgetId,
|
||||||
|
"room_id" to roomId
|
||||||
|
).filterNotNull()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private fun Map<String, String?>.filterNotNull(): Map<String, String>{
|
||||||
|
return filterValues { it != null } as Map<String, String>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.riotx.features.widgets.room
|
package im.vector.riotx.features.widgets
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
@ -51,12 +51,12 @@ data class WidgetArgs(
|
||||||
val urlParams: Map<String, String> = emptyMap()
|
val urlParams: Map<String, String> = emptyMap()
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
class RoomWidgetFragment @Inject constructor(
|
class WidgetFragment @Inject constructor(
|
||||||
private val viewModelFactory: RoomWidgetViewModel.Factory
|
private val viewModelFactory: WidgetViewModel.Factory
|
||||||
) : VectorBaseFragment(), RoomWidgetViewModel.Factory by viewModelFactory, WebViewEventListener {
|
) : VectorBaseFragment(), WidgetViewModel.Factory by viewModelFactory, WebViewEventListener {
|
||||||
|
|
||||||
private val fragmentArgs: WidgetArgs by args()
|
private val fragmentArgs: WidgetArgs by args()
|
||||||
private val viewModel: RoomWidgetViewModel by fragmentViewModel()
|
private val viewModel: WidgetViewModel by fragmentViewModel()
|
||||||
|
|
||||||
override fun getLayoutResId() = R.layout.fragment_room_widget
|
override fun getLayoutResId() = R.layout.fragment_room_widget
|
||||||
|
|
||||||
|
@ -68,15 +68,10 @@ class RoomWidgetFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
viewModel.observeViewEvents {
|
viewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
is RoomWidgetViewEvents.DisplayTerms -> displayTerms(it)
|
is WidgetViewEvents.DisplayTerms -> displayTerms(it)
|
||||||
is RoomWidgetViewEvents.LoadFormattedURL -> loadFormattedUrl(it)
|
is WidgetViewEvents.LoadFormattedURL -> loadFormattedUrl(it)
|
||||||
is RoomWidgetViewEvents.Close -> vectorBaseActivity.finish()
|
is WidgetViewEvents.Close -> handleClose(it)
|
||||||
is RoomWidgetViewEvents.DisplayIntegrationManager -> navigator.openIntegrationManager(
|
is WidgetViewEvents.DisplayIntegrationManager -> displayIntegrationManager(it)
|
||||||
context = vectorBaseActivity,
|
|
||||||
roomId = fragmentArgs.roomId,
|
|
||||||
integId = it.integId,
|
|
||||||
screenId = it.integType
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +79,7 @@ class RoomWidgetFragment @Inject constructor(
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
if (requestCode == ReviewTermsActivity.TERMS_REQUEST_CODE) {
|
if (requestCode == ReviewTermsActivity.TERMS_REQUEST_CODE) {
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
viewModel.handle(RoomWidgetAction.OnTermsReviewed)
|
viewModel.handle(WidgetAction.OnTermsReviewed)
|
||||||
} else {
|
} else {
|
||||||
vectorBaseActivity.finish()
|
vectorBaseActivity.finish()
|
||||||
}
|
}
|
||||||
|
@ -169,7 +164,23 @@ class RoomWidgetFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun displayTerms(displayTerms: RoomWidgetViewEvents.DisplayTerms) {
|
override fun onPageStarted(url: String) {
|
||||||
|
viewModel.handle(WidgetAction.OnWebViewStartedToLoad(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPageFinished(url: String) {
|
||||||
|
viewModel.handle(WidgetAction.OnWebViewLoadingSuccess(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPageError(url: String, errorCode: Int, description: String) {
|
||||||
|
viewModel.handle(WidgetAction.OnWebViewLoadingError(url, false, errorCode, description))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onHttpError(url: String, errorCode: Int, description: String) {
|
||||||
|
viewModel.handle(WidgetAction.OnWebViewLoadingError(url, true, errorCode, description))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun displayTerms(displayTerms: WidgetViewEvents.DisplayTerms) {
|
||||||
navigator.openTerms(
|
navigator.openTerms(
|
||||||
fragment = this,
|
fragment = this,
|
||||||
serviceType = TermsService.ServiceType.IntegrationManager,
|
serviceType = TermsService.ServiceType.IntegrationManager,
|
||||||
|
@ -178,7 +189,7 @@ class RoomWidgetFragment @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadFormattedUrl(loadFormattedUrl: RoomWidgetViewEvents.LoadFormattedURL) {
|
private fun loadFormattedUrl(loadFormattedUrl: WidgetViewEvents.LoadFormattedURL) {
|
||||||
widgetWebView.clearHistory()
|
widgetWebView.clearHistory()
|
||||||
widgetWebView.loadUrl(loadFormattedUrl.formattedURL)
|
widgetWebView.loadUrl(loadFormattedUrl.formattedURL)
|
||||||
}
|
}
|
||||||
|
@ -195,19 +206,20 @@ class RoomWidgetFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPageStarted(url: String) {
|
private fun displayIntegrationManager(event: WidgetViewEvents.DisplayIntegrationManager) {
|
||||||
viewModel.handle(RoomWidgetAction.OnWebViewStartedToLoad(url))
|
navigator.openIntegrationManager(
|
||||||
|
context = vectorBaseActivity,
|
||||||
|
roomId = fragmentArgs.roomId,
|
||||||
|
integId = event.integId,
|
||||||
|
screenId = event.integType
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPageFinished(url: String) {
|
private fun handleClose(event: WidgetViewEvents.Close) {
|
||||||
viewModel.handle(RoomWidgetAction.OnWebViewLoadingSuccess(url))
|
if (event.content != null) {
|
||||||
|
val intent = WidgetActivity.createResultIntent(event.content)
|
||||||
|
vectorBaseActivity.setResult(Activity.RESULT_OK, intent)
|
||||||
}
|
}
|
||||||
|
vectorBaseActivity.finish()
|
||||||
override fun onPageError(url: String, errorCode: Int, description: String) {
|
|
||||||
viewModel.handle(RoomWidgetAction.OnWebViewLoadingError(url, false, errorCode, description))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onHttpError(url: String, errorCode: Int, description: String) {
|
|
||||||
viewModel.handle(RoomWidgetAction.OnWebViewLoadingError(url, true, errorCode, description))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,6 +21,7 @@ import com.squareup.inject.assisted.Assisted
|
||||||
import com.squareup.inject.assisted.AssistedInject
|
import com.squareup.inject.assisted.AssistedInject
|
||||||
import im.vector.matrix.android.api.query.QueryStringValue
|
import im.vector.matrix.android.api.query.QueryStringValue
|
||||||
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.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.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
|
||||||
|
@ -49,6 +50,7 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
|
||||||
|
|
||||||
interface NavigationCallback {
|
interface NavigationCallback {
|
||||||
fun close()
|
fun close()
|
||||||
|
fun closeWithResult(content: Content)
|
||||||
fun openIntegrationManager(integId: String?, integType: String?)
|
fun openIntegrationManager(integId: String?, integType: String?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +72,7 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
|
||||||
"set_bot_power" -> setBotPower(eventData).run { true }
|
"set_bot_power" -> setBotPower(eventData).run { true }
|
||||||
"set_plumbing_state" -> setPlumbingState(eventData).run { true }
|
"set_plumbing_state" -> setPlumbingState(eventData).run { true }
|
||||||
"set_widget" -> setWidget(eventData).run { true }
|
"set_widget" -> setWidget(eventData).run { true }
|
||||||
|
"m.sticker" -> pickStickerData(eventData).run { true }
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,6 +397,23 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
|
||||||
widgetPostAPIMediator.sendIntegerResponse(numberOfJoinedMembers, eventData)
|
widgetPostAPIMediator.sendIntegerResponse(numberOfJoinedMembers, eventData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private fun pickStickerData(eventData: JsonDict) {
|
||||||
|
Timber.d("Received request send sticker")
|
||||||
|
val data = eventData["data"]
|
||||||
|
if (data == null) {
|
||||||
|
widgetPostAPIMediator.sendError(stringProvider.getString(R.string.widget_integration_missing_parameter), eventData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val content = (data as? JsonDict)?.get("content") as? Content
|
||||||
|
if (content == null) {
|
||||||
|
widgetPostAPIMediator.sendError(stringProvider.getString(R.string.widget_integration_missing_parameter), eventData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
widgetPostAPIMediator.sendSuccess(eventData)
|
||||||
|
navigationCallback.closeWithResult(content)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if roomId is present in the event and match
|
* Check if roomId is present in the event and match
|
||||||
* Send response and return true in case of error
|
* Send response and return true in case of error
|
||||||
|
|
|
@ -14,13 +14,14 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.riotx.features.widgets.room
|
package im.vector.riotx.features.widgets
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Content
|
||||||
import im.vector.riotx.core.platform.VectorViewEvents
|
import im.vector.riotx.core.platform.VectorViewEvents
|
||||||
|
|
||||||
sealed class RoomWidgetViewEvents : VectorViewEvents {
|
sealed class WidgetViewEvents : VectorViewEvents {
|
||||||
object Close: RoomWidgetViewEvents()
|
data class Close(val content: Content?): WidgetViewEvents()
|
||||||
data class DisplayIntegrationManager(val integId: String?, val integType: String?): RoomWidgetViewEvents()
|
data class DisplayIntegrationManager(val integId: String?, val integType: String?): WidgetViewEvents()
|
||||||
data class LoadFormattedURL(val formattedURL: String): RoomWidgetViewEvents()
|
data class LoadFormattedURL(val formattedURL: String): WidgetViewEvents()
|
||||||
data class DisplayTerms(val url: String, val token: String): RoomWidgetViewEvents()
|
data class DisplayTerms(val url: String, val token: String): WidgetViewEvents()
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.riotx.features.widgets.room
|
package im.vector.riotx.features.widgets
|
||||||
|
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.airbnb.mvrx.ActivityViewModelContext
|
import com.airbnb.mvrx.ActivityViewModelContext
|
||||||
|
@ -28,27 +28,30 @@ import com.squareup.inject.assisted.Assisted
|
||||||
import com.squareup.inject.assisted.AssistedInject
|
import com.squareup.inject.assisted.AssistedInject
|
||||||
import im.vector.matrix.android.api.query.QueryStringValue
|
import im.vector.matrix.android.api.query.QueryStringValue
|
||||||
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.Content
|
||||||
|
import im.vector.matrix.android.api.session.integrationmanager.IntegrationManagerService
|
||||||
import im.vector.matrix.android.internal.session.widgets.WidgetManagementFailure
|
import im.vector.matrix.android.internal.session.widgets.WidgetManagementFailure
|
||||||
import im.vector.riotx.core.platform.VectorViewModel
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
import im.vector.riotx.features.widgets.WidgetPostAPIHandler
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.net.ssl.HttpsURLConnection
|
import javax.net.ssl.HttpsURLConnection
|
||||||
|
|
||||||
class RoomWidgetViewModel @AssistedInject constructor(@Assisted val initialState: WidgetViewState,
|
class WidgetViewModel @AssistedInject constructor(@Assisted val initialState: WidgetViewState,
|
||||||
private val widgetPostAPIHandlerFactory: WidgetPostAPIHandler.Factory,
|
private val widgetPostAPIHandlerFactory: WidgetPostAPIHandler.Factory,
|
||||||
private val session: Session)
|
private val session: Session)
|
||||||
: VectorViewModel<WidgetViewState, RoomWidgetAction, RoomWidgetViewEvents>(initialState), WidgetPostAPIHandler.NavigationCallback {
|
: VectorViewModel<WidgetViewState, WidgetAction, WidgetViewEvents>(initialState),
|
||||||
|
WidgetPostAPIHandler.NavigationCallback,
|
||||||
|
IntegrationManagerService.Listener {
|
||||||
|
|
||||||
@AssistedInject.Factory
|
@AssistedInject.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(initialState: WidgetViewState): RoomWidgetViewModel
|
fun create(initialState: WidgetViewState): WidgetViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : MvRxViewModelFactory<RoomWidgetViewModel, WidgetViewState> {
|
companion object : MvRxViewModelFactory<WidgetViewModel, WidgetViewState> {
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
override fun create(viewModelContext: ViewModelContext, state: WidgetViewState): RoomWidgetViewModel? {
|
override fun create(viewModelContext: ViewModelContext, state: WidgetViewState): WidgetViewModel? {
|
||||||
val factory = when (viewModelContext) {
|
val factory = when (viewModelContext) {
|
||||||
is FragmentViewModelContext -> viewModelContext.fragment as? Factory
|
is FragmentViewModelContext -> viewModelContext.fragment as? Factory
|
||||||
is ActivityViewModelContext -> viewModelContext.activity as? Factory
|
is ActivityViewModelContext -> viewModelContext.activity as? Factory
|
||||||
|
@ -59,11 +62,12 @@ class RoomWidgetViewModel @AssistedInject constructor(@Assisted val initialState
|
||||||
|
|
||||||
private val widgetService = session.widgetService()
|
private val widgetService = session.widgetService()
|
||||||
private val integrationManagerService = session.integrationManagerService()
|
private val integrationManagerService = session.integrationManagerService()
|
||||||
private val widgetBuilder = widgetService.getWidgetURLFormatter()
|
private val widgetURLFormatter = widgetService.getWidgetURLFormatter()
|
||||||
private val postAPIMediator = widgetService.getWidgetPostAPIMediator()
|
private val postAPIMediator = widgetService.getWidgetPostAPIMediator()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if(initialState.widgetKind.isAdmin()) {
|
integrationManagerService.addListener(this)
|
||||||
|
if (initialState.widgetKind.isAdmin()) {
|
||||||
val widgetPostAPIHandler = widgetPostAPIHandlerFactory.create(initialState.roomId, this)
|
val widgetPostAPIHandler = widgetPostAPIHandlerFactory.create(initialState.roomId, this)
|
||||||
postAPIMediator.setHandler(widgetPostAPIHandler)
|
postAPIMediator.setHandler(widgetPostAPIHandler)
|
||||||
}
|
}
|
||||||
|
@ -82,11 +86,11 @@ class RoomWidgetViewModel @AssistedInject constructor(@Assisted val initialState
|
||||||
|
|
||||||
fun getPostAPIMediator() = postAPIMediator
|
fun getPostAPIMediator() = postAPIMediator
|
||||||
|
|
||||||
override fun handle(action: RoomWidgetAction) {
|
override fun handle(action: WidgetAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is RoomWidgetAction.OnWebViewLoadingError -> handleWebViewLoadingError(action.isHttpError, action.errorCode, action.errorDescription)
|
is WidgetAction.OnWebViewLoadingError -> handleWebViewLoadingError(action.isHttpError, action.errorCode, action.errorDescription)
|
||||||
is RoomWidgetAction.OnWebViewLoadingSuccess -> handleWebViewLoadingSuccess(action.url)
|
is WidgetAction.OnWebViewLoadingSuccess -> handleWebViewLoadingSuccess(action.url)
|
||||||
is RoomWidgetAction.OnWebViewStartedToLoad -> handleWebViewStartLoading()
|
is WidgetAction.OnWebViewStartedToLoad -> handleWebViewStartLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,17 +135,17 @@ class RoomWidgetViewModel @AssistedInject constructor(@Assisted val initialState
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
setState { copy(formattedURL = Loading()) }
|
setState { copy(formattedURL = Loading()) }
|
||||||
val formattedUrl = widgetBuilder.format(
|
val formattedUrl = widgetURLFormatter.format(
|
||||||
baseUrl = initialState.baseUrl,
|
baseUrl = initialState.baseUrl,
|
||||||
params = initialState.urlParams,
|
params = initialState.urlParams,
|
||||||
forceFetchScalarToken = forceFetchToken,
|
forceFetchScalarToken = forceFetchToken,
|
||||||
bypassWhitelist = initialState.widgetKind == WidgetKind.INTEGRATION_MANAGER
|
bypassWhitelist = initialState.widgetKind == WidgetKind.INTEGRATION_MANAGER
|
||||||
)
|
)
|
||||||
setState { copy(formattedURL = Success(formattedUrl)) }
|
setState { copy(formattedURL = Success(formattedUrl)) }
|
||||||
_viewEvents.post(RoomWidgetViewEvents.LoadFormattedURL(formattedUrl))
|
_viewEvents.post(WidgetViewEvents.LoadFormattedURL(formattedUrl))
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
if (failure is WidgetManagementFailure.TermsNotSignedException) {
|
if (failure is WidgetManagementFailure.TermsNotSignedException) {
|
||||||
_viewEvents.post(RoomWidgetViewEvents.DisplayTerms(failure.baseUrl, failure.token))
|
_viewEvents.post(WidgetViewEvents.DisplayTerms(failure.baseUrl, failure.token))
|
||||||
}
|
}
|
||||||
setState { copy(formattedURL = Fail(failure)) }
|
setState { copy(formattedURL = Fail(failure)) }
|
||||||
}
|
}
|
||||||
|
@ -162,9 +166,11 @@ class RoomWidgetViewModel @AssistedInject constructor(@Assisted val initialState
|
||||||
private fun handleWebViewLoadingError(isHttpError: Boolean, reason: Int, errorDescription: String) {
|
private fun handleWebViewLoadingError(isHttpError: Boolean, reason: Int, errorDescription: String) {
|
||||||
if (isHttpError) {
|
if (isHttpError) {
|
||||||
// In case of 403, try to refresh the scalar token
|
// In case of 403, try to refresh the scalar token
|
||||||
if (reason == HttpsURLConnection.HTTP_FORBIDDEN) {
|
withState {
|
||||||
|
if (it.formattedURL is Success && reason == HttpsURLConnection.HTTP_FORBIDDEN) {
|
||||||
loadFormattedUrl(true)
|
loadFormattedUrl(true)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setState { copy(webviewLoadedUrl = Fail(Throwable(errorDescription))) }
|
setState { copy(webviewLoadedUrl = Fail(Throwable(errorDescription))) }
|
||||||
}
|
}
|
||||||
|
@ -172,14 +178,27 @@ class RoomWidgetViewModel @AssistedInject constructor(@Assisted val initialState
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
|
integrationManagerService.removeListener(this)
|
||||||
postAPIMediator.setHandler(null)
|
postAPIMediator.setHandler(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IntegrationManagerService.Listener
|
||||||
|
|
||||||
|
override fun onWidgetPermissionsChanged(widgets: Map<String, Boolean>) {
|
||||||
|
refreshPermissionStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WidgetPostAPIHandler.NavigationCallback
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
_viewEvents.post(RoomWidgetViewEvents.Close)
|
_viewEvents.post(WidgetViewEvents.Close(null))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun closeWithResult(content: Content) {
|
||||||
|
_viewEvents.post(WidgetViewEvents.Close(content))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openIntegrationManager(integId: String?, integType: String?) {
|
override fun openIntegrationManager(integId: String?, integType: String?) {
|
||||||
_viewEvents.post(RoomWidgetViewEvents.DisplayIntegrationManager(integId, integType))
|
_viewEvents.post(WidgetViewEvents.DisplayIntegrationManager(integId, integType))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.riotx.features.widgets.room
|
package im.vector.riotx.features.widgets
|
||||||
|
|
||||||
import com.airbnb.mvrx.Async
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 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.riotx.features.widgets.admin
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
|
||||||
import com.airbnb.mvrx.withState
|
|
||||||
import im.vector.riotx.R
|
|
||||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
|
||||||
import timber.log.Timber
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class AdminWidgetFragment @Inject constructor(
|
|
||||||
private val viewModelFactory: AdminWidgetViewModel.Factory
|
|
||||||
) : VectorBaseFragment(), AdminWidgetViewModel.Factory by viewModelFactory {
|
|
||||||
|
|
||||||
private val viewModel: AdminWidgetViewModel by fragmentViewModel()
|
|
||||||
|
|
||||||
override fun getLayoutResId() = R.layout.fragment_admin_widget
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
// Initialize your view, subscribe to viewModel...
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
super.onDestroyView()
|
|
||||||
// Clear your view, unsubscribe...
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
|
||||||
Timber.v("Invalidate with state: $state")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 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.riotx.features.widgets.admin
|
|
||||||
|
|
||||||
import im.vector.riotx.core.platform.VectorViewEvents
|
|
||||||
|
|
||||||
sealed class AdminWidgetViewEvents : VectorViewEvents
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 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.riotx.features.widgets.admin
|
|
||||||
|
|
||||||
import com.airbnb.mvrx.ActivityViewModelContext
|
|
||||||
import com.airbnb.mvrx.FragmentViewModelContext
|
|
||||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
|
||||||
import com.squareup.inject.assisted.Assisted
|
|
||||||
import com.squareup.inject.assisted.AssistedInject
|
|
||||||
import im.vector.riotx.core.platform.VectorViewModel
|
|
||||||
|
|
||||||
class AdminWidgetViewModel @AssistedInject constructor(@Assisted initialState: AdminWidgetViewState)
|
|
||||||
: VectorViewModel<AdminWidgetViewState, AdminWidgetAction, AdminWidgetViewEvents>(initialState) {
|
|
||||||
|
|
||||||
@AssistedInject.Factory
|
|
||||||
interface Factory {
|
|
||||||
fun create(initialState: AdminWidgetViewState): AdminWidgetViewModel
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object : MvRxViewModelFactory<AdminWidgetViewModel, AdminWidgetViewState> {
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
override fun create(viewModelContext: ViewModelContext, state: AdminWidgetViewState): AdminWidgetViewModel? {
|
|
||||||
val factory = when (viewModelContext) {
|
|
||||||
is FragmentViewModelContext -> viewModelContext.fragment as? Factory
|
|
||||||
is ActivityViewModelContext -> viewModelContext.activity as? Factory
|
|
||||||
}
|
|
||||||
return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handle(action: AdminWidgetAction) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 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.riotx.features.widgets.admin
|
|
||||||
|
|
||||||
import com.airbnb.mvrx.MvRxState
|
|
||||||
|
|
||||||
data class AdminWidgetViewState(val boolean: Boolean = false) : MvRxState
|
|
10
vector/src/main/res/layout/dialog_no_sticker_pack.xml
Normal file
10
vector/src/main/res/layout/dialog_no_sticker_pack.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:drawableBottom="@drawable/stickerpack_rabbit"
|
||||||
|
android:drawablePadding="16dp"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:maxWidth="300dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:text="@string/no_sticker_application_dialog_content" />
|
Loading…
Reference in a new issue