diff --git a/CHANGES.md b/CHANGES.md index f4c72ba7..5b598a57 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,21 +2,23 @@ Changes in RiotX 0.2.1 (2019-XX-XX) =================================================== Features: - - Message Editing: View edit history + - Message Editing: View edit history (#121) - Rooms filtering (#304) Improvements: - Handle click on redacted events: view source and create permalink - Improve long tap menu: reply on top, more compact (#368) - Quick reply in timeline with swipe gesture + - Improve edit of replies Other changes: - - + - migrate from rxbinding 2 to rxbinding 3 Bugfix: - Fix regression on permalink click - Fix crash reported by the PlayStore (#341) - Fix Chat composer separator color in dark/black theme + - Fix bad layout for room directory filter (#349) Translations: - diff --git a/build.gradle b/build.gradle index 4fa468ab..b52707d5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,5 @@ +import javax.tools.JavaCompiler + // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { @@ -52,6 +54,19 @@ allprojects { } } } + + tasks.withType(JavaCompile).all { + options.compilerArgs += [ + '-Adagger.gradle.incremental=enabled' + ] + } + + afterEvaluate { + extensions.findByName("kapt")?.arguments { + arg("dagger.gradle.incremental", "enabled") + } + } + } task clean(type: Delete) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/Session.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/Session.kt index 08e706c3..54ae24c7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/Session.kt @@ -57,6 +57,9 @@ interface Session : */ val sessionParams: SessionParams + /** + * Useful shortcut to get access to the userId + */ val myUserId: String get() = sessionParams.credentials.userId diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/RelationType.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/RelationType.kt index 56d4801c..0f5421a0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/RelationType.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/events/model/RelationType.kt @@ -17,7 +17,7 @@ package im.vector.matrix.android.api.session.events.model /** - * Constants defining known event relation types from Matrix specifications. + * Constants defining known event relation types from Matrix specifications */ object RelationType { @@ -25,7 +25,7 @@ object RelationType { const val ANNOTATION = "m.annotation" /** Lets you define an event which replaces an existing event.*/ const val REPLACE = "m.replace" - /** ets you define an event which references an existing event.*/ + /** Lets you define an event which references an existing event.*/ const val REFERENCE = "m.reference" } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageContent.kt index c45e47fc..bd32a75a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/message/MessageContent.kt @@ -25,4 +25,9 @@ interface MessageContent { val body: String val relatesTo: RelationDefaultContent? val newContent: Content? +} + + +fun MessageContent?.isReply(): Boolean { + return this?.relatesTo?.inReplyTo != null } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationContent.kt index 9bbdf5ab..5f89a482 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationContent.kt @@ -16,7 +16,10 @@ package im.vector.matrix.android.api.session.room.model.relation +import im.vector.matrix.android.api.session.events.model.RelationType + interface RelationContent { + /** See [RelationType] for known possible values */ val type: String? val eventId: String? val inReplyTo: ReplyToContent? diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationService.kt index 7ffbd5f1..da91ee70 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/relation/RelationService.kt @@ -80,6 +80,22 @@ interface RelationService { newBodyAutoMarkdown: Boolean, compatibilityBodyText: String = "* $newBodyText"): Cancelable + + /** + * Edit a reply. This is a special case because replies contains fallback text as a prefix. + * This method will take the new body (stripped from fallbacks) and re-add them before sending. + * @param replyToEdit The event to edit + * @param originalSenderId the sender of the message that this reply (being edited) is relating to + * @param originalEventId the event id that this reply (being edited) is relating to + * @param newBodyText The edited body (stripped from in reply to content) + * @param compatibilityBodyText The text that will appear on clients that don't support yet edition + */ + fun editReply(replyToEdit: TimelineEvent, + originalSenderId: String?, + originalEventId : String, + newBodyText: String, + compatibilityBodyText: String = "* $newBodyText"): Cancelable + /** * Get's the edit history of the given event */ diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt index f626e3a7..761c3961 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/timeline/TimelineEvent.kt @@ -21,7 +21,9 @@ 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.room.model.EventAnnotationsSummary import im.vector.matrix.android.api.session.room.model.message.MessageContent +import im.vector.matrix.android.api.session.room.model.message.isReply import im.vector.matrix.android.api.session.room.send.SendState +import im.vector.matrix.android.api.util.ContentUtils.extractUsefulTextFromReply /** * This data class is a wrapper around an Event. It allows to get useful data in the context of a timeline. @@ -88,3 +90,15 @@ data class TimelineEvent( */ fun TimelineEvent.getLastMessageContent(): MessageContent? = annotations?.editSummary?.aggregatedContent?.toModel() ?: root.getClearContent().toModel() + + +fun TimelineEvent.getTextEditableContent(): String? { + val originalContent = root.getClearContent().toModel() ?: return null + val isReply = originalContent.isReply() + val lastContent = getLastMessageContent() + return if (isReply) { + return extractUsefulTextFromReply(lastContent?.body ?: "") + } else { + lastContent?.body ?: "" + } +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/ContentUtils.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/ContentUtils.kt new file mode 100644 index 00000000..ad17d26b --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/ContentUtils.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.matrix.android.api.util + + +object ContentUtils { + fun extractUsefulTextFromReply(repliedBody: String): String { + val lines = repliedBody.lines() + var wellFormed = repliedBody.startsWith(">") + var endOfPreviousFound = false + val usefullines = ArrayList() + lines.forEach { + if (it == "") { + endOfPreviousFound = true + return@forEach + } + if (!endOfPreviousFound) { + wellFormed = wellFormed && it.startsWith(">") + } else { + usefullines.add(it) + } + } + return usefullines.joinToString("\n").takeIf { wellFormed } ?: repliedBody + } + + fun extractUsefulTextFromHtmlReply(repliedBody: String): String { + if (repliedBody.startsWith("")) { + val closingTagIndex = repliedBody.lastIndexOf("") + if (closingTagIndex != -1) + return repliedBody.substring(closingTagIndex + "".length).trim() + } + return repliedBody + } +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/SessionManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/SessionManager.kt index 7cc73ceb..21f16d3d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/SessionManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/SessionManager.kt @@ -50,16 +50,10 @@ internal class SessionManager @Inject constructor(private val matrixComponent: M } private fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent { - val userId = sessionParams.credentials.userId - if (sessionComponents.containsKey(userId)) { - return sessionComponents[userId]!! + return sessionComponents.getOrPut(sessionParams.credentials.userId) { + DaggerSessionComponent + .factory() + .create(matrixComponent, sessionParams) } - return DaggerSessionComponent - .factory() - .create(matrixComponent, sessionParams) - .also { - sessionComponents[sessionParams.credentials.userId] = it - } } - } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt index 6a1cda53..a84e0193 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt @@ -94,11 +94,11 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se } override fun requireBackgroundSync() { - SyncWorker.requireBackgroundSync(context, sessionParams.credentials.userId) + SyncWorker.requireBackgroundSync(context, myUserId) } override fun startAutomaticBackgroundSync(repeatDelay: Long) { - SyncWorker.automaticallyBackgroundSync(context, sessionParams.credentials.userId, 0, repeatDelay) + SyncWorker.automaticallyBackgroundSync(context, myUserId, 0, repeatDelay) } override fun stopAnyBackgroundSync() { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt index 1b487d96..37a7f094 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/relation/DefaultRelationService.kt @@ -25,6 +25,7 @@ import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary +import im.vector.matrix.android.api.session.room.model.message.MessageType import im.vector.matrix.android.api.session.room.model.relation.RelationService import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.api.util.Cancelable @@ -132,6 +133,24 @@ internal class DefaultRelationService @Inject constructor(private val context: C } + override fun editReply(replyToEdit: TimelineEvent, + originalSenderId: String?, + originalEventId: String, + newBodyText: String, + compatibilityBodyText: String): Cancelable { + val event = eventFactory + .createReplaceTextOfReply(roomId, + replyToEdit, + originalSenderId, originalEventId, + newBodyText, true, MessageType.MSGTYPE_TEXT, compatibilityBodyText) + .also { + saveLocalEcho(it) + } + val workRequest = createSendEventWork(event) + TimelineSendEventWorkCommon.postWork(context, roomId, workRequest) + return CancelableWork(context, workRequest.id) + } + override fun fetchEditHistory(eventId: String, callback: MatrixCallback>) { val params = FetchEditHistoryTask.Params(roomId, eventId) fetchEditHistoryTask.configureWith(params) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt index 67d1eabc..40390d5d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoEventFactory.kt @@ -104,6 +104,45 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials )) } + fun createReplaceTextOfReply(roomId: String, eventReplaced: TimelineEvent, + originalSenderId: String?, + originalEventId: String, + newBodyText: String, + newBodyAutoMarkdown: Boolean, + msgType: String, + compatibilityText: String): Event { + val permalink = PermalinkFactory.createPermalink(roomId, originalEventId) + val userLink = originalSenderId?.let { PermalinkFactory.createPermalink(it) } ?: "" + + val body = bodyForReply(eventReplaced.getLastMessageContent(), eventReplaced.root.getClearContent().toModel()) + val replyFormatted = REPLY_PATTERN.format( + permalink, + stringProvider.getString(R.string.message_reply_to_prefix), + userLink, + originalSenderId, + body.takeFormatted(), + createTextContent(newBodyText, newBodyAutoMarkdown).takeFormatted() + ) + // + // > <@alice:example.org> This is the original body + // + val replyFallback = buildReplyFallback(body, originalSenderId, newBodyText) + + return createEvent(roomId, + MessageTextContent( + type = msgType, + body = compatibilityText, + relatesTo = RelationDefaultContent(RelationType.REPLACE, eventReplaced.root.eventId), + newContent = MessageTextContent( + type = msgType, + format = MessageType.FORMAT_MATRIX_HTML, + body = replyFallback, + formattedBody = replyFormatted + ) + .toContent() + )) + } + fun createMediaEvent(roomId: String, attachment: ContentAttachmentData): Event { return when (attachment.type) { ContentAttachmentData.Type.IMAGE -> createImageEvent(roomId, attachment) @@ -239,16 +278,8 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials val permalink = PermalinkFactory.createPermalink(eventReplied.root) ?: return null val userId = eventReplied.root.senderId ?: return null val userLink = PermalinkFactory.createPermalink(userId) ?: return null - // - //
- // In reply to - // @alice:example.org - //
- // - //
- //
- // This is where the reply goes. - val body = bodyForReply(eventReplied.getLastMessageContent()) + + val body = bodyForReply(eventReplied.getLastMessageContent(), eventReplied.root.getClearContent().toModel()) val replyFormatted = REPLY_PATTERN.format( permalink, stringProvider.getString(R.string.message_reply_to_prefix), @@ -260,8 +291,22 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials // // > <@alice:example.org> This is the original body // + val replyFallback = buildReplyFallback(body, userId, replyText) + + val eventId = eventReplied.root.eventId ?: return null + val content = MessageTextContent( + type = MessageType.MSGTYPE_TEXT, + format = MessageType.FORMAT_MATRIX_HTML, + body = replyFallback, + formattedBody = replyFormatted, + relatesTo = RelationDefaultContent(null, null, ReplyToContent(eventId)) + ) + return createEvent(roomId, content) + } + + private fun buildReplyFallback(body: TextContent, originalSenderId: String?, newBodyText: String): String { val lines = body.text.split("\n") - val replyFallback = StringBuffer("><$userId>") + val replyFallback = StringBuffer("><$originalSenderId>") lines.forEachIndexed { index, s -> if (index == 0) { replyFallback.append(" $s") @@ -269,23 +314,16 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials replyFallback.append("\n>$s") } } - replyFallback.append("\n\n").append(replyText) - - val eventId = eventReplied.root.eventId ?: return null - val content = MessageTextContent( - type = MessageType.MSGTYPE_TEXT, - format = MessageType.FORMAT_MATRIX_HTML, - body = replyFallback.toString(), - formattedBody = replyFormatted, - relatesTo = RelationDefaultContent(null, null, ReplyToContent(eventId)) - ) - return createEvent(roomId, content) + replyFallback.append("\n\n").append(newBodyText) + return replyFallback.toString() } /** * Returns a TextContent used for the fallback event representation in a reply message. + * We also pass the original content, because in case of an edit of a reply the last content is not + * himself a reply, but it will contain the fallbacks, so we have to trim them. */ - private fun bodyForReply(content: MessageContent?): TextContent { + private fun bodyForReply(content: MessageContent?, originalContent: MessageContent?): TextContent { when (content?.type) { MessageType.MSGTYPE_EMOTE, MessageType.MSGTYPE_TEXT, @@ -296,7 +334,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials formattedText = content.formattedBody } } - val isReply = content.relatesTo?.inReplyTo?.eventId != null + val isReply = content.isReply() || originalContent.isReply() return if (isReply) TextContent(content.body, formattedText).removeInReplyFallbacks() else @@ -353,7 +391,16 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials companion object { const val LOCAL_ID_PREFIX = "local." - // No whitespace + + // + //
+ // In reply to + // @alice:example.org + //
+ // + //
+ //
+ // No whitespace because currently breaks temporary formatted text to Span const val REPLY_PATTERN = """
%s%s
%s
%s""" fun isLocalEchoId(eventId: String): Boolean = eventId.startsWith(LOCAL_ID_PREFIX) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/TextContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/TextContent.kt index 3061bd83..bf7cb361 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/TextContent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/TextContent.kt @@ -18,6 +18,8 @@ package im.vector.matrix.android.internal.session.room.send import im.vector.matrix.android.api.session.room.model.message.MessageTextContent import im.vector.matrix.android.api.session.room.model.message.MessageType +import im.vector.matrix.android.api.util.ContentUtils.extractUsefulTextFromHtmlReply +import im.vector.matrix.android.api.util.ContentUtils.extractUsefulTextFromReply /** * Contains a text and eventually a formatted text @@ -47,28 +49,4 @@ fun TextContent.removeInReplyFallbacks(): TextContent { ) } -private fun extractUsefulTextFromReply(repliedBody: String): String { - val lines = repliedBody.lines() - var wellFormed = repliedBody.startsWith(">") - var endOfPreviousFound = false - val usefullines = ArrayList() - lines.forEach { - if (it == "") { - endOfPreviousFound = true - return@forEach - } - if (!endOfPreviousFound) { - wellFormed = wellFormed && it.startsWith(">") - } else { - usefullines.add(it) - } - } - return usefullines.joinToString("\n").takeIf { wellFormed } ?: repliedBody -} -private fun extractUsefulTextFromHtmlReply(repliedBody: String): String { - if (repliedBody.startsWith("")) { - return repliedBody.substring(repliedBody.lastIndexOf("") + "".length).trim() - } - return repliedBody -} diff --git a/vector/build.gradle b/vector/build.gradle index d7332c47..5fdb240a 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -187,8 +187,9 @@ dependencies { implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0' implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' implementation 'com.jakewharton.rxrelay2:rxrelay:2.1.0' - // TODO RxBindings3 exists - implementation 'com.jakewharton.rxbinding2:rxbinding:2.2.0' + // RXBinding + implementation 'com.jakewharton.rxbinding3:rxbinding:3.0.0-alpha2' + implementation 'com.jakewharton.rxbinding3:rxbinding-appcompat:3.0.0-alpha2' implementation("com.airbnb.android:epoxy:$epoxy_version") kapt "com.airbnb.android:epoxy-processor:$epoxy_version" diff --git a/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt b/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt index 6c9f16c6..5a4aa36c 100755 --- a/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt +++ b/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt @@ -199,7 +199,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { if (eventType == null) { //Just add a generic unknown event val simpleNotifiableEvent = SimpleNotifiableEvent( - session.sessionParams.credentials.userId, + session.myUserId, eventId, true, //It's an issue in this case, all event will bing even if expected to be silent. title = getString(R.string.notification_unknown_new_event), @@ -238,7 +238,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { } notifiableEvent.isPushGatewayEvent = true - notifiableEvent.matrixID = session.sessionParams.credentials.userId + notifiableEvent.matrixID = session.myUserId notificationDrawerManager.onNotifiableEventReceived(notifiableEvent) notificationDrawerManager.refreshNotificationDrawer() } diff --git a/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt b/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt index 37abde20..534a346a 100644 --- a/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt +++ b/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt @@ -57,9 +57,15 @@ import im.vector.riotx.features.workers.signout.SignOutViewModel interface ViewModelModule { + /** + * ViewModels with @IntoMap will be injected by this factory + */ @Binds fun bindViewModelFactory(factory: VectorViewModelFactory): ViewModelProvider.Factory + /** + * Below are bindings for the androidx view models (which extend ViewModel). Will be converted to MvRx ViewModel in the future. + */ @Binds @IntoMap @ViewModelKey(SignOutViewModel::class) @@ -110,6 +116,10 @@ interface ViewModelModule { @ViewModelKey(ConfigurationViewModel::class) fun bindConfigurationViewModel(viewModel: ConfigurationViewModel): ViewModel + /** + * Below are bindings for the MvRx view models (which extend VectorViewModel). Will be the only usage in the future. + */ + @Binds fun bindHomeActivityViewModelFactory(factory: HomeActivityViewModel_AssistedFactory): HomeActivityViewModel.Factory diff --git a/vector/src/main/java/im/vector/riotx/core/preference/UserAvatarPreference.kt b/vector/src/main/java/im/vector/riotx/core/preference/UserAvatarPreference.kt index e5e84514..b0747e7e 100755 --- a/vector/src/main/java/im/vector/riotx/core/preference/UserAvatarPreference.kt +++ b/vector/src/main/java/im/vector/riotx/core/preference/UserAvatarPreference.kt @@ -58,10 +58,10 @@ open class UserAvatarPreference : Preference { open fun refreshAvatar() { val session = mSession ?: return val view = mAvatarView ?: return - session.getUser(session.sessionParams.credentials.userId)?.let { + session.getUser(session.myUserId)?.let { avatarRenderer.render(it, view) } ?: run { - avatarRenderer.render(null, session.sessionParams.credentials.userId, null, view) + avatarRenderer.render(null, session.myUserId, null, view) } } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyViewModel.kt index c4da3038..1d7a6a35 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyViewModel.kt @@ -21,8 +21,8 @@ import androidx.lifecycle.ViewModel import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.listeners.StepProgressListener import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService -import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult +import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.riotx.R import im.vector.riotx.core.platform.WaitingViewData import im.vector.riotx.core.ui.views.KeysBackupBanner @@ -57,7 +57,7 @@ class KeysBackupRestoreFromKeyViewModel @Inject constructor() : ViewModel() { keysBackup.restoreKeysWithRecoveryKey(keysVersionResult, recoveryKey, null, - session.sessionParams.credentials.userId, + session.myUserId, object : StepProgressListener { override fun onStepProgress(step: StepProgressListener.Step) { when (step) { diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt index 3a4a9528..45995434 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseViewModel.kt @@ -21,8 +21,8 @@ import androidx.lifecycle.ViewModel import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.listeners.StepProgressListener import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupService -import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult +import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.riotx.R import im.vector.riotx.core.platform.WaitingViewData import im.vector.riotx.core.ui.views.KeysBackupBanner @@ -58,7 +58,7 @@ class KeysBackupRestoreFromPassphraseViewModel @Inject constructor() : ViewModel keysBackup.restoreKeyBackupWithPassword(keysVersionResult, passphrase.value!!, null, - sharedViewModel.session.sessionParams.credentials.userId, + sharedViewModel.session.myUserId, object : StepProgressListener { override fun onStepProgress(step: StepProgressListener.Step) { when (step) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/HomeDrawerFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/HomeDrawerFragment.kt index 832e8a5e..ac4cc08d 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/HomeDrawerFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/HomeDrawerFragment.kt @@ -52,7 +52,7 @@ class HomeDrawerFragment : VectorBaseFragment() { replaceChildFragment(groupListFragment, R.id.homeDrawerGroupListContainer) } - session.observeUser(session.sessionParams.credentials.userId).observeK(this) { user -> + session.observeUser(session.myUserId).observeK(this) { user -> if (user != null) { avatarRenderer.render(user.avatarUrl, user.userId, user.displayName, homeDrawerHeaderAvatarView) homeDrawerUsernameView.text = user.displayName diff --git a/vector/src/main/java/im/vector/riotx/features/home/group/GroupListViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/group/GroupListViewModel.kt index 229652b0..513379bd 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/group/GroupListViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/group/GroupListViewModel.kt @@ -93,7 +93,7 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro .rx() .liveGroupSummaries() .map { - val myUser = session.getUser(session.sessionParams.credentials.userId) + val myUser = session.getUser(session.myUserId) val allCommunityGroup = GroupSummary( groupId = ALL_COMMUNITIES_GROUP_ID, displayName = stringProvider.getString(R.string.group_all_communities), diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index bfe3d2e1..e0f67aaf 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -62,6 +62,7 @@ import im.vector.matrix.android.api.session.room.model.message.* 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.getLastMessageContent +import im.vector.matrix.android.api.session.room.timeline.getTextEditableContent import im.vector.matrix.android.api.session.user.model.User import im.vector.riotx.R import im.vector.riotx.core.di.ScreenComponent @@ -261,7 +262,7 @@ class RoomDetailFragment : composerLayout.composerRelatedMessageContent.text = formattedBody ?: nonFormattedBody - composerLayout.composerEditText.setText(if (useText) nonFormattedBody else "") + composerLayout.composerEditText.setText(if (useText) event.getTextEditableContent() else "") composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), iconRes)) avatarRenderer.render(event.senderAvatar, event.root.senderId @@ -515,7 +516,7 @@ class RoomDetailFragment : timelineEventController.setTimeline(state.timeline, state.eventId) inviteView.visibility = View.GONE - val uid = session.sessionParams.credentials.userId + val uid = session.myUserId val meMember = session.getRoom(state.roomId)?.getRoomMember(uid) avatarRenderer.render(meMember?.avatarUrl, uid, meMember?.displayName, composerLayout.composerAvatarImageView) @@ -809,7 +810,7 @@ class RoomDetailFragment : if (null != text) { // var vibrate = false - val myDisplayName = session.getUser(session.sessionParams.credentials.userId)?.displayName + val myDisplayName = session.getUser(session.myUserId)?.displayName if (TextUtils.equals(myDisplayName, text)) { // current user if (TextUtils.isEmpty(composerLayout.composerEditText.text)) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 36b989fe..20512c28 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -39,7 +39,6 @@ import im.vector.matrix.android.api.session.room.model.message.getFileUrl import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt import im.vector.matrix.rx.rx -import im.vector.riotx.R import im.vector.riotx.core.intent.getFilenameFromUri import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.resources.UserPreferencesProvider @@ -52,8 +51,6 @@ import org.commonmark.parser.Parser import org.commonmark.renderer.html.HtmlRenderer import timber.log.Timber import java.io.File -import java.text.SimpleDateFormat -import java.util.* import java.util.concurrent.TimeUnit @@ -229,16 +226,24 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } } is SendMode.EDIT -> { - val messageContent: MessageContent? = - state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel() - ?: state.sendMode.timelineEvent.root.getClearContent().toModel() - val nonFormattedBody = messageContent?.body ?: "" - if (nonFormattedBody != action.text) { - room.editTextMessage(state.sendMode.timelineEvent.root.eventId - ?: "", messageContent?.type ?: MessageType.MSGTYPE_TEXT, action.text, action.autoMarkdown) + //is original event a reply? + val inReplyTo = state.sendMode.timelineEvent.root.getClearContent().toModel()?.relatesTo?.inReplyTo?.eventId + if (inReplyTo != null) { + //TODO check if same content? + room.editReply(state.sendMode.timelineEvent, room.getTimeLineEvent(inReplyTo)?.root?.senderId, inReplyTo, action.text) } else { - Timber.w("Same message content, do not send edition") + val messageContent: MessageContent? = + state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel() + ?: state.sendMode.timelineEvent.root.getClearContent().toModel() + val existingBody = messageContent?.body ?: "" + if (existingBody != action.text) { + room.editTextMessage(state.sendMode.timelineEvent.root.eventId + ?: "", messageContent?.type + ?: MessageType.MSGTYPE_TEXT, action.text, action.autoMarkdown) + } else { + Timber.w("Same message content, do not send edition") + } } setState { copy( @@ -347,7 +352,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro } private fun handleUndoReact(action: RoomDetailActions.UndoReaction) { - room.undoReaction(action.key, action.targetEventId, session.sessionParams.credentials.userId) + room.undoReaction(action.key, action.targetEventId, session.myUserId) } @@ -355,7 +360,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro if (action.add) { room.sendReaction(action.selectedReaction, action.targetEventId) } else { - room.undoReaction(action.selectedReaction, action.targetEventId, session.sessionParams.credentials.userId) + room.undoReaction(action.selectedReaction, action.targetEventId, session.myUserId) } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageMenuViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageMenuViewModel.kt index bc21de4d..54ff3077 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageMenuViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageMenuViewModel.kt @@ -132,11 +132,11 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M this.add(SimpleAction(ACTION_REPLY, R.string.reply, R.drawable.ic_reply, eventId)) } - if (canEdit(event, session.sessionParams.credentials.userId)) { + if (canEdit(event, session.myUserId)) { this.add(SimpleAction(ACTION_EDIT, R.string.edit, R.drawable.ic_edit, eventId)) } - if (canRedact(event, session.sessionParams.credentials.userId)) { + if (canRedact(event, session.myUserId)) { this.add(SimpleAction(ACTION_DELETE, R.string.delete, R.drawable.ic_delete, eventId)) } @@ -185,7 +185,7 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M } this.add(SimpleAction(ACTION_COPY_PERMALINK, R.string.permalink, R.drawable.ic_permalink, event.root.eventId)) - if (session.sessionParams.credentials.userId != event.root.senderId && event.root.getClearType() == EventType.MESSAGE) { + if (session.myUserId != event.root.senderId && event.root.getClearType() == EventType.MESSAGE) { //not sent by me this.add(SimpleAction(ACTION_FLAG, R.string.report_content, R.drawable.ic_flag, event.root.eventId)) } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewEditHistoryEpoxyController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewEditHistoryEpoxyController.kt index 4ae62fbd..34e34073 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewEditHistoryEpoxyController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewEditHistoryEpoxyController.kt @@ -26,6 +26,7 @@ import com.airbnb.mvrx.Success 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.room.model.message.MessageTextContent +import im.vector.matrix.android.api.util.ContentUtils.extractUsefulTextFromReply import im.vector.riotx.R import im.vector.riotx.core.extensions.localDateTime import im.vector.riotx.core.ui.list.genericFooterItem @@ -60,13 +61,13 @@ class ViewEditHistoryEpoxyController(private val context: Context, } } is Success -> { - state.editList()?.let { renderEvents(it) } + state.editList()?.let { renderEvents(it, state.isOriginalAReply) } } } } - private fun renderEvents(sourceEvents: List) { + private fun renderEvents(sourceEvents: List, isOriginalReply: Boolean) { if (sourceEvents.isEmpty()) { genericItem { id("footer") @@ -92,7 +93,7 @@ class ViewEditHistoryEpoxyController(private val context: Context, } } lastDate = evDate - val cContent = getCorrectContent(timelineEvent) + val cContent = getCorrectContent(timelineEvent, isOriginalReply) val body = cContent.second?.let { eventHtmlRenderer.render(it) } ?: cContent.first @@ -101,7 +102,7 @@ class ViewEditHistoryEpoxyController(private val context: Context, var spannedDiff: Spannable? = null if (nextEvent != null && cContent.second == null /*No diff for html*/) { //compares the body - val nContent = getCorrectContent(nextEvent) + val nContent = getCorrectContent(nextEvent, isOriginalReply) val nextBody = nContent.second?.let { eventHtmlRenderer.render(it) } ?: nContent.first val dmp = diff_match_patch() @@ -144,11 +145,14 @@ class ViewEditHistoryEpoxyController(private val context: Context, } } - private fun getCorrectContent(event: Event): Pair { + private fun getCorrectContent(event: Event, isOriginalReply: Boolean): Pair { val clearContent = event.getClearContent().toModel() val newContent = clearContent ?.newContent ?.toModel() + if (isOriginalReply) { + return extractUsefulTextFromReply(newContent?.body ?: clearContent?.body ?: "") to null + } return (newContent?.body ?: clearContent?.body ?: "") to (newContent?.formattedBody ?: clearContent?.formattedBody) } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewEditHistoryViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewEditHistoryViewModel.kt index 64005c3f..576ef5e9 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewEditHistoryViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/ViewEditHistoryViewModel.kt @@ -21,6 +21,9 @@ import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.events.model.Event +import im.vector.matrix.android.api.session.events.model.toModel +import im.vector.matrix.android.api.session.room.model.message.MessageContent +import im.vector.matrix.android.api.session.room.model.message.isReply import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDateFormatter @@ -28,6 +31,7 @@ import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDateFor data class ViewEditHistoryViewState( val eventId: String, val roomId: String, + val isOriginalAReply: Boolean = false, val editList: Async> = Uninitialized) : MvRxState { @@ -77,11 +81,16 @@ class ViewEditHistoryViewModel @AssistedInject constructor(@Assisted override fun onSuccess(data: List) { //TODO until supported by API Add original event manually val withOriginal = data.toMutableList() + var originalIsReply = false room.getTimeLineEvent(eventId)?.let { withOriginal.add(it.root) + originalIsReply = it.root.getClearContent().toModel().isReply() } setState { - copy(editList = Success(withOriginal)) + copy( + editList = Success(withOriginal), + isOriginalAReply = originalIsReply + ) } } }) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/filtered/FilteredRoomFooterItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/filtered/FilteredRoomFooterItem.kt index 0e916a0e..777f0d32 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/filtered/FilteredRoomFooterItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/filtered/FilteredRoomFooterItem.kt @@ -30,10 +30,13 @@ abstract class FilteredRoomFooterItem : VectorEpoxyModel { isLoginNotEmpty, isPasswordNotEmpty, isHomeServerNotEmpty -> isLoginNotEmpty && isPasswordNotEmpty && isHomeServerNotEmpty } diff --git a/vector/src/main/java/im/vector/riotx/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/riotx/features/navigation/DefaultNavigator.kt index c9af93a3..2e34a7d1 100644 --- a/vector/src/main/java/im/vector/riotx/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/riotx/features/navigation/DefaultNavigator.kt @@ -58,13 +58,13 @@ class DefaultNavigator @Inject constructor() : Navigator { context.startActivity(intent) } - override fun openRoomDirectory(context: Context) { - val intent = Intent(context, RoomDirectoryActivity::class.java) + override fun openRoomDirectory(context: Context, initialFilter: String) { + val intent = RoomDirectoryActivity.getIntent(context, initialFilter) context.startActivity(intent) } - override fun openCreateRoom(context: Context) { - val intent = CreateRoomActivity.getIntent(context) + override fun openCreateRoom(context: Context, initialName: String) { + val intent = CreateRoomActivity.getIntent(context, initialName) context.startActivity(intent) } diff --git a/vector/src/main/java/im/vector/riotx/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/riotx/features/navigation/Navigator.kt index 48f77118..bf888ffe 100644 --- a/vector/src/main/java/im/vector/riotx/features/navigation/Navigator.kt +++ b/vector/src/main/java/im/vector/riotx/features/navigation/Navigator.kt @@ -27,9 +27,9 @@ interface Navigator { fun openRoomPreview(publicRoom: PublicRoom, context: Context) - fun openCreateRoom(context: Context) + fun openCreateRoom(context: Context, initialName: String = "") - fun openRoomDirectory(context: Context) + fun openRoomDirectory(context: Context, initialFilter: String = "") fun openRoomsFiltering(context: Context) diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEventResolver.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEventResolver.kt index a98c7535..6650bf0d 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEventResolver.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotifiableEventResolver.kt @@ -70,7 +70,7 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St val bodyPreview = event.type return SimpleNotifiableEvent( - session.sessionParams.credentials.userId, + session.myUserId, eventId = event.eventId!!, noisy = false,//will be updated timestamp = event.originServerTs ?: System.currentTimeMillis(), @@ -109,7 +109,7 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St roomId = event.root.roomId!!, roomName = roomName) - notifiableEvent.matrixID = session.sessionParams.credentials.userId + notifiableEvent.matrixID = session.myUserId return notifiableEvent } else { if (event.root.isEncrypted() && event.root.mxDecryptionResult == null) { @@ -145,7 +145,7 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St roomName = roomName, roomIsDirect = room.roomSummary()?.isDirect ?: false) - notifiableEvent.matrixID = session.sessionParams.credentials.userId + notifiableEvent.matrixID = session.myUserId notifiableEvent.soundName = null // Get the avatars URL @@ -175,7 +175,7 @@ class NotifiableEventResolver @Inject constructor(private val stringProvider: St val body = noticeEventFormatter.format(event, dName) ?: stringProvider.getString(R.string.notification_new_invitation) return InviteNotifiableEvent( - session.sessionParams.credentials.userId, + session.myUserId, eventId = event.eventId!!, roomId = roomId, timestamp = event.originServerTs ?: 0, diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationBroadcastReceiver.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationBroadcastReceiver.kt index 17a1b222..ac6068b0 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationBroadcastReceiver.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationBroadcastReceiver.kt @@ -121,9 +121,9 @@ class NotificationBroadcastReceiver : BroadcastReceiver() { UUID.randomUUID().toString(), false, System.currentTimeMillis(), - session.getUser(session.sessionParams.credentials.userId)?.displayName + session.getUser(session.myUserId)?.displayName ?: context?.getString(R.string.notification_sender_me), - session.sessionParams.credentials.userId, + session.myUserId, message, room.roomId, room.roomSummary()?.displayName ?: room.roomId, diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationDrawerManager.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationDrawerManager.kt index 72a9e1e3..45317da5 100644 --- a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationDrawerManager.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationDrawerManager.kt @@ -181,8 +181,9 @@ class NotificationDrawerManager @Inject constructor(private val context: Context val session = activeSessionHolder.getSafeActiveSession() ?: return - val user = session.getUser(session.sessionParams.credentials.userId) - val myUserDisplayName = user?.displayName ?: session.sessionParams.credentials.userId + val user = session.getUser(session.myUserId) + // myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash + val myUserDisplayName = user?.displayName?.takeIf { it.isNotBlank() } ?: session.myUserId val myUserAvatarUrl = session.contentUrlResolver().resolveThumbnail(user?.avatarUrl, avatarSize, avatarSize, ContentUrlResolver.ThumbnailMethod.SCALE) synchronized(eventList) { @@ -343,7 +344,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context for (event in simpleEvents) { //We build a simple event if (firstTime || !event.hasBeenDisplayed) { - NotificationUtils.buildSimpleEventNotification(context, event, null, myUserDisplayName)?.let { + NotificationUtils.buildSimpleEventNotification(context, event, null, session.myUserId)?.let { notifications.add(it) NotificationUtils.showNotificationMessage(context, event.eventId, ROOM_EVENT_NOTIFICATION_ID, it) event.hasBeenDisplayed = true //we can consider it as displayed diff --git a/vector/src/main/java/im/vector/riotx/features/rageshake/BugReporter.kt b/vector/src/main/java/im/vector/riotx/features/rageshake/BugReporter.kt index 774bdfb9..d34d2be4 100755 --- a/vector/src/main/java/im/vector/riotx/features/rageshake/BugReporter.kt +++ b/vector/src/main/java/im/vector/riotx/features/rageshake/BugReporter.kt @@ -204,7 +204,7 @@ class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSes var olmVersion = "undefined" activeSessionHolder.getSafeActiveSession()?.let { session -> - userId = session.sessionParams.credentials.userId + userId = session.myUserId deviceId = session.sessionParams.credentials.deviceId ?: "undefined" olmVersion = session.getCryptoVersion(context, true) } diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsFragment.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsFragment.kt index 873f8b8b..f072b1f4 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsFragment.kt @@ -25,14 +25,13 @@ import com.airbnb.epoxy.EpoxyVisibilityTracker import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState import com.google.android.material.snackbar.Snackbar -import com.jakewharton.rxbinding2.widget.RxTextView +import com.jakewharton.rxbinding3.appcompat.queryTextChanges import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom import im.vector.riotx.R import im.vector.riotx.core.di.ScreenComponent import im.vector.riotx.core.error.ErrorFormatter import im.vector.riotx.core.extensions.observeEvent import im.vector.riotx.core.platform.VectorBaseFragment -import im.vector.riotx.features.themes.ThemeUtils import io.reactivex.rxkotlin.subscribeBy import kotlinx.android.synthetic.main.fragment_public_rooms.* import timber.log.Timber @@ -70,9 +69,7 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback it.setDisplayHomeAsUpEnabled(true) } - publicRoomsFilter.setBackgroundResource(ThemeUtils.getResourceId(requireContext(), R.drawable.bg_search_edit_text_light)) - - RxTextView.textChanges(publicRoomsFilter) + publicRoomsFilter.queryTextChanges() .debounce(500, TimeUnit.MILLISECONDS) .subscribeBy { viewModel.filterWith(it.toString()) @@ -147,6 +144,11 @@ class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback } override fun invalidate() = withState(viewModel) { state -> + if (publicRoomsFilter.text.toString() != state.currentFilter) { + // For initial filter + publicRoomsFilter.setText(state.currentFilter) + } + // Populate list with Epoxy publicRoomsController.setData(state) } diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsViewState.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsViewState.kt index 0ad1ac26..549d81cc 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsViewState.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsViewState.kt @@ -22,6 +22,8 @@ import com.airbnb.mvrx.Uninitialized import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom data class PublicRoomsViewState( + // The current filter + val currentFilter: String = "", // Store cumul of pagination result val publicRooms: List = emptyList(), // Current pagination request diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryActivity.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryActivity.kt index d708de94..d3cefad2 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryActivity.kt @@ -16,8 +16,11 @@ package im.vector.riotx.features.roomdirectory +import android.content.Context +import android.content.Intent import android.os.Bundle import androidx.lifecycle.ViewModelProviders +import com.airbnb.mvrx.viewModel import im.vector.riotx.R import im.vector.riotx.core.di.ScreenComponent import im.vector.riotx.core.extensions.addFragment @@ -25,6 +28,7 @@ import im.vector.riotx.core.extensions.addFragmentToBackstack import im.vector.riotx.core.extensions.observeEvent import im.vector.riotx.core.platform.VectorBaseActivity import im.vector.riotx.features.roomdirectory.createroom.CreateRoomFragment +import im.vector.riotx.features.roomdirectory.createroom.CreateRoomViewModel import im.vector.riotx.features.roomdirectory.picker.RoomDirectoryPickerFragment import javax.inject.Inject @@ -39,7 +43,10 @@ class RoomDirectoryActivity : VectorBaseActivity() { } + @Inject lateinit var createRoomViewModelFactory: CreateRoomViewModel.Factory @Inject lateinit var roomDirectoryViewModelFactory: RoomDirectoryViewModel.Factory + private val roomDirectoryViewModel: RoomDirectoryViewModel by viewModel() + private val createRoomViewModel: CreateRoomViewModel by viewModel() private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel override fun getLayoutRes() = R.layout.activity_simple @@ -51,6 +58,11 @@ class RoomDirectoryActivity : VectorBaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) navigationViewModel = ViewModelProviders.of(this, viewModelFactory).get(RoomDirectoryNavigationViewModel::class.java) + + if (isFirstCreation()) { + roomDirectoryViewModel.filterWith(intent?.getStringExtra(INITIAL_FILTER) ?: "") + } + navigationViewModel.navigateTo.observeEvent(this) { navigation -> when (navigation) { is Navigation.Back -> onBackPressed() @@ -59,6 +71,11 @@ class RoomDirectoryActivity : VectorBaseActivity() { is Navigation.Close -> finish() } } + + roomDirectoryViewModel.selectSubscribe(this, PublicRoomsViewState::currentFilter) { currentFilter -> + // Transmit the filter to the createRoomViewModel + createRoomViewModel.setName(currentFilter) + } } override fun initUiAndData() { @@ -67,4 +84,13 @@ class RoomDirectoryActivity : VectorBaseActivity() { } } + companion object { + private const val INITIAL_FILTER = "INITIAL_FILTER" + + fun getIntent(context: Context, initialFilter: String = ""): Intent { + val intent = Intent(context, RoomDirectoryActivity::class.java) + intent.putExtra(INITIAL_FILTER, initialFilter) + return intent + } + } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewModel.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewModel.kt index b34618e2..c47e8bbd 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryViewModel.kt @@ -59,9 +59,6 @@ class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: get() = _joinRoomErrorLiveData - // TODO Store in ViewState? - private var currentFilter: String = "" - private var since: String? = null private var currentTask: Cancelable? = null @@ -70,9 +67,6 @@ class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: private var roomDirectoryData = RoomDirectoryData() init { - // Load with empty filter - load() - setState { copy( roomDirectoryDisplayName = roomDirectoryData.displayName @@ -115,24 +109,20 @@ class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: this.roomDirectoryData = roomDirectoryData - reset() - load() + reset("") + load("") } - fun filterWith(filter: String) { - if (currentFilter == filter) { - return + fun filterWith(filter: String) = withState { state -> + if (state.currentFilter != filter) { + currentTask?.cancel() + + reset(filter) + load(filter) } - - currentTask?.cancel() - - currentFilter = filter - - reset() - load() } - private fun reset() { + private fun reset(newFilter: String) { // Reset since token since = null @@ -141,12 +131,13 @@ class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: publicRooms = emptyList(), asyncPublicRoomsRequest = Loading(), hasMore = false, - roomDirectoryDisplayName = roomDirectoryData.displayName + roomDirectoryDisplayName = roomDirectoryData.displayName, + currentFilter = newFilter ) } } - fun loadMore() { + fun loadMore() = withState { state -> if (currentTask == null) { setState { copy( @@ -154,15 +145,15 @@ class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState: ) } - load() + load(state.currentFilter) } } - private fun load() { + private fun load(filter: String) { currentTask = session.getPublicRooms(roomDirectoryData.homeServer, PublicRoomsParams( limit = PUBLIC_ROOMS_LIMIT, - filter = PublicRoomsFilter(searchTerm = currentFilter), + filter = PublicRoomsFilter(searchTerm = filter), includeAllNetworks = roomDirectoryData.includeAllNetworks, since = since, thirdPartyInstanceId = roomDirectoryData.thirdPartyInstanceId diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomActivity.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomActivity.kt index ffc342d8..d6cca2b6 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomActivity.kt @@ -21,6 +21,7 @@ import android.content.Intent import android.os.Bundle import androidx.appcompat.widget.Toolbar import androidx.lifecycle.ViewModelProviders +import com.airbnb.mvrx.viewModel import im.vector.riotx.R import im.vector.riotx.core.di.ScreenComponent import im.vector.riotx.core.extensions.addFragment @@ -29,12 +30,16 @@ import im.vector.riotx.core.platform.ToolbarConfigurable import im.vector.riotx.core.platform.VectorBaseActivity import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity import im.vector.riotx.features.roomdirectory.RoomDirectoryNavigationViewModel +import javax.inject.Inject /** * Simple container for [CreateRoomFragment] */ class CreateRoomActivity : VectorBaseActivity(), ToolbarConfigurable { + @Inject lateinit var createRoomViewModelFactory: CreateRoomViewModel.Factory + private val createRoomViewModel: CreateRoomViewModel by viewModel() + private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel override fun getLayoutRes() = R.layout.activity_simple @@ -46,6 +51,8 @@ class CreateRoomActivity : VectorBaseActivity(), ToolbarConfigurable { override fun initUiAndData() { if (isFirstCreation()) { addFragment(CreateRoomFragment(), R.id.simpleFragmentContainer) + + createRoomViewModel.setName(intent?.getStringExtra(INITIAL_NAME) ?: "") } } @@ -58,14 +65,19 @@ class CreateRoomActivity : VectorBaseActivity(), ToolbarConfigurable { navigationViewModel = ViewModelProviders.of(this, viewModelFactory).get(RoomDirectoryNavigationViewModel::class.java) navigationViewModel.navigateTo.observeEvent(this) { navigation -> when (navigation) { - is RoomDirectoryActivity.Navigation.Back -> finish() + is RoomDirectoryActivity.Navigation.Back, + is RoomDirectoryActivity.Navigation.Close -> finish() } } } companion object { - fun getIntent(context: Context): Intent { - return Intent(context, CreateRoomActivity::class.java) + private const val INITIAL_NAME = "INITIAL_NAME" + + fun getIntent(context: Context, initialName: String = ""): Intent { + return Intent(context, CreateRoomActivity::class.java).apply { + putExtra(INITIAL_NAME, initialName) + } } } diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomFragment.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomFragment.kt index 28dc761a..3a007901 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomFragment.kt @@ -21,7 +21,7 @@ import android.view.MenuItem import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.LinearLayoutManager import com.airbnb.mvrx.Success -import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState import im.vector.riotx.R import im.vector.riotx.core.di.ScreenComponent @@ -35,9 +35,8 @@ import javax.inject.Inject class CreateRoomFragment : VectorBaseFragment(), CreateRoomController.Listener { private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel - private val viewModel: CreateRoomViewModel by fragmentViewModel() + private val viewModel: CreateRoomViewModel by activityViewModel() @Inject lateinit var createRoomController: CreateRoomController - @Inject lateinit var createRoomViewModelFactory: CreateRoomViewModel.Factory override fun getLayoutResId() = R.layout.fragment_create_room diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomViewModel.kt index c6a4ff17..f0ee0115 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -16,6 +16,7 @@ package im.vector.riotx.features.roomdirectory.createroom +import androidx.fragment.app.FragmentActivity import com.airbnb.mvrx.* import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject @@ -25,6 +26,7 @@ import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.session.room.model.create.CreateRoomPreset import im.vector.riotx.core.platform.VectorViewModel +import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: CreateRoomViewState, private val session: Session @@ -39,8 +41,13 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted initialState: Cr @JvmStatic override fun create(viewModelContext: ViewModelContext, state: CreateRoomViewState): CreateRoomViewModel? { - val fragment: CreateRoomFragment = (viewModelContext as FragmentViewModelContext).fragment() - return fragment.createRoomViewModelFactory.create(state) + val activity: FragmentActivity = (viewModelContext as ActivityViewModelContext).activity() + + return when (activity) { + is CreateRoomActivity -> activity.createRoomViewModelFactory.create(state) + is RoomDirectoryActivity -> activity.createRoomViewModelFactory.create(state) + else -> throw IllegalStateException("Wrong activity") + } } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsActivity.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsActivity.kt index 7fd60562..5db218c3 100755 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsActivity.kt @@ -79,9 +79,9 @@ class VectorSettingsActivity : VectorBaseActivity(), var oFragment: Fragment? = null if (VectorPreferences.SETTINGS_NOTIFICATION_TROUBLESHOOT_PREFERENCE_KEY == pref?.key) { - oFragment = VectorSettingsNotificationsTroubleshootFragment.newInstance(session.sessionParams.credentials.userId) + oFragment = VectorSettingsNotificationsTroubleshootFragment.newInstance(session.myUserId) } else if (VectorPreferences.SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY == pref?.key) { - oFragment = VectorSettingsAdvancedNotificationPreferenceFragment.newInstance(session.sessionParams.credentials.userId) + oFragment = VectorSettingsAdvancedNotificationPreferenceFragment.newInstance(session.myUserId) } else { try { pref?.fragment?.let { diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsGeneralFragment.kt index 63246b25..2bec8cf1 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsGeneralFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsGeneralFragment.kt @@ -95,7 +95,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() { // Display name mDisplayNamePreference.let { - it.summary = session.getUser(session.sessionParams.credentials.userId)?.displayName ?: "" + it.summary = session.getUser(session.myUserId)?.displayName ?: "" it.text = it.summary.toString() it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> onDisplayNameClick(newValue?.let { (it as String).trim() }) @@ -148,7 +148,7 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() { // user account findPreference(VectorPreferences.SETTINGS_LOGGED_IN_PREFERENCE_KEY) - .summary = session.sessionParams.credentials.userId + .summary = session.myUserId // home server findPreference(VectorPreferences.SETTINGS_HOME_SERVER_PREFERENCE_KEY) diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsSecurityPrivacyFragment.kt index 10a4fcce..06a33434 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -367,7 +367,7 @@ class VectorSettingsSecurityPrivacyFragment : VectorSettingsBaseFragment() { * @param aMyDeviceInfo the device info */ private fun refreshCryptographyPreference(aMyDeviceInfo: DeviceInfo?) { - val userId = session.sessionParams.credentials.userId + val userId = session.myUserId val deviceId = session.sessionParams.credentials.deviceId // device name diff --git a/vector/src/main/java/im/vector/riotx/features/workers/signout/SignOutUiWorker.kt b/vector/src/main/java/im/vector/riotx/features/workers/signout/SignOutUiWorker.kt index e3e7fb30..fd0af94f 100644 --- a/vector/src/main/java/im/vector/riotx/features/workers/signout/SignOutUiWorker.kt +++ b/vector/src/main/java/im/vector/riotx/features/workers/signout/SignOutUiWorker.kt @@ -35,7 +35,7 @@ class SignOutUiWorker(private val activity: FragmentActivity) { activeSessionHolder = context.vectorComponent().activeSessionHolder() val session = activeSessionHolder.getActiveSession() if (SignOutViewModel.doYouNeedToBeDisplayed(session)) { - val signOutDialog = SignOutBottomSheetDialogFragment.newInstance(session.sessionParams.credentials.userId) + val signOutDialog = SignOutBottomSheetDialogFragment.newInstance(session.myUserId) signOutDialog.onSignOut = Runnable { doSignOut() } diff --git a/vector/src/main/res/drawable/ic_search.xml b/vector/src/main/res/drawable/ic_search.xml new file mode 100644 index 00000000..e2a66c77 --- /dev/null +++ b/vector/src/main/res/drawable/ic_search.xml @@ -0,0 +1,22 @@ + + + + diff --git a/vector/src/main/res/layout/activity_filtered_rooms.xml b/vector/src/main/res/layout/activity_filtered_rooms.xml index aa65778a..4e26bc0e 100644 --- a/vector/src/main/res/layout/activity_filtered_rooms.xml +++ b/vector/src/main/res/layout/activity_filtered_rooms.xml @@ -14,17 +14,17 @@ android:layout_width="0dp" android:layout_height="?attr/actionBarSize" android:elevation="4dp" + app:contentInsetStart="0dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> diff --git a/vector/src/main/res/layout/fragment_create_room.xml b/vector/src/main/res/layout/fragment_create_room.xml index f5eeeb31..301d5dee 100644 --- a/vector/src/main/res/layout/fragment_create_room.xml +++ b/vector/src/main/res/layout/fragment_create_room.xml @@ -11,10 +11,10 @@ diff --git a/vector/src/main/res/layout/fragment_home_detail.xml b/vector/src/main/res/layout/fragment_home_detail.xml index 5ee80314..13d3fea8 100644 --- a/vector/src/main/res/layout/fragment_home_detail.xml +++ b/vector/src/main/res/layout/fragment_home_detail.xml @@ -8,10 +8,10 @@ diff --git a/vector/src/main/res/layout/fragment_public_rooms.xml b/vector/src/main/res/layout/fragment_public_rooms.xml index de6fa436..99fbd896 100644 --- a/vector/src/main/res/layout/fragment_public_rooms.xml +++ b/vector/src/main/res/layout/fragment_public_rooms.xml @@ -23,36 +23,22 @@ - - + android:layout_height="wrap_content" + app:queryHint="@string/room_directory_search_hint" /> diff --git a/vector/src/main/res/layout/fragment_room_detail.xml b/vector/src/main/res/layout/fragment_room_detail.xml index 95093ca8..c0e37139 100644 --- a/vector/src/main/res/layout/fragment_room_detail.xml +++ b/vector/src/main/res/layout/fragment_room_detail.xml @@ -8,10 +8,10 @@ diff --git a/vector/src/main/res/layout/fragment_room_list.xml b/vector/src/main/res/layout/fragment_room_list.xml index d4b6bd0f..c3fa4530 100644 --- a/vector/src/main/res/layout/fragment_room_list.xml +++ b/vector/src/main/res/layout/fragment_room_list.xml @@ -8,7 +8,7 @@ android:background="?riotx_header_panel_background"> diff --git a/vector/src/main/res/layout/fragment_room_preview_no_preview.xml b/vector/src/main/res/layout/fragment_room_preview_no_preview.xml index d6a154da..ee8f87fc 100644 --- a/vector/src/main/res/layout/fragment_room_preview_no_preview.xml +++ b/vector/src/main/res/layout/fragment_room_preview_no_preview.xml @@ -13,10 +13,10 @@ + android:elevation="4dp"> No edits found + Filter conversations… Can’t find what you’re looking for? Create a new room Send a new direct message View the room directory + Name or ID (#example:matrix.org) + Enable swipe to reply in timeline \ No newline at end of file diff --git a/vector/src/main/res/values/styles_riot.xml b/vector/src/main/res/values/styles_riot.xml index 78907193..91753271 100644 --- a/vector/src/main/res/values/styles_riot.xml +++ b/vector/src/main/res/values/styles_riot.xml @@ -9,6 +9,7 @@ @style/Vector.Toolbar.Title @style/Vector.Toolbar.SubTitle ?riotx_background + 0dp + +