Stop making dozens of /profile calls to get usernames

This commit is contained in:
Danila Fedorin 2019-10-09 12:42:33 -07:00
parent 4ef8471585
commit 4505b4ba27
4 changed files with 47 additions and 65 deletions

View File

@ -14,7 +14,6 @@ import Scylla.Model exposing (..)
import Scylla.Http exposing (..)
import Scylla.Views exposing (viewFull)
import Scylla.Route exposing (Route(..), RoomId)
import Scylla.UserData exposing (..)
import Scylla.Notification exposing (..)
import Scylla.Storage exposing (..)
import Scylla.Markdown exposing (..)
@ -51,7 +50,6 @@ init _ url key =
, roomText = Dict.empty
, sending = Dict.empty
, transactionId = 0
, userData = Dict.empty
, connected = True
, searchText = ""
, rooms = emptyOpenRooms
@ -86,7 +84,7 @@ update msg model = case msg of
ReceiveLoginResponse a r -> updateLoginResponse model a r
ReceiveFirstSyncResponse r -> updateSyncResponse model r False
ReceiveSyncResponse r -> updateSyncResponse model r True
ReceiveUserData s r -> updateUserData model s r
ReceiveUserData s r -> (model, Cmd.none)
ChangeRoomText r t -> updateChangeRoomText model r t
SendRoomText r -> updateSendRoomText model r
SendRoomTextResponse t r -> updateSendRoomTextResponse model t r
@ -112,12 +110,6 @@ update msg model = case msg of
requestScrollCmd : Cmd Msg
requestScrollCmd = Task.attempt ViewportAfterMessage (Browser.Dom.getViewportOf "messages-wrapper")
newUsersCmd : Model -> List Username -> Cmd Msg
newUsersCmd m us = m.token
|> Maybe.map (\t -> List.map (getUserData m.apiUrl t) us)
|> Maybe.withDefault []
|> Cmd.batch
updateSendRoomTextResponse : Model -> Int -> Result Http.Error String -> (Model, Cmd Msg)
updateSendRoomTextResponse m t r =
let
@ -179,16 +171,9 @@ updateUploadSelected m rid f fs msg =
updateHistoryResponse : Model -> RoomId -> Result Http.Error HistoryResponse -> (Model, Cmd Msg)
updateHistoryResponse m r hr =
let
userDataCmd h = newUsersCmd m
<| newUsers m
<| uniqueBy identity
<| List.map getSender
<| h.chunk
in
case hr of
Ok h -> ({ m | rooms = applyHistoryResponse r h m.rooms }, userDataCmd h)
Err _ -> ({ m | errors = "Unable to load older history from server"::m.errors }, Cmd.none)
case hr of
Ok h -> ({ m | rooms = applyHistoryResponse r h m.rooms }, Cmd.none)
Err _ -> ({ m | errors = "Unable to load older history from server"::m.errors }, Cmd.none)
updateHistory : Model -> RoomId -> (Model, Cmd Msg)
updateHistory m r =
@ -268,11 +253,6 @@ updateViewportAfterMessage m vr =
in
(m, Result.withDefault Cmd.none <| Result.map cmd vr)
updateUserData : Model -> String -> Result Http.Error UserData -> (Model, Cmd Msg)
updateUserData m s r = case r of
Ok ud -> ({ m | userData = Dict.insert s ud m.userData }, Cmd.none)
Err e -> ({ m | errors = ("Failed to retrieve user data for user " ++ s)::m.errors }, Cmd.none)
updateSendRoomText : Model -> RoomId -> (Model, Cmd Msg)
updateSendRoomText m r =
let
@ -311,9 +291,6 @@ updateSyncResponse model r notify =
nextBatch = Result.withDefault model.nextBatch
<| Result.map .nextBatch r
syncCmd = sync model.apiUrl token nextBatch
userDataCmd sr = newUsersCmd model
<| newUsers model
<| allUsers sr
notification sr =
getPushRuleset model.accountData
|> Maybe.map (\rs -> getNotificationEvents rs sr)
@ -324,7 +301,7 @@ updateSyncResponse model r notify =
notificationCmd sr = if notify
then Maybe.withDefault Cmd.none
<| Maybe.map (\(s, e) -> sendNotificationPort
{ name = getDisplayName model.userData e.sender
{ name = roomLocalDisplayName model s e.sender
, text = getText e
, room = s
}) <| notification sr
@ -362,7 +339,6 @@ updateSyncResponse model r notify =
Ok sr -> (newModel sr
, Cmd.batch
[ syncCmd
, userDataCmd sr
, notificationCmd sr
, setScrollCmd sr
, setReadReceiptCmd sr

View File

@ -1,13 +1,14 @@
module Scylla.Model exposing (..)
import Scylla.Api exposing (..)
import Scylla.Room exposing (getLocalDisplayName)
import Scylla.Sync exposing (SyncResponse, HistoryResponse)
import Scylla.ListUtils exposing (findFirst)
import Scylla.Room exposing (OpenRooms)
import Scylla.UserData exposing (UserData)
import Scylla.Sync.Rooms exposing (JoinedRoom)
import Scylla.Sync.Push exposing (Ruleset)
import Scylla.Sync.AccountData exposing (AccountData, directMessagesDecoder)
import Scylla.Login exposing (LoginResponse, Username, Password)
import Scylla.UserData exposing (UserData)
import Scylla.Route exposing (Route(..), RoomId)
import Scylla.Messages exposing (..)
import Scylla.Storage exposing (..)
@ -36,7 +37,6 @@ type alias Model =
, roomText : Dict RoomId String
, sending : Dict Int (RoomId, SendingMessage)
, transactionId : Int
, userData : Dict Username UserData
, connected : Bool
, searchText : String
, rooms : OpenRooms
@ -84,10 +84,13 @@ roomUrl s = Url.Builder.absolute [ "room", s ] []
loginUrl : String
loginUrl = Url.Builder.absolute [ "login" ] []
newUsers : Model -> List Username -> List Username
newUsers m lus = List.filter (\u -> not <| Dict.member u m.userData) lus
currentRoomId : Model -> Maybe RoomId
currentRoomId m = case m.route of
Room r -> Just r
_ -> Nothing
roomLocalDisplayName : Model -> RoomId -> Username -> String
roomLocalDisplayName m rid u =
case Dict.get rid m.rooms of
Just rd -> getLocalDisplayName rd u
_ -> u

View File

@ -2,7 +2,6 @@ module Scylla.Room exposing (..)
import Scylla.Route exposing (RoomId)
import Scylla.Sync exposing (SyncResponse)
import Scylla.Login exposing (Username)
import Scylla.UserData exposing (UserData, getDisplayName)
import Scylla.Sync exposing (HistoryResponse)
import Scylla.Sync.Events exposing (MessageEvent, StateEvent, toStateEvent, toMessageEvent)
import Scylla.Sync.AccountData exposing (AccountData, getDirectMessages, applyAccountData)
@ -133,8 +132,8 @@ getRoomTypingUsers : RoomData -> List String
getRoomTypingUsers = Maybe.withDefault []
<< getEphemeralData "m.typing" (field "user_ids" (list string))
getRoomName : AccountData -> Dict Username UserData -> RoomId -> RoomData -> String
getRoomName ad ud rid rd =
getRoomName : AccountData -> RoomId -> RoomData -> String
getRoomName ad rid rd =
let
customName = getStateData ("m.room.name", "") (field "name" (string)) rd
direct = getDirectMessages ad
@ -142,9 +141,14 @@ getRoomName ad ud rid rd =
in
case (customName, direct) of
(Just cn, _) -> cn
(_, Just d) -> getDisplayName ud d
(_, Just d) -> getLocalDisplayName rd d
_ -> rid
getLocalDisplayName : RoomData -> Username -> String
getLocalDisplayName rd u =
getStateData ("m.room.member", u) (field "displayname" string) rd
|> Maybe.withDefault u
getNotificationCount : RoomData -> (Int, Int)
getNotificationCount rd =
( Maybe.withDefault 0 rd.unreadNotifications.notificationCount

View File

@ -3,12 +3,11 @@ import Scylla.Model exposing (..)
import Scylla.Sync exposing (..)
import Scylla.Sync.Events exposing (..)
import Scylla.Sync.Rooms exposing (..)
import Scylla.Room exposing (RoomData, emptyOpenRooms, getHomeserver, getRoomName, getRoomTypingUsers)
import Scylla.Room exposing (RoomData, emptyOpenRooms, getHomeserver, getRoomName, getRoomTypingUsers, getLocalDisplayName)
import Scylla.Route exposing (..)
import Scylla.Fnv as Fnv
import Scylla.Messages exposing (..)
import Scylla.Login exposing (Username)
import Scylla.UserData exposing (UserData, getDisplayName)
import Scylla.Http exposing (fullMediaUrl)
import Scylla.Api exposing (ApiUrl)
import Scylla.ListUtils exposing (groupBy)
@ -21,7 +20,7 @@ import Json.Decode as Decode
import Html exposing (Html, Attribute, div, input, text, button, div, span, a, h2, h3, table, td, tr, img, textarea, video, source, p)
import Html.Attributes exposing (type_, placeholder, value, href, class, style, src, id, rows, controls, src, classList)
import Html.Events exposing (onInput, onClick, preventDefaultOn)
import Html.Lazy exposing (lazy6)
import Html.Lazy exposing (lazy5)
import Dict exposing (Dict)
import Tuple
@ -111,14 +110,14 @@ homeserverView m hs rs =
let
roomList = div [ class "rooms-list" ]
<| List.map (\(rid, r) -> roomListElementView m rid r)
<| List.sortBy (\(rid, r) -> getRoomName m.accountData m.userData rid r) rs
<| List.sortBy (\(rid, r) -> getRoomName m.accountData rid r) rs
in
div [ class "homeserver-wrapper" ] [ h3 [] [ text hs ], roomList ]
roomListElementView : Model -> RoomId -> RoomData -> Html Msg
roomListElementView m rid rd =
let
name = getRoomName m.accountData m.userData rid rd
name = getRoomName m.accountData rid rd
isVisible = m.searchText == "" || (String.contains (String.toLower m.searchText) <| String.toLower name)
isCurrentRoom = case currentRoomId m of
Nothing -> False
@ -161,7 +160,7 @@ loginView m = div [ class "login-wrapper" ]
joinedRoomView : Model -> RoomId -> RoomData -> Html Msg
joinedRoomView m roomId rd =
let
typing = List.map (getDisplayName m.userData) <| getRoomTypingUsers rd
typing = List.map (getLocalDisplayName rd) <| getRoomTypingUsers rd
typingText = String.join ", " typing
typingSuffix = case List.length typing of
0 -> ""
@ -182,18 +181,18 @@ joinedRoomView m roomId rd =
]
in
div [ class "room-wrapper" ]
[ h2 [] [ text <| getRoomName m.accountData m.userData roomId rd ]
, lazy6 lazyMessagesView m.userData roomId rd m.apiUrl m.loginUsername m.sending
[ h2 [] [ text <| getRoomName m.accountData roomId rd ]
, lazy5 lazyMessagesView roomId rd m.apiUrl m.loginUsername m.sending
, messageInput
, typingWrapper
]
lazyMessagesView : Dict String UserData -> RoomId -> RoomData -> ApiUrl -> Username -> Dict Int (RoomId, SendingMessage) -> Html Msg
lazyMessagesView ud rid rd au lu snd =
lazyMessagesView : RoomId -> RoomData -> ApiUrl -> Username -> Dict Int (RoomId, SendingMessage) -> Html Msg
lazyMessagesView rid rd au lu snd =
let
roomReceived = getReceivedMessages rd
roomSending = getSendingMessages rid snd
renderedMessages = List.map (userMessagesView ud au)
renderedMessages = List.map (userMessagesView rd au)
<| groupMessages lu
<| roomReceived ++ roomSending
in
@ -224,38 +223,38 @@ messagesWrapperView rid es = div [ class "messages-wrapper", id "messages-wrappe
, table [ class "messages-table" ] es
]
senderView : Dict String UserData -> Username -> Html Msg
senderView ud s =
span [ style "color" <| stringColor s, class "sender-wrapper" ] [ text <| getDisplayName ud s ]
senderView : RoomData -> Username -> Html Msg
senderView rd s =
span [ style "color" <| stringColor s, class "sender-wrapper" ] [ text <| getLocalDisplayName rd s ]
userMessagesView : Dict String UserData -> ApiUrl -> (Username, List Message) -> Html Msg
userMessagesView ud apiUrl (u, ms) =
userMessagesView : RoomData -> ApiUrl -> (Username, List Message) -> Html Msg
userMessagesView rd apiUrl (u, ms) =
let
wrap h = div [ class "message" ] [ h ]
in
tr []
[ td [] [ senderView ud u ]
, td [] <| List.map wrap <| List.filterMap (messageView ud apiUrl) ms
[ td [] [ senderView rd u ]
, td [] <| List.map wrap <| List.filterMap (messageView rd apiUrl) ms
]
messageView : Dict String UserData -> ApiUrl -> Message -> Maybe (Html Msg)
messageView ud apiUrl msg = case msg of
messageView : RoomData -> ApiUrl -> Message -> Maybe (Html Msg)
messageView rd apiUrl msg = case msg of
Sending t -> Just <| sendingMessageView t
Received re -> roomEventView ud apiUrl re
Received re -> roomEventView rd apiUrl re
sendingMessageView : SendingMessage -> Html Msg
sendingMessageView msg = case msg.body of
TextMessage t -> span [ class "sending"] [ text t ]
roomEventView : Dict String UserData -> ApiUrl -> MessageEvent -> Maybe (Html Msg)
roomEventView ud apiUrl re =
roomEventView : RoomData -> ApiUrl -> MessageEvent -> Maybe (Html Msg)
roomEventView rd apiUrl re =
let
msgtype = Decode.decodeValue (Decode.field "msgtype" Decode.string) re.content
in
case msgtype of
Ok "m.text" -> roomEventTextView re
Ok "m.notice" -> roomEventNoticeView re
Ok "m.emote" -> roomEventEmoteView ud re
Ok "m.emote" -> roomEventEmoteView rd re
Ok "m.image" -> roomEventImageView apiUrl re
Ok "m.file" -> roomEventFileView apiUrl re
Ok "m.video" -> roomEventVideoView apiUrl re
@ -277,10 +276,10 @@ roomEventContent f re =
Just c -> Just <| f c
Nothing -> Maybe.map (f << List.singleton << text) <| Result.toMaybe body
roomEventEmoteView : Dict String UserData -> MessageEvent -> Maybe (Html Msg)
roomEventEmoteView ud re =
roomEventEmoteView : RoomData -> MessageEvent -> Maybe (Html Msg)
roomEventEmoteView rd re =
let
emoteText = "* " ++ getDisplayName ud re.sender ++ " "
emoteText = "* " ++ getLocalDisplayName rd re.sender ++ " "
in
roomEventContent (\cs -> span [] (text emoteText :: cs)) re