Skip to content
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

[#21227] Simpler chat screen #21313

Merged
merged 9 commits into from
Oct 2, 2024
Merged

[#21227] Simpler chat screen #21313

merged 9 commits into from
Oct 2, 2024

Conversation

ulisesmac
Copy link
Contributor

@ulisesmac ulisesmac commented Sep 24, 2024

fixes #21227
fixes #20680

Summary

This PR implements the new simpler designs for the chat screen.

Lot of changes were made since some additional (but need) improvements were made for the sake of readability, but it preserves the past behavior (besides the redesign).

Review notes

The implementation is keeping a couple of ratoms in the chat component due to their "async renderer" nature, the same result could be achieved by React hooks, but I'd need to use js/requestAnimationFrame along with a use-effect which makes the code more complex.

The usage of ratoms is to avoid a blank screen while the chat screen is opened:
with ratoms:

with-atom.mp4

with hooks:

with-hooks.mp4

Please refer to the self-review comments if you want to explore the implementation details more deeply.

Testing notes

Please test that the chat screen is behaving in the same way as before for 1:1 chats, group chats and channels, and it only changes the design.

Platforms

  • Android
  • iOS
Functional
  • 1-1 chats
  • group chats

status: ready

Comment on lines 19 to 21
(defn view
[{:keys [layout-height]}]
[layout-height]
(let [suggestions (rf/sub [:chat/mention-suggestions])
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We passed a big map of props but we only used one of them, which is actually an atom, so it's a stable reference, no fear from uinexpected re-renders now. This is a simplification made.

Comment on lines 5 to -17
(def ^:const pinned-banner-height 40)
(def ^:const header-container-top-margin 48)
(def ^:const header-container-radius 20)
(def ^:const header-animation-distance 20)
(def ^:const content-animation-start-position-android 130)
(def ^:const content-animation-start-position-ios 124)
;; Note - We should also consider height of bio for banner animation starting position
;; Todo - Should be updated once New-profile implemation is complete
(def ^:const pinned-banner-animation-start-position 148)

(def ^:const default-extrapolation-option
{:extrapolateLeft "clamp"
:extrapolateRight "clamp"})
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now unused consts, some animations were no longer necessary.

Comment on lines 1 to +15
(ns status-im.contexts.chat.messenger.placeholder.style
(:require [quo.foundations.colors :as colors]
[react-native.reanimated :as reanimated]))
[react-native.safe-area :as safe-area]))

(defn container
[top opacity z-index theme]
(reanimated/apply-animations-to-style
{:opacity opacity
:z-index z-index}
{:position :absolute
:padding-top top
:top 0
:left 0
:right 0
:bottom 0
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)}))
[theme on-layout-done?]
{:position :absolute
:padding-top (safe-area/get-top)
:top 0
:left 0
:right 0
:bottom 0
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:opacity (if on-layout-done? 0 1)
:z-index (if on-layout-done? 0 2)})
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We had some shared values to control the logic here, but we didn't do any animations, and a ratom can do the job, (this is the piece of code I mentioned works simpler with a ratom)

Comment on lines -58 to -59
(when *screen-loaded?*
(rn/use-mount #(reset! *screen-loaded?* true)))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We conditionally used a hook

@status-im-auto
Copy link
Member

status-im-auto commented Sep 24, 2024

Jenkins Builds

Click to see older builds (12)
Commit #️⃣ Finished (UTC) Duration Platform Result
✔️ 161fc54 #1 2024-09-24 04:47:28 ~5 min tests 📄log
✔️ 161fc54 #1 2024-09-24 04:48:55 ~6 min android 🤖apk 📲
✔️ 161fc54 #1 2024-09-24 04:50:47 ~8 min android-e2e 🤖apk 📲
✔️ 161fc54 #1 2024-09-24 04:50:59 ~9 min ios 📱ipa 📲
✔️ de24093 #2 2024-09-24 22:52:51 ~4 min tests 📄log
✔️ de24093 #2 2024-09-24 22:55:00 ~6 min android 🤖apk 📲
✔️ de24093 #2 2024-09-24 22:55:36 ~7 min android-e2e 🤖apk 📲
✔️ de24093 #2 2024-09-24 22:57:52 ~9 min ios 📱ipa 📲
✔️ b95f5a9 #3 2024-09-30 11:51:57 ~5 min tests 📄log
✔️ b95f5a9 #3 2024-09-30 11:55:10 ~8 min android-e2e 🤖apk 📲
✔️ b95f5a9 #3 2024-09-30 11:55:21 ~9 min android 🤖apk 📲
✔️ b95f5a9 #3 2024-09-30 11:55:57 ~9 min ios 📱ipa 📲
Commit #️⃣ Finished (UTC) Duration Platform Result
✔️ 103f561 #4 2024-10-02 20:09:56 ~4 min tests 📄log
✔️ 103f561 #4 2024-10-02 20:12:49 ~7 min android-e2e 🤖apk 📲
✔️ 103f561 #4 2024-10-02 20:13:41 ~7 min android 🤖apk 📲
✔️ 103f561 #4 2024-10-02 20:14:54 ~9 min ios 📱ipa 📲
✔️ 2d7ce71 #5 2024-10-02 20:27:56 ~4 min tests 📄log
✔️ 2d7ce71 #5 2024-10-02 20:30:35 ~7 min android-e2e 🤖apk 📲
✔️ 2d7ce71 #5 2024-10-02 20:31:06 ~7 min android 🤖apk 📲
✔️ 2d7ce71 #5 2024-10-02 20:31:57 ~8 min ios 📱ipa 📲

Comment on lines -60 to -64
(when-not (if *screen-loaded?* @*screen-loaded?* screen-loaded?)
(reanimated/set-shared-value chat-screen-layout-calculations-complete? false)
(reanimated/set-shared-value distance-from-list-top 0)
(reanimated/set-shared-value chat-list-scroll-y 0))
(when (if *screen-loaded?* @*screen-loaded?* screen-loaded?)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

when + if seems hard to read

Comment on lines -71 to -72
*screen-loaded?* (when-not jump-to-enabled?
(reagent/atom false))]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ratom being created in a non-form-2-component. This works because we aren't re-rendering this component, but as soon as ff/enabled? changes during this screen mounted, it won't work.

Although it works now, I prefered to refactor to properly create the ratom.

Comment on lines -47 to -57
(let [screen-loaded? (rf/sub [:shell/chat-screen-loaded?])
distance-from-list-top (reanimated/use-shared-value 0)
chat-list-scroll-y (reanimated/use-shared-value 0)
props {:insets (safe-area/get-insets)
:content-height (atom 0)
:layout-height (atom 0)
:distance-atom (atom 0)
:distance-from-list-top distance-from-list-top
:chat-list-scroll-y chat-list-scroll-y
:chat-screen-layout-calculations-complete?
chat-screen-layout-calculations-complete?}]
Copy link
Contributor Author

@ulisesmac ulisesmac Sep 24, 2024

Choose a reason for hiding this comment

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

These atoms are not created in a form-2 component, I moved them to be use-ref-atom.

Comment on lines 179 to -372
(reset! layout-height layout-height-new))
(when-not (reanimated/get-shared-value chat-screen-layout-calculations-complete?)
(reanimated/set-shared-value chat-screen-layout-calculations-complete? true))))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The layout calculation is just a boolean marked once the on-layout event was fired. It's been simplified to only be a ratom switch.

Comment on lines +191 to +187
(let [content-height (rn/use-ref-atom 0)
distance-atom (rn/use-ref-atom 0)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These two values were received, but there's no need to lift up the state even more, they are only used here, so they are being created here.

Copy link
Member

@clauxx clauxx left a comment

Choose a reason for hiding this comment

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

Thank you so much for this! The chat really needed some cleanup and simplifying.

Left some comments/questions, but otherwise looks good 👍

:customization-color customization-color}]
:footer [more-messages-loader
{:chat-id chat-id
:window-height window-height}]
:data messages
Copy link
Member

Choose a reason for hiding this comment

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

unrelated to the changes made in this PR, but since the chat screen is getting reworked, we could also consider the way we do the rendering in the chat. Currently we pass a list of messages as data, which makes it slower when the flat-list re-renders (and it will quite often). For large lists we should consider just passing a list of "message ids" and get the message data through a subscription inside the list items.

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'd really like to check the rendering for the chat screen and improve the implementation to make it more optimal 🙂

As I said in another response, we could file an issue to check this and improve it. Addressing it in this PR would make the review even harder.

CC: @ilmotta

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice suggestion @clauxx, this can work well, but worth measuring first to be sure it's worth it.

As I said in another response, we could file an issue to check this and improve it. Addressing it in this PR would make the review even harder.

This is the key for us to keep develop releasable. PRs with focused scope and with clear requirements for QAs and devs to verify. Performance optimizations are much easier to test in isolation.

Comment on lines +245 to +241
:content-container-style {:padding-top distance-from-last-message
:padding-bottom top-margin}
Copy link
Member

Choose a reason for hiding this comment

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

Should be in styles based on the guidelines, but don't mind it tbh

Comment on lines +55 to +56
(let [on-layout-done? (reagent/atom false)
first-render-done? (reagent/atom false)]
Copy link
Member

Choose a reason for hiding this comment

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

Could the on-layout-done? ratom be avoided smh? Like having a value in the db for it maybe or smh else, or does that make it much slower to open?

Asking cause it's passed through a few children, mutated "somewhere" and used in another "somewhere", so I wonder about the complexity trade-offs you mentioned, if any.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for this comment and for noticing it!

I know this ratom is being passed, but we need to use the advantages of being a ratom and deref it in its children.

It can't be substituted with a hook (unless we use the js/requestAnimationFrame to update its value).

It could be moved to re-frame, but I think there's no need to move this local state to be a global one.

This ratom was originally called something like chat-screen-layout-calculations-complete, and what I did was rename it and simplify the code, but I preserved the same main logic, so it means the behavior is the same.

I can rework the logic and bring a simpler one, but I didn't want to change it because the issue solved is mostly about a redesign.

I can open a new issue with a list of code improvements we want to fix in the chat screen and then solve it. Also, the review will be easier. wdyt?

Copy link
Member

Choose a reason for hiding this comment

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

It could be moved to re-frame, but I think there's no need to move this local state to be a global one.

Since it's mutated and derefed in nested children, I'd argue it doesn't/shouldn't fall under local state anymore, but I agree that this will introduce even more changes and could be should outside this PR 👍.

Copy link
Member

@flexsurfer flexsurfer left a comment

Choose a reason for hiding this comment

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

nice work!

Copy link
Contributor

@ilmotta ilmotta left a comment

Choose a reason for hiding this comment

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

Wow, when this simplification was designed in Figma I had no idea we would be able to clean up so much. Thank you @ulisesmac

@status-im-auto
Copy link
Member

84% of end-end tests have passed

Total executed tests: 51
Failed tests: 8
Expected to fail tests: 0
Passed tests: 43
IDs of failed tests: 702845,702786,703202,702809,702838,702948,703629,702843 

Failed tests (8)

Click to expand
  • Rerun failed tests

  • Class TestCommunityMultipleDeviceMerged:

    1. test_community_message_send_check_timestamps_sender_username, id: 702838

    Device 2: Verifying that 'new message' is under today
    Device 2: Looking for a message by text: new message

    critical/chats/test_public_chat_browsing.py:367: in test_community_message_send_check_timestamps_sender_username
        self.channel_2.verify_message_is_under_today_text(new_message, self.errors, 60)
    ../views/chat_view.py:976: in verify_message_is_under_today_text
        message_element.wait_for_visibility_of_element(timeout)
    ../views/base_element.py:147: in wait_for_visibility_of_element
        raise TimeoutException(
     Device 2: ChatElementByText by xpath:`//*[starts-with(@text,'new message')]/ancestor::android.view.ViewGroup[@content-desc='chat-item']` is not found on the screen after wait_for_visibility_of_element
    



    Device sessions

    2. test_community_message_edit, id: 702843

    Device 1: Wait for text element EmojisNumber to be equal to 1
    Device 1: Find EmojisNumber by xpath: //*[starts-with(@text,'Message AFTER edit 2 (Edited)')]/ancestor::android.view.ViewGroup[@content-desc='chat-item']/../..//*[@content-desc='emoji-reaction-2']/android.widget.TextView[2]

    critical/chats/test_public_chat_browsing.py:387: in test_community_message_edit
        self.errors.verify_no_errors()
    base_test_case.py:192: in verify_no_errors
        pytest.fail('\n '.join([self.errors.pop(0) for _ in range(len(self.errors))]))
     Message reaction is not shown for the sender
    



    Device sessions

    Class TestCommunityMultipleDeviceMergedTwo:

    1. test_community_leave, id: 702845

    Test setup failed: critical/chats/test_public_chat_browsing.py:872: in prepare_devices
        self.community_2.join_community()
    ../views/chat_view.py:425: in join_community
        self.community_status_joined.wait_for_visibility_of_element(60)
    ../views/base_element.py:147: in wait_for_visibility_of_element
        raise TimeoutException(
     Device 2: Text by accessibility id:`status-tag-positive` is not found on the screen after wait_for_visibility_of_element
    



    2. test_community_mentions_push_notification, id: 702786

    Device 2: Find LogInButton by accessibility id: login-button
    Device 2: Tap on found: LogInButton

    Test setup failed: critical/chats/test_public_chat_browsing.py:872: in prepare_devices
        self.community_2.join_community()
    ../views/chat_view.py:425: in join_community
        self.community_status_joined.wait_for_visibility_of_element(60)
    ../views/base_element.py:147: in wait_for_visibility_of_element
        raise TimeoutException(
     Device 2: Text by accessibility id:`status-tag-positive` is not found on the screen after wait_for_visibility_of_element
    



    Device sessions

    3. test_community_markdown_support, id: 702809

    Test setup failed: critical/chats/test_public_chat_browsing.py:872: in prepare_devices
        self.community_2.join_community()
    ../views/chat_view.py:425: in join_community
        self.community_status_joined.wait_for_visibility_of_element(60)
    ../views/base_element.py:147: in wait_for_visibility_of_element
        raise TimeoutException(
     Device 2: Text by accessibility id:`status-tag-positive` is not found on the screen after wait_for_visibility_of_element
    



    4. test_community_hashtag_links_to_community_channels, id: 702948

    Test setup failed: critical/chats/test_public_chat_browsing.py:872: in prepare_devices
        self.community_2.join_community()
    ../views/chat_view.py:425: in join_community
        self.community_status_joined.wait_for_visibility_of_element(60)
    ../views/base_element.py:147: in wait_for_visibility_of_element
        raise TimeoutException(
     Device 2: Text by accessibility id:`status-tag-positive` is not found on the screen after wait_for_visibility_of_element
    



    5. test_community_join_when_node_owner_offline, id: 703629

    Test setup failed: critical/chats/test_public_chat_browsing.py:872: in prepare_devices
        self.community_2.join_community()
    ../views/chat_view.py:425: in join_community
        self.community_status_joined.wait_for_visibility_of_element(60)
    ../views/base_element.py:147: in wait_for_visibility_of_element
        raise TimeoutException(
     Device 2: Text by accessibility id:`status-tag-positive` is not found on the screen after wait_for_visibility_of_element
    



    Class TestGroupChatMultipleDeviceMergedNewUI:

    1. test_group_chat_reactions, id: 703202

    Device 2: Find EmojisNumber by xpath: //*[starts-with(@text,'This is a test message to check some reactions.')]/ancestor::android.view.ViewGroup[@content-desc='chat-item']/../..//*[@content-desc='emoji-reaction-2']/android.widget.TextView[2]
    Device 2: Find EmojisNumber by xpath: //*[starts-with(@text,'This is a test message to check some reactions.')]/ancestor::android.view.ViewGroup[@content-desc='chat-item']/../..//*[@content-desc='emoji-reaction-2']/android.widget.TextView[2]

    critical/chats/test_group_chat.py:123: in test_group_chat_reactions
        self.loop.run_until_complete(run_in_parallel((
    /usr/lib/python3.10/asyncio/base_events.py:649: in run_until_complete
        return future.result()
    __init__.py:52: in run_in_parallel
        returns.append(await k)
    /usr/lib/python3.10/concurrent/futures/thread.py:58: in run
        result = self.fn(*self.args, **self.kwargs)
    critical/chats/test_group_chat.py:119: in _check_reactions_count
        chat_element.emojis_below_message(emoji="thumbs-up").wait_for_element_text(2)
    ../views/base_element.py:190: in wait_for_element_text
        self.driver.fail(message if message else "`%s` is not equal to expected `%s` in %s sec" % (
    base_test_case.py:180: in fail
        pytest.fail('Device %s: %s' % (self.number, text))
     Device 2: `1` is not equal to expected `2` in 30 sec
    



    Device sessions

    Passed tests (43)

    Click to expand

    Class TestCommunityOneDeviceMerged:

    1. test_community_copy_and_paste_message_in_chat_input, id: 702742
    Device sessions

    2. test_community_navigate_to_channel_when_relaunch, id: 702846
    Device sessions

    3. test_restore_multiaccount_with_waku_backup_remove_switch, id: 703133
    Device sessions

    4. test_community_undo_delete_message, id: 702869
    Device sessions

    5. test_community_mute_community_and_channel, id: 703382
    Device sessions

    6. test_community_discovery, id: 703503
    Device sessions

    Class TestOneToOneChatMultipleSharedDevicesNewUi:

    1. test_1_1_chat_edit_message, id: 702855
    Device sessions

    2. test_1_1_chat_message_reaction, id: 702730
    Device sessions

    3. test_1_1_chat_non_latin_messages_stack_update_profile_photo, id: 702745
    Device sessions

    4. test_1_1_chat_pin_messages, id: 702731
    Device sessions

    5. test_1_1_chat_text_message_delete_push_disappear, id: 702733
    Device sessions

    6. test_1_1_chat_push_emoji, id: 702813
    Device sessions

    7. test_1_1_chat_emoji_send_reply_and_open_link, id: 702782
    Device sessions

    8. test_1_1_chat_send_image_save_and_share, id: 703391
    Device sessions

    Class TestActivityMultipleDevicePRTwo:

    1. test_activity_center_admin_notification_accept_swipe, id: 702958
    Device sessions

    2. test_activity_center_mentions, id: 702957
    Device sessions

    Class TestOneToOneChatMultipleSharedDevicesNewUiTwo:

    1. test_1_1_chat_mute_chat, id: 703496
    Device sessions

    2. test_1_1_chat_is_shown_message_sent_delivered_from_offline, id: 702783
    Device sessions

    3. test_1_1_chat_delete_via_long_press_relogin, id: 702784
    Device sessions

    Class TestActivityMultipleDevicePR:

    1. test_activity_center_reply_read_unread_delete_filter_swipe, id: 702947
    Device sessions

    Class TestDeepLinksOneDevice:

    1. test_links_open_universal_links_from_chat, id: 704613
    Device sessions

    2. test_links_deep_links_profile, id: 702775
    Device sessions

    3. test_deep_links_communities, id: 739307
    Device sessions

    Class TestWalletOneDevice:

    1. test_wallet_add_remove_regular_account, id: 727231
    Device sessions

    Class TestWalletMultipleDevice:

    1. test_wallet_send_asset_from_drawer, id: 727230
    2. test_wallet_send_eth, id: 727229

    Class TestGroupChatMultipleDeviceMergedNewUI:

    1. test_group_chat_join_send_text_messages_push, id: 702807
    Device sessions

    2. test_group_chat_offline_pn, id: 702808
    Device sessions

    3. test_group_chat_pin_messages, id: 702732
    Device sessions

    4. test_group_chat_send_image_save_and_share, id: 703297
    Device sessions

    5. test_group_chat_mute_chat, id: 703495
    Device sessions

    Class TestCommunityMultipleDeviceMerged:

    1. test_community_emoji_send_copy_paste_reply, id: 702840
    Device sessions

    2. test_community_contact_block_unblock_offline, id: 702894
    Device sessions

    3. test_community_mark_all_messages_as_read, id: 703086
    Device sessions

    4. test_community_links_with_previews_github_youtube_twitter_gif_send_enable, id: 702844
    Device sessions

    5. test_community_unread_messages_badge, id: 702841
    Device sessions

    6. test_community_message_delete, id: 702839
    Device sessions

    7. test_community_edit_delete_message_when_offline, id: 704615
    Device sessions

    8. test_community_one_image_send_reply, id: 702859
    Device sessions

    9. test_community_several_images_send_reply, id: 703194
    Device sessions

    Class TestActivityCenterContactRequestMultipleDevicePR:

    1. test_activity_center_contact_request_accept_swipe_mark_all_as_read, id: 702851
    Device sessions

    2. test_activity_center_contact_request_decline, id: 702850
    Device sessions

    3. test_add_contact_field_validation, id: 702777
    Device sessions

    @status-im-auto
    Copy link
    Member

    100% of end-end tests have passed

    Total executed tests: 8
    Failed tests: 0
    Expected to fail tests: 0
    Passed tests: 8
    

    Passed tests (8)

    Click to expand

    Class TestCommunityMultipleDeviceMerged:

    1. test_community_message_send_check_timestamps_sender_username, id: 702838
    Device sessions

    2. test_community_message_edit, id: 702843
    Device sessions

    Class TestCommunityMultipleDeviceMergedTwo:

    1. test_community_leave, id: 702845
    Device sessions

    2. test_community_mentions_push_notification, id: 702786
    Device sessions

    3. test_community_markdown_support, id: 702809
    Device sessions

    4. test_community_hashtag_links_to_community_channels, id: 702948
    Device sessions

    5. test_community_join_when_node_owner_offline, id: 703629
    Device sessions

    Class TestGroupChatMultipleDeviceMergedNewUI:

    1. test_group_chat_reactions, id: 703202
    Device sessions

    @mariia-skrypnyk
    Copy link

    Hey @ulisesmac !

    Thanks for your PR.

    Looks good on both platforms and PR is ready to be merged.

    ….messenger.messages.list.view` to be more REPL friendly
    - Change shared-value to ratom usage since no animations were performed.
    The previous implementation has two main problems:
    1. It is creating atoms and ratoms in non-form-2-components.
    2. Conditionally uses a hook (`rn/use-mount` in `lazy-chat-screen`).
    
    The new implementation fixes the previous problems, improves the readability
    and passes only the props needed to children components.
    @ulisesmac ulisesmac merged commit 63d0aac into develop Oct 2, 2024
    6 checks passed
    @ulisesmac ulisesmac deleted the 21227-Simpler-chat branch October 2, 2024 20:35
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    Archived in project
    Development

    Successfully merging this pull request may close these issues.

    Simpler and improved design for empty chats and channels Chats - Remove action buttons from all chats
    6 participants