diff --git a/src/Scylla/Model.elm b/src/Scylla/Model.elm index 385803e..7f87b01 100644 --- a/src/Scylla/Model.elm +++ b/src/Scylla/Model.elm @@ -1,6 +1,6 @@ module Scylla.Model exposing (..) import Scylla.Api exposing (..) -import Scylla.Sync exposing (SyncResponse, HistoryResponse, JoinedRoom, senderName, roomName, roomJoinedUsers) +import Scylla.Sync exposing (SyncResponse, HistoryResponse, JoinedRoom, senderName, roomName, roomJoinedUsers, findFirst, directMessagesDecoder) import Scylla.Login exposing (LoginResponse, Username, Password) import Scylla.UserData exposing (UserData) import Scylla.Route exposing (Route(..), RoomId) @@ -13,7 +13,7 @@ import Url.Builder import Dict exposing (Dict) import Time exposing (Posix) import File exposing (File) -import Json.Decode +import Json.Decode as Decode import Browser import Http import Url exposing (Url) @@ -54,7 +54,7 @@ type Msg = | ReceiveUserData Username (Result Http.Error UserData) -- HTTP, receive user data | ReceiveCompletedReadMarker (Result Http.Error ()) -- HTTP, read marker request completed | ReceiveCompletedTypingIndicator (Result Http.Error ()) -- HTTP, typing indicator request completed - | ReceiveStoreData Json.Decode.Value -- We are send back a value on request from localStorage. + | ReceiveStoreData Decode.Value -- We are send back a value on request from localStorage. | TypingTick Posix -- Tick for updating the typing status | History RoomId -- Load history for a room | ReceiveHistoryResponse RoomId (Result Http.Error HistoryResponse) -- HTTP, receive history @@ -74,24 +74,21 @@ type Msg = displayName : Model -> Username -> String displayName m s = Maybe.withDefault (senderName s) <| Maybe.andThen .displayName <| Dict.get s m.userData -roomDisplayName : Model -> JoinedRoom -> String -roomDisplayName m jr = +roomDisplayName : Model -> RoomId -> JoinedRoom -> String +roomDisplayName m rid jr = let customName = roomName jr - roomUsers = List.filter ((/=) m.loginUsername) <| roomJoinedUsers jr - singleUserName = if List.length roomUsers == 1 then List.head roomUsers else Nothing - singleUserDisplayName = Maybe.andThen - (\u -> Maybe.andThen .displayName <| Dict.get u m.userData) singleUserName - firstOption d os = case os of - [] -> d - ((Just v)::_) -> v - (Nothing::xs) -> firstOption d xs + direct = m.sync.accountData + |> Maybe.andThen .events + |> Maybe.andThen (findFirst ((==) "m.direct" << .type_)) + |> Maybe.map (Decode.decodeValue directMessagesDecoder << .content) + |> Maybe.andThen Result.toMaybe + |> Maybe.andThen (Dict.get rid) in - firstOption "" - [ customName - , singleUserDisplayName - , singleUserName - ] + case (customName, direct) of + (Just s, _) -> s + (_, Just u) -> displayName m u + _ -> "" roomUrl : String -> String roomUrl s = Url.Builder.absolute [ "room", s ] [] diff --git a/src/Scylla/Sync.elm b/src/Scylla/Sync.elm index 4bd4e31..21e6232 100644 --- a/src/Scylla/Sync.elm +++ b/src/Scylla/Sync.elm @@ -258,6 +258,22 @@ historyResponseDecoder = |> required "end" string |> required "chunk" (list roomEventDecoder) +-- Direct Messages +type alias DirectMessages = Dict String String +type alias DirectMessagesRaw = Dict String (List String) + +directMessagesDecoder : Decoder DirectMessages +directMessagesDecoder = + Decode.dict (Decode.list Decode.string) + |> Decode.map (invertDirectMessages) + +invertDirectMessages : DirectMessagesRaw -> DirectMessages +invertDirectMessages dmr = + Dict.foldl + (\k lv acc -> List.foldl (\v -> Dict.insert v k) acc lv) + Dict.empty + dmr + -- Business Logic: Helper Functions groupBy : (a -> comparable) -> List a -> Dict comparable (List a) groupBy f xs = @@ -275,7 +291,7 @@ uniqueByTailRecursive f l s acc = if Set.member (f x) s then uniqueByTailRecursive f tail s acc else uniqueByTailRecursive f tail s (x::acc) - [] -> acc + [] -> List.reverse acc uniqueBy : (a -> comparable) -> List a -> List a uniqueBy f l = uniqueByTailRecursive f l Set.empty [] @@ -304,18 +320,18 @@ findLastEvent = findLastBy .originServerTs mergeMaybe : (a -> a -> a) -> Maybe a -> Maybe a -> Maybe a mergeMaybe f l r = case (l, r) of (Just v1, Just v2) -> Just <| f v1 v2 - (Just v, Nothing) -> Just v - (Nothing, Just v) -> Just v + (Just v, Nothing) -> l + (Nothing, Just v) -> r _ -> Nothing mergeEvents : List Event -> List Event -> List Event mergeEvents l1 l2 = l1 ++ l2 mergeStateEvents : List StateEvent -> List StateEvent -> List StateEvent -mergeStateEvents l1 l2 = uniqueBy .eventId <| l1 ++ l2 +mergeStateEvents l1 l2 = l1 ++ l2 mergeRoomEvents : List RoomEvent -> List RoomEvent -> List RoomEvent -mergeRoomEvents l1 l2 = uniqueBy .eventId <| l1 ++ l2 +mergeRoomEvents l1 l2 = l1 ++ l2 mergeStrippedStates : List StrippedState -> List StrippedState -> List StrippedState mergeStrippedStates l1 l2 = l1 ++ l2 diff --git a/src/Scylla/Views.elm b/src/Scylla/Views.elm index fea82b9..dffa59e 100644 --- a/src/Scylla/Views.elm +++ b/src/Scylla/Views.elm @@ -109,18 +109,18 @@ homeserverView m hs rs = let roomList = div [ class "rooms-list" ] <| List.map (\(rid, r) -> roomListElementView m rid r) - <| List.sortBy (\(rid, r) -> roomDisplayName m r) rs + <| List.sortBy (\(rid, r) -> roomDisplayName m rid r) rs in div [ class "homeserver-wrapper" ] [ h3 [] [ text hs ], roomList ] -roomListElementView : Model -> String -> JoinedRoom -> Html Msg -roomListElementView m s jr = +roomListElementView : Model -> RoomId -> JoinedRoom -> Html Msg +roomListElementView m rid jr = let - name = roomDisplayName m jr + name = roomDisplayName m rid jr isVisible = m.searchText == "" || (String.contains (String.toLower m.searchText) <| String.toLower name) isCurrentRoom = case currentRoomId m of Nothing -> False - Just cr -> cr == s + Just cr -> cr == rid in div [ classList [ ("room-link-wrapper", True) @@ -129,7 +129,7 @@ roomListElementView m s jr = ] ] <| roomNotificationCountView jr.unreadNotifications ++ - [ a [ href <| roomUrl s ] [ text name ] ] + [ a [ href <| roomUrl rid ] [ text name ] ] roomNotificationCountView : Maybe UnreadNotificationCounts -> List (Html Msg) roomNotificationCountView ns = @@ -182,7 +182,7 @@ joinedRoomView m roomId rd = ] in div [ class "room-wrapper" ] - [ h2 [] [ text <| roomDisplayName m rd.joinedRoom ] + [ h2 [] [ text <| roomDisplayName m roomId rd.joinedRoom ] , messagesWrapper , messageInput , typingWrapper