From 9fa285e6ca8e0ed276a2b287b5160a418938019b Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 8 Mar 2022 14:06:28 +0300 Subject: [PATCH 01/45] Support showing push notifications for poll start events. --- .../app/features/notifications/NotifiableEventResolver.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt index ec034173fc..0cf586afea 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt @@ -94,7 +94,7 @@ class NotifiableEventResolver @Inject constructor( } suspend fun resolveInMemoryEvent(session: Session, event: Event, canBeReplaced: Boolean): NotifiableEvent? { - if (event.getClearType() != EventType.MESSAGE) return null + if (event.getClearType() !in listOf(EventType.MESSAGE, EventType.POLL_START)) return null // Ignore message edition if (event.isEdition()) return null @@ -153,7 +153,8 @@ class NotifiableEventResolver @Inject constructor( event.attemptToDecryptIfNeeded(session) // only convert encrypted messages to NotifiableMessageEvents when (event.root.getClearType()) { - EventType.MESSAGE -> { + EventType.MESSAGE, + EventType.POLL_START -> { val body = displayableEventFormatter.format(event, isDm = room.roomSummary()?.isDirect.orFalse(), appendAuthor = false).toString() val roomName = room.roomSummary()?.displayName ?: "" val senderDisplayName = event.senderInfo.disambiguatedDisplayName @@ -185,7 +186,7 @@ class NotifiableEventResolver @Inject constructor( soundName = null ) } - else -> null + else -> null } } } From 7a1d3aa3f27fb184bea9e082321e69cec13d1ca2 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 8 Mar 2022 14:07:14 +0300 Subject: [PATCH 02/45] Filter poll response events in latest event query. --- .../sdk/internal/database/query/TimelineEventEntityQueries.kt | 1 + .../android/sdk/internal/database/query/TimelineEventFilter.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt index 63f41ebf2c..81d5ac835f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventEntityQueries.kt @@ -97,6 +97,7 @@ internal fun RealmQuery.filterEvents(filters: TimelineEvent if (filters.filterEdits) { not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.EDIT) not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.RESPONSE) + not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.REFERENCE) } if (filters.filterRedacted) { not().like(TimelineEventEntityFields.ROOT.UNSIGNED_DATA, TimelineEventFilter.Unsigned.REDACTED) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventFilter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventFilter.kt index 10a0d1dcec..a7317506a0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventFilter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/TimelineEventFilter.kt @@ -26,6 +26,7 @@ internal object TimelineEventFilter { internal object Content { internal const val EDIT = """{*"m.relates_to"*"rel_type":*"m.replace"*}""" internal const val RESPONSE = """{*"m.relates_to"*"rel_type":*"org.matrix.response"*}""" + internal const val REFERENCE = """{*"m.relates_to"*"rel_type":*"m.reference"*}""" } /** From 83ff898ce5399d5bbe301143068d4f77ef1d7be8 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 8 Mar 2022 14:14:45 +0300 Subject: [PATCH 03/45] Changelog added. --- changelog.d/4780.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/4780.bugfix diff --git a/changelog.d/4780.bugfix b/changelog.d/4780.bugfix new file mode 100644 index 0000000000..51eb1e4ad7 --- /dev/null +++ b/changelog.d/4780.bugfix @@ -0,0 +1 @@ +Poll system notifications on Android are not user friendly \ No newline at end of file From 5dfa3623453ff8be873f500fec5d8c1d19a9525d Mon Sep 17 00:00:00 2001 From: bmarty Date: Mon, 14 Mar 2022 00:05:30 +0000 Subject: [PATCH 04/45] Sync analytics plan --- .../app/features/analytics/plan/Composer.kt | 5 ++ .../features/analytics/plan/Interaction.kt | 51 ++++++++++++++++++- .../features/analytics/plan/MobileScreen.kt | 5 ++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Composer.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Composer.kt index a3b847a1bd..79be8aae2b 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/Composer.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Composer.kt @@ -39,6 +39,10 @@ data class Composer( * sent event. */ val isReply: Boolean, + /** + * Whether this message begins a new thread or not. + */ + val startsThread: Boolean? = null, ) : VectorAnalyticsEvent { override fun getName() = "Composer" @@ -48,6 +52,7 @@ data class Composer( put("inThread", inThread) put("isEditing", isEditing) put("isReply", isReply) + startsThread?.let { put("startsThread", it) } }.takeIf { it.isNotEmpty() } } } diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt index 4c00cfd014..2007f75fbc 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt @@ -50,6 +50,26 @@ data class Interaction( */ MobileRoomLeave, + /** + * User tapped on Threads button on Room screen. + */ + MobileRoomThreadListButton, + + /** + * User tapped on a thread summary item on Room screen. + */ + MobileRoomThreadSummaryItem, + + /** + * User tapped on the filter button on ThreadList screen. + */ + MobileThreadListFilterItem, + + /** + * User selected a thread on ThreadList screen. + */ + MobileThreadListThreadItem, + /** * User tapped the already selected space from the space list. */ @@ -115,12 +135,24 @@ data class Interaction( */ WebRightPanelRoomUserInfoInviteButton, + /** + * User clicked the threads 'show' filter dropdown in the threads panel + * in Element Web/Desktop. + */ + WebRightPanelThreadPanelFilterDropdown, + /** * User clicked the create room button in the room directory of Element * Web/Desktop. */ WebRoomDirectoryCreateRoomButton, + /** + * User clicked the Threads button in the top right of a room in Element + * Web/Desktop. + */ + WebRoomHeaderButtonsThreadsButton, + /** * User adjusted their favourites using the context menu on the header * of a room in Element Web/Desktop. @@ -207,7 +239,7 @@ data class Interaction( /** * User clicked the explore rooms button in the + context menu of the - * rooms sublist in Element Web/Desktop. + * rooms sublist in Element Web/Desktop. */ WebRoomListRoomsSublistPlusMenuExploreRoomsItem, @@ -223,6 +255,12 @@ data class Interaction( */ WebRoomSettingsSecurityTabCreateNewRoomButton, + /** + * User clicked a thread summary in the timeline of a room in Element + * Web/Desktop. + */ + WebRoomTimelineThreadSummaryButton, + /** * User interacted with the theme radio selector in the Appearance tab * of Settings in Element Web/Desktop. @@ -259,6 +297,17 @@ data class Interaction( */ WebSpaceHomeCreateRoomButton, + /** + * User clicked the back button on a Thread view going back to the + * Threads Panel of Element Web/Desktop. + */ + WebThreadViewBackButton, + + /** + * User selected a thread in the Threads panel in Element Web/Desktop. + */ + WebThreadsPanelThreadItem, + /** * User clicked the theme toggle button in the user menu of Element * Web/Desktop. diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt index 29b6667cca..79bae544ec 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt @@ -286,6 +286,11 @@ data class MobileScreen( */ SwitchDirectory, + /** + * Screen that displays list of threads for a room + */ + ThreadList, + /** * A screen that shows information about a room member. */ From 4cf820cb12190339af911c863da1f226c32fa66b Mon Sep 17 00:00:00 2001 From: Arnaud Ringenbach Date: Mon, 14 Mar 2022 11:59:10 +0100 Subject: [PATCH 05/45] Use client permalink base url on mentions if available --- .../session/room/send/MarkdownParserTest.kt | 4 ++ .../session/permalinks/PermalinkFactory.kt | 2 +- .../session/room/send/pills/TextPillsUtils.kt | 49 ++++++++++++++++--- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt index 9856ee7770..9d8eacccf2 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt @@ -60,6 +60,10 @@ class MarkdownParserTest : InstrumentedTest { applicationFlavor = "TestFlavor", roomDisplayNameFallbackProvider = TestRoomDisplayNameFallbackProvider() ) + ), + MatrixConfiguration( + applicationFlavor = "TestFlavor", + roomDisplayNameFallbackProvider = TestRoomDisplayNameFallbackProvider() )) ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt index 39c1ddfdce..377b083bd6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt @@ -145,7 +145,7 @@ internal class PermalinkFactory @Inject constructor( companion object { private const val ROOM_PATH = "room/" - private const val USER_PATH = "user/" + const val USER_PATH = "user/" private const val GROUP_PATH = "group/" } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt index ccbfbfcded..3edae5e26a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt @@ -16,9 +16,12 @@ package org.matrix.android.sdk.internal.session.room.send.pills import android.text.SpannableString +import org.matrix.android.sdk.api.MatrixConfiguration +import org.matrix.android.sdk.api.session.permalinks.PermalinkService.Companion.MATRIX_TO_URL_BASE import org.matrix.android.sdk.api.session.room.send.MatrixItemSpan import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.internal.session.displayname.DisplayNameResolver +import org.matrix.android.sdk.internal.session.permalinks.PermalinkFactory import java.util.Collections import javax.inject.Inject @@ -28,7 +31,8 @@ import javax.inject.Inject */ internal class TextPillsUtils @Inject constructor( private val mentionLinkSpecComparator: MentionLinkSpecComparator, - private val displayNameResolver: DisplayNameResolver + private val displayNameResolver: DisplayNameResolver, + private val matrixConfiguration: MatrixConfiguration ) { /** @@ -36,7 +40,7 @@ internal class TextPillsUtils @Inject constructor( * @return the transformed String or null if no Span found */ fun processSpecialSpansToHtml(text: CharSequence): String? { - return transformPills(text, MENTION_SPAN_TO_HTML_TEMPLATE) + return transformPills(text, createHtmlMentionSpanTemplate(forceMatrixTo = false)) } /** @@ -44,7 +48,7 @@ internal class TextPillsUtils @Inject constructor( * @return the transformed String or null if no Span found */ fun processSpecialSpansToMarkdown(text: CharSequence): String? { - return transformPills(text, MENTION_SPAN_TO_MD_TEMPLATE) + return transformPills(text, createMdMentionSpanTemplate(forceMatrixTo = false)) } private fun transformPills(text: CharSequence, template: String): String? { @@ -109,9 +113,42 @@ internal class TextPillsUtils @Inject constructor( } } - companion object { - private const val MENTION_SPAN_TO_HTML_TEMPLATE = "%2\$s" + private fun baseUrl(forceMatrixTo: Boolean): String { + return matrixConfiguration.clientPermalinkBaseUrl + ?.takeUnless { forceMatrixTo } + ?: MATRIX_TO_URL_BASE + } - private const val MENTION_SPAN_TO_MD_TEMPLATE = "[%2\$s](https://matrix.to/#/%1\$s)" + private fun useClientFormat(forceMatrixTo: Boolean): Boolean { + return !forceMatrixTo && matrixConfiguration.clientPermalinkBaseUrl != null + } + + private fun createHtmlMentionSpanTemplate(forceMatrixTo: Boolean): String { + return buildString { + append(MENTION_SPAN_TO_HTML_TEMPLATE_BEGIN) + append(baseUrl(forceMatrixTo)) + if (useClientFormat(forceMatrixTo)) { + append(PermalinkFactory.USER_PATH) + } + append(MENTION_SPAN_TO_HTML_TEMPLATE_END) + } + } + + private fun createMdMentionSpanTemplate(forceMatrixTo: Boolean): String { + return buildString { + append(MENTION_SPAN_TO_MD_TEMPLATE_BEGIN) + append(baseUrl(forceMatrixTo)) + if (useClientFormat(forceMatrixTo)) { + append(PermalinkFactory.USER_PATH) + } + append(MENTION_SPAN_TO_MD_TEMPLATE_END) + } + } + + companion object { + private const val MENTION_SPAN_TO_HTML_TEMPLATE_BEGIN = "%2\$s" + private const val MENTION_SPAN_TO_MD_TEMPLATE_BEGIN = "[%2\$s](" + private const val MENTION_SPAN_TO_MD_TEMPLATE_END = "%1\$s)" } } From df794ee41f9af3d48e87071fce7895691293e9e8 Mon Sep 17 00:00:00 2001 From: Arnaud Ringenbach Date: Tue, 15 Mar 2022 11:26:47 +0100 Subject: [PATCH 06/45] Move template creation to PermalinkService --- .../session/permalinks/PermalinkService.kt | 21 +++++++++ .../permalinks/DefaultPermalinkService.kt | 8 ++++ .../session/permalinks/PermalinkFactory.kt | 28 ++++++++++- .../session/room/send/pills/TextPillsUtils.kt | 46 ++----------------- 4 files changed, 60 insertions(+), 43 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt index 920dc85c7a..36aec29b8d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkService.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.api.session.permalinks import org.matrix.android.sdk.api.session.events.model.Event +import org.matrix.android.sdk.internal.session.permalinks.PermalinkFactory /** * Useful methods to create permalink (like matrix.to links or client permalinks). @@ -80,4 +81,24 @@ interface PermalinkService { * @return the id from the url, ex: "@benoit:matrix.org", or null if the url is not a permalink */ fun getLinkedId(url: String): String? + + /** + * Creates a HTML mention span template. Can be used to replace a mention with a permalink to mentioned user. + * Ex: "%2\$s" + * + * @param forceMatrixTo whether we should force using matrix.to base URL + * + * @return the HTML template + */ + fun createHtmlMentionSpanTemplate(forceMatrixTo: Boolean = false): String + + /** + * Creates a Markdown mention span template. Can be used to replace a mention with a permalink to mentioned user. + * Ex: "[%2\$s](https://matrix.to/#/%1\$s)" + * + * @param forceMatrixTo whether we should force using matrix.to base URL + * + * @return the HTML template + */ + fun createMdMentionSpanTemplate(forceMatrixTo: Boolean = false): String } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/DefaultPermalinkService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/DefaultPermalinkService.kt index 144ebb5404..fb46a26751 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/DefaultPermalinkService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/DefaultPermalinkService.kt @@ -43,4 +43,12 @@ internal class DefaultPermalinkService @Inject constructor( override fun getLinkedId(url: String): String? { return permalinkFactory.getLinkedId(url) } + + override fun createHtmlMentionSpanTemplate(forceMatrixTo: Boolean): String { + return permalinkFactory.createHtmlMentionSpanTemplate(forceMatrixTo) + } + + override fun createMdMentionSpanTemplate(forceMatrixTo: Boolean): String { + return permalinkFactory.createMdMentionSpanTemplate(forceMatrixTo) + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt index 377b083bd6..affd6c137c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/PermalinkFactory.kt @@ -105,6 +105,28 @@ internal class PermalinkFactory @Inject constructor( ?.substringBeforeLast("?") } + fun createHtmlMentionSpanTemplate(forceMatrixTo: Boolean): String { + return buildString { + append(MENTION_SPAN_TO_HTML_TEMPLATE_BEGIN) + append(baseUrl(forceMatrixTo)) + if (useClientFormat(forceMatrixTo)) { + append(USER_PATH) + } + append(MENTION_SPAN_TO_HTML_TEMPLATE_END) + } + } + + fun createMdMentionSpanTemplate(forceMatrixTo: Boolean): String { + return buildString { + append(MENTION_SPAN_TO_MD_TEMPLATE_BEGIN) + append(baseUrl(forceMatrixTo)) + if (useClientFormat(forceMatrixTo)) { + append(USER_PATH) + } + append(MENTION_SPAN_TO_MD_TEMPLATE_END) + } + } + /** * Escape '/' in id, because it is used as a separator * @@ -145,7 +167,11 @@ internal class PermalinkFactory @Inject constructor( companion object { private const val ROOM_PATH = "room/" - const val USER_PATH = "user/" + private const val USER_PATH = "user/" private const val GROUP_PATH = "group/" + private const val MENTION_SPAN_TO_HTML_TEMPLATE_BEGIN = "%2\$s" + private const val MENTION_SPAN_TO_MD_TEMPLATE_BEGIN = "[%2\$s](" + private const val MENTION_SPAN_TO_MD_TEMPLATE_END = "%1\$s)" } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt index 3edae5e26a..427f4d966e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/pills/TextPillsUtils.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.session.room.send.pills import android.text.SpannableString import org.matrix.android.sdk.api.MatrixConfiguration +import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.permalinks.PermalinkService.Companion.MATRIX_TO_URL_BASE import org.matrix.android.sdk.api.session.room.send.MatrixItemSpan import org.matrix.android.sdk.api.util.MatrixItem @@ -32,7 +33,7 @@ import javax.inject.Inject internal class TextPillsUtils @Inject constructor( private val mentionLinkSpecComparator: MentionLinkSpecComparator, private val displayNameResolver: DisplayNameResolver, - private val matrixConfiguration: MatrixConfiguration + private val permalinkService: PermalinkService ) { /** @@ -40,7 +41,7 @@ internal class TextPillsUtils @Inject constructor( * @return the transformed String or null if no Span found */ fun processSpecialSpansToHtml(text: CharSequence): String? { - return transformPills(text, createHtmlMentionSpanTemplate(forceMatrixTo = false)) + return transformPills(text, permalinkService.createHtmlMentionSpanTemplate()) } /** @@ -48,7 +49,7 @@ internal class TextPillsUtils @Inject constructor( * @return the transformed String or null if no Span found */ fun processSpecialSpansToMarkdown(text: CharSequence): String? { - return transformPills(text, createMdMentionSpanTemplate(forceMatrixTo = false)) + return transformPills(text, permalinkService.createMdMentionSpanTemplate()) } private fun transformPills(text: CharSequence, template: String): String? { @@ -112,43 +113,4 @@ internal class TextPillsUtils @Inject constructor( i++ } } - - private fun baseUrl(forceMatrixTo: Boolean): String { - return matrixConfiguration.clientPermalinkBaseUrl - ?.takeUnless { forceMatrixTo } - ?: MATRIX_TO_URL_BASE - } - - private fun useClientFormat(forceMatrixTo: Boolean): Boolean { - return !forceMatrixTo && matrixConfiguration.clientPermalinkBaseUrl != null - } - - private fun createHtmlMentionSpanTemplate(forceMatrixTo: Boolean): String { - return buildString { - append(MENTION_SPAN_TO_HTML_TEMPLATE_BEGIN) - append(baseUrl(forceMatrixTo)) - if (useClientFormat(forceMatrixTo)) { - append(PermalinkFactory.USER_PATH) - } - append(MENTION_SPAN_TO_HTML_TEMPLATE_END) - } - } - - private fun createMdMentionSpanTemplate(forceMatrixTo: Boolean): String { - return buildString { - append(MENTION_SPAN_TO_MD_TEMPLATE_BEGIN) - append(baseUrl(forceMatrixTo)) - if (useClientFormat(forceMatrixTo)) { - append(PermalinkFactory.USER_PATH) - } - append(MENTION_SPAN_TO_MD_TEMPLATE_END) - } - } - - companion object { - private const val MENTION_SPAN_TO_HTML_TEMPLATE_BEGIN = "%2\$s" - private const val MENTION_SPAN_TO_MD_TEMPLATE_BEGIN = "[%2\$s](" - private const val MENTION_SPAN_TO_MD_TEMPLATE_END = "%1\$s)" - } } From 9f6d3ec380d00284562435a7b6103d12b83b6a36 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 28 Feb 2022 16:52:43 +0000 Subject: [PATCH 07/45] playing confetti effect when unable to personalise account on account creation - extracts the logic to an extension for reuse from the timeline --- .../im/vector/app/core/animations/Konfetti.kt | 35 +++++++++++++++++++ .../home/room/detail/TimelineFragment.kt | 14 ++------ .../FtueAuthAccountCreatedFragment.kt | 9 +++++ .../layout/fragment_ftue_account_created.xml | 6 ++++ 4 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/animations/Konfetti.kt diff --git a/vector/src/main/java/im/vector/app/core/animations/Konfetti.kt b/vector/src/main/java/im/vector/app/core/animations/Konfetti.kt new file mode 100644 index 0000000000..18f135d527 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/animations/Konfetti.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 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.app.core.animations + +import android.graphics.Color +import nl.dionsegijn.konfetti.KonfettiView +import nl.dionsegijn.konfetti.models.Shape +import nl.dionsegijn.konfetti.models.Size + +fun KonfettiView.play() { + build() + .addColors(Color.YELLOW, Color.GREEN, Color.MAGENTA) + .setDirection(0.0, 359.0) + .setSpeed(2f, 5f) + .setFadeOutEnabled(true) + .setTimeToLive(2000L) + .addShapes(Shape.Square, Shape.Circle) + .addSizes(Size(12)) + .setPosition(-50f, width + 50f, -50f, -50f) + .streamFor(150, 3000L) +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt index c638666cd7..969805e3ca 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt @@ -68,6 +68,7 @@ import com.airbnb.mvrx.withState import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.vanniktech.emoji.EmojiPopup import im.vector.app.R +import im.vector.app.core.animations.play import im.vector.app.core.dialogs.ConfirmationDialogBuilder import im.vector.app.core.dialogs.GalleryOrCameraDialogHelper import im.vector.app.core.epoxy.LayoutManagerStateRestorer @@ -203,8 +204,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import nl.dionsegijn.konfetti.models.Shape -import nl.dionsegijn.konfetti.models.Size import org.billcarsonfr.jsonviewer.JSonViewerDialog import org.commonmark.parser.Parser import org.matrix.android.sdk.api.session.Session @@ -562,16 +561,7 @@ class TimelineFragment @Inject constructor( when (chatEffect) { ChatEffect.CONFETTI -> { views.viewKonfetti.isVisible = true - views.viewKonfetti.build() - .addColors(Color.YELLOW, Color.GREEN, Color.MAGENTA) - .setDirection(0.0, 359.0) - .setSpeed(2f, 5f) - .setFadeOutEnabled(true) - .setTimeToLive(2000L) - .addShapes(Shape.Square, Shape.Circle) - .addSizes(Size(12)) - .setPosition(-50f, views.viewKonfetti.width + 50f, -50f, -50f) - .streamFor(150, 3000L) + views.viewKonfetti.play() } ChatEffect.SNOWFALL -> { views.viewSnowFall.isVisible = true diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthAccountCreatedFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthAccountCreatedFragment.kt index ccfb863a5b..49db52da67 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthAccountCreatedFragment.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthAccountCreatedFragment.kt @@ -22,6 +22,7 @@ import android.view.View import android.view.ViewGroup import androidx.core.view.isVisible import im.vector.app.R +import im.vector.app.core.animations.play import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.databinding.FragmentFtueAccountCreatedBinding import im.vector.app.features.onboarding.OnboardingAction @@ -33,6 +34,8 @@ class FtueAuthAccountCreatedFragment @Inject constructor( private val activeSessionHolder: ActiveSessionHolder ) : AbstractFtueAuthFragment() { + private var hasPlayedConfetti = false + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueAccountCreatedBinding { return FragmentFtueAccountCreatedBinding.inflate(inflater, container, false) } @@ -53,6 +56,12 @@ class FtueAuthAccountCreatedFragment @Inject constructor( val canPersonalize = state.personalizationState.supportsPersonalization() views.personalizeButtonGroup.isVisible = canPersonalize views.takeMeHomeButtonGroup.isVisible = !canPersonalize + + if (!hasPlayedConfetti && !canPersonalize) { + hasPlayedConfetti = true + views.viewKonfetti.isVisible = true + views.viewKonfetti.play() + } } override fun resetViewModel() { diff --git a/vector/src/main/res/layout/fragment_ftue_account_created.xml b/vector/src/main/res/layout/fragment_ftue_account_created.xml index 65bcdf2b63..89e94804af 100644 --- a/vector/src/main/res/layout/fragment_ftue_account_created.xml +++ b/vector/src/main/res/layout/fragment_ftue_account_created.xml @@ -6,6 +6,12 @@ android:layout_height="match_parent" android:background="?colorSecondary"> + + Date: Mon, 28 Feb 2022 17:37:49 +0000 Subject: [PATCH 08/45] adding personalization complete screen --- .../im/vector/app/core/di/FragmentModule.kt | 6 + ...FtueAuthPersonalizationCompleteFragment.kt | 61 ++++++++++ .../onboarding/ftueauth/FtueAuthVariant.kt | 14 ++- .../src/main/res/drawable/ic_celebration.xml | 22 ++++ ...fragment_ftue_personalization_complete.xml | 113 ++++++++++++++++++ vector/src/main/res/values/donottranslate.xml | 4 +- 6 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPersonalizationCompleteFragment.kt create mode 100644 vector/src/main/res/drawable/ic_celebration.xml create mode 100644 vector/src/main/res/layout/fragment_ftue_personalization_complete.xml diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt index 2ffdd7ddf3..4dcfbe16f8 100644 --- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt @@ -103,6 +103,7 @@ import im.vector.app.features.onboarding.ftueauth.FtueAuthChooseDisplayNameFragm import im.vector.app.features.onboarding.ftueauth.FtueAuthChooseProfilePictureFragment import im.vector.app.features.onboarding.ftueauth.FtueAuthGenericTextInputFormFragment import im.vector.app.features.onboarding.ftueauth.FtueAuthLoginFragment +import im.vector.app.features.onboarding.ftueauth.FtueAuthPersonalizationCompleteFragment import im.vector.app.features.onboarding.ftueauth.FtueAuthResetPasswordFragment import im.vector.app.features.onboarding.ftueauth.FtueAuthResetPasswordMailConfirmationFragment import im.vector.app.features.onboarding.ftueauth.FtueAuthResetPasswordSuccessFragment @@ -491,6 +492,11 @@ interface FragmentModule { @FragmentKey(FtueAuthChooseProfilePictureFragment::class) fun bindFtueAuthChooseProfilePictureFragment(fragment: FtueAuthChooseProfilePictureFragment): Fragment + @Binds + @IntoMap + @FragmentKey(FtueAuthPersonalizationCompleteFragment::class) + fun bindFtueAuthPersonalizationCompleteFragment(fragment: FtueAuthPersonalizationCompleteFragment): Fragment + @Binds @IntoMap @FragmentKey(UserListFragment::class) diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPersonalizationCompleteFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPersonalizationCompleteFragment.kt new file mode 100644 index 0000000000..6b47b9830c --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthPersonalizationCompleteFragment.kt @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 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.app.features.onboarding.ftueauth + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.view.isVisible +import im.vector.app.core.animations.play +import im.vector.app.databinding.FragmentFtuePersonalizationCompleteBinding +import im.vector.app.features.onboarding.OnboardingAction +import im.vector.app.features.onboarding.OnboardingViewEvents +import javax.inject.Inject + +class FtueAuthPersonalizationCompleteFragment @Inject constructor() : AbstractFtueAuthFragment() { + + private var hasPlayedConfetti = false + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtuePersonalizationCompleteBinding { + return FragmentFtuePersonalizationCompleteBinding.inflate(inflater, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupViews() + } + + private fun setupViews() { + views.personalizationCompleteCta.debouncedClicks { viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.OnTakeMeHome)) } + + if (!hasPlayedConfetti) { + hasPlayedConfetti = true + views.viewKonfetti.isVisible = true + views.viewKonfetti.play() + } + } + + override fun resetViewModel() { + // Nothing to do + } + + override fun onBackPressed(toolbarButton: Boolean): Boolean { + viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.OnTakeMeHome)) + return true + } +} diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt index 2008726ac3..79a974038b 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt @@ -227,7 +227,7 @@ class FtueAuthVariant( OnboardingViewEvents.OnChooseDisplayName -> onChooseDisplayName() OnboardingViewEvents.OnTakeMeHome -> navigateToHome(createdAccount = true) OnboardingViewEvents.OnChooseProfilePicture -> onChooseProfilePicture() - OnboardingViewEvents.OnPersonalizationComplete -> navigateToHome(createdAccount = true) + OnboardingViewEvents.OnPersonalizationComplete -> onPersonalizationComplete() OnboardingViewEvents.OnBack -> activity.popBackstack() }.exhaustive } @@ -393,7 +393,8 @@ class FtueAuthVariant( activity.supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) activity.replaceFragment( views.loginFragmentContainer, - FtueAuthAccountCreatedFragment::class.java + FtueAuthAccountCreatedFragment::class.java, + useCustomAnimation = true ) } @@ -416,4 +417,13 @@ class FtueAuthVariant( option = commonOption ) } + + private fun onPersonalizationComplete() { + activity.supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) + activity.replaceFragment( + views.loginFragmentContainer, + FtueAuthPersonalizationCompleteFragment::class.java, + useCustomAnimation = true + ) + } } diff --git a/vector/src/main/res/drawable/ic_celebration.xml b/vector/src/main/res/drawable/ic_celebration.xml new file mode 100644 index 0000000000..3868a60a60 --- /dev/null +++ b/vector/src/main/res/drawable/ic_celebration.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/vector/src/main/res/layout/fragment_ftue_personalization_complete.xml b/vector/src/main/res/layout/fragment_ftue_personalization_complete.xml new file mode 100644 index 0000000000..64908a4133 --- /dev/null +++ b/vector/src/main/res/layout/fragment_ftue_personalization_complete.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + +