Skip to content

#3296 Typing Notification update #5206

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 23, 2022
Merged

#3296 Typing Notification update #5206

merged 6 commits into from
Feb 23, 2022

Conversation

ahmed-radhouane
Copy link
Contributor

Issue #3296 Typing Notification update

Signed-off-by: Ahmed Radhouane Belkilani [email protected]

Type of change

  • Feature
  • Bugfix
  • Technical
  • Other :

Content

  • While user is in a room a typing notification appear in the toolbar with the sender name and a short message "user A is typing..."
  • This will be removed with the issues Update the top bar in a room #4642
  • In this implementation we added a new typing notification view at the bottom of the time line showing some loading dots animation and sending users avatars with new text to appear related to different states (one, two or more senders) . please refer to the Gifs.

Motivation and context

  • A new string resources has been added to the strings.xml file with a //TODO tag above.
  • please refer to the Figma file describing the new UI for the typing notification.

Screenshots / GIFs

On sender Two sender
device-2022-02-11-004242_1 device-2022-02-11-003851_1
Multi-senders RTL
device-2022-02-11-003404_1 device-2022-02-11-112149_20220211112314_1

Tests

  • Get into a room from user A connected with User B
  • Type a message in room as User A
  • Access to same room as User B ans see the typing notification at the bottom of the timeline.

Tested devices

  • Physical
  • Emulator
  • OS version(s):

Checklist

@github-actions
Copy link

github-actions bot commented Feb 11, 2022

Unit Test Results

  84 files  ±0    84 suites  ±0   1m 2s ⏱️ +3s
157 tests ±0  157 ✔️ ±0  0 💤 ±0  0 ±0 
504 runs  ±0  504 ✔️ ±0  0 💤 ±0  0 ±0 

Results for commit 91ab472. ± Comparison against base commit 924a4f8.

♻️ This comment has been updated with latest results.

@github-actions
Copy link

github-actions bot commented Feb 11, 2022

Matrix SDK

Integration Tests Results:

  • [org.matrix.android.sdk.session]
    passed=
  • [org.matrix.android.sdk.account]
    passed=
  • [org.matrix.android.sdk.internal]
    passed=
  • [org.matrix.android.sdk.ordering]
    passed=
  • [org.matrix.android.sdk.PermalinkParserTest]
    passed=

@@ -0,0 +1,4 @@
<changelist name="Uncommitted_changes_before_rebase_[Default_Changelist]" date="1644570474870" recycled="true" deleted="true">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like a bonus file was included!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it run away, catch it !

const val OVERLAP_FACT0R = -3 // =~ 30% to left
}

fun render(typingUsers: List<SenderInfo>, avatarRender: AvatarRenderer) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have you noticed any performance issues with creating/dropping views as part of the typing flow?

I'm wondering if it's worth caching and reusing the imageviews instead of dynamically creating/removing them, probably not~

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think we need to handle cache at this level.
avatars count are limit to 4, and users could change rapidly in a short time.
in total the view took almost 1 second and disappear. Still I will try to renforce test on this.
Thank you

animator.duration = DEFAULT_CIRCLE_DURATION
animator.startDelay = DEFAULT_START_ANIM_CIRCLE_DURATION * index
animator.repeatCount = ValueAnimator.INFINITE
animator.addUpdateListener {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could also use ObjectAnimator to avoid needing the separate callback, I don't think there's any difference other than syntax~

val animator = ObjectAnimator.ofFloat(circle, "alpha", DEFAULT_MAX_ALPHA, DEFAULT_MIN_ALPHA)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed !
Thanks

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="40dp"
android:layout_height="40dp">
android:layout_width="24dp"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this layout used anywhere else? this change might effect another screen~

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was an error, I've revert value to those of develop branch.
Thanks

Copy link
Contributor

@ouchadam ouchadam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great work! the change looks awesome 💯

added a few minor comments/queries

Copy link
Contributor

@ouchadam ouchadam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 💯

Copy link
Member

@bmarty bmarty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some remark before we can merge this PR

@@ -35,3 +36,5 @@ data class SenderInfo(
else -> "$displayName ($userId)"
}
}

fun SenderInfo.toMatrixItem() = MatrixItem.UserItem(userId, displayName, avatarUrl)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All extensions like this are declared in the file MatrixItem.kt. Maybe move this one there for coherency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.
Thanks !

views = TypingMessageLayoutBinding.bind(this)
}

fun render(typingUsers: List<SenderInfo>, avatarRender: AvatarRenderer) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fun render(typingUsers: List<SenderInfo>, avatarRender: AvatarRenderer) {
fun render(typingUsers: List<SenderInfo>, avatarRenderer: AvatarRenderer) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.
Thanks !


fun render(typingUsers: List<SenderInfo>, avatarRender: AvatarRenderer) {
views.usersName.text = typingHelper.getNotificationTypingMessage(typingUsers)
views.avatars.render(typingUsers, avatarRender)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
views.avatars.render(typingUsers, avatarRender)
views.avatars.render(typingUsers, avatarRenderer)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.
Thanks !

@@ -1597,6 +1601,17 @@ class TimelineFragment @Inject constructor(
voiceMessageRecorderView.isVisible = false
}

private fun renderTypingMessageNotification(roomSummary: RoomSummary?, state: RoomDetailViewState) {
if (!isThreadTimeLine() && roomSummary != null) {
views.typingMessageView.isInvisible = state.typingUsers.isNullOrEmpty()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I understand than when there is no typing user, there is an empty area at the bottom of the timeline, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's about 20dp, otherwise we will see the jump of the time line recycler view.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, thanks

if (!isThreadTimeLine() && roomSummary != null) {
views.typingMessageView.isInvisible = state.typingUsers.isNullOrEmpty()
state.typingUsers?.let { senders ->
views.typingMessageView.render(senders.take(MAX_TYPING_MESSAGE_USERS_COUNT), avatarRenderer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I would rewrite to

state.typingUsers
    ?.take(MAX_TYPING_MESSAGE_USERS_COUNT)
    ?.let { typingUsers -> views.typingMessageView.render(typingUsers, avatarRenderer) }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.
Thanks !

android:layout_width="0dp"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:visibility="invisible"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe make it visible in the layout editor

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.
Thanks !

@@ -119,8 +129,7 @@
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert this change. Layout editor should show all the views if possible

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.
Thanks !

android:layout_height="0dp"
android:layout_marginStart="8dp"
android:gravity="center"
android:visibility="visible"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is not necessary

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.
Thanks !

@@ -952,6 +952,9 @@
<string name="room_one_user_is_typing">%s is typing…</string>
<string name="room_two_users_are_typing">%1$s &#038; %2$s are typing…</string>
<string name="room_many_users_are_typing">%1$s &#038; %2$s &#038; others are typing…</string>
<!--TODO #3296 add next two strings values -->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This TODO is not necessary. Adding new strings will be handled automatically by Weblate

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.
Thanks !

import org.matrix.android.sdk.api.session.room.sender.SenderInfo
import org.matrix.android.sdk.api.util.toMatrixItem

class TypingMessageAvatar @JvmOverloads constructor(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another possible implementation could be like in the View ReadReceiptsView. I do not know if it is better or not though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First Idea was to use this view, but too much differences with what is asked from UI team.
But, in other way TypingMessageAvatar could be used from showing the read receipts, with some modification.

@ahmed-radhouane
Copy link
Contributor Author

@bmarty
Any manip to avoid the :

❌ Error: 1 file has more than 2500 lines:
./vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt (2513 lines)

which set a failing state for the Code Quality Checks ?

@bmarty
Copy link
Member

bmarty commented Feb 18, 2022

@ahmed-radhouane you can increase the limit here (to 2800 maybe), we will have to split this class later.

ahmed-radhouane and others added 6 commits February 23, 2022 11:34
 - Adding a typing message notification view at the bottom of the timeline in rooms.

Signed-off-by: Ahmed Radhouane Belkilani <[email protected]>
 - prevent timeline jump up while TypingMessageView populated.

Signed-off-by: Ahmed Radhouane Belkilani <[email protected]>
 - revert vector_settings_round_avatar.xml file to develop state.

Signed-off-by: Ahmed Radhouane Belkilani <[email protected]>
 - use ObjectAnimator instead of ValueAnimator in TypingMessageDots.

Signed-off-by: Ahmed Radhouane Belkilani <[email protected]>
- Fixes after review.

Signed-off-by: Ahmed Radhouane Belkilani <[email protected]>
@@ -42,4 +42,15 @@ class TypingHelper @Inject constructor(private val stringProvider: StringProvide
typingUsers[1].disambiguatedDisplayName)
}
}

fun getNotificationTypingMessage(typingUsers: List<SenderInfo>): String {
return when {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not change it, but I think we could have when(typingUsers.size())

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah it's similar than the fun above :)

Copy link
Member

@bmarty bmarty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update!

@bmarty bmarty merged commit 93de61e into develop Feb 23, 2022
@bmarty bmarty deleted the arb/issues/3296 branch February 23, 2022 17:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants