diff --git a/src/Main.elm b/src/Main.elm index 09cf662..6b7b79a 100644 --- a/src/Main.elm +++ b/src/Main.elm @@ -2,6 +2,7 @@ import Browser exposing (application, UrlRequest(..)) import Browser.Navigation as Nav import Browser.Dom exposing (Viewport, setViewportOf) import Scylla.Sync exposing (..) +import Scylla.Sync.Events exposing (toMessageEvent, getType, getSender, getUnsigned) import Scylla.Messages exposing (..) import Scylla.Login exposing (..) import Scylla.Api exposing (..) @@ -182,7 +183,7 @@ updateHistoryResponse m r hr = userDataCmd h = newUsersCmd m <| newUsers m <| uniqueBy identity - <| List.map .sender + <| List.map getSender <| h.chunk in case hr of @@ -253,7 +254,7 @@ updateChangeRoute m r = joinedRoom = case r of Room rid -> Maybe.andThen (Dict.get rid) <| Maybe.andThen .join <| m.sync.rooms _ -> Nothing - lastMessage = Maybe.andThen (findLastEvent (((==) "m.room.message") << .type_)) <| Maybe.andThen .events <| Maybe.andThen .timeline joinedRoom + lastMessage = Maybe.andThen (findLastEvent (((==) "m.room.message") << .type_)) <| Maybe.map (List.filterMap toMessageEvent) <| Maybe.andThen .events <| Maybe.andThen .timeline joinedRoom readMarkerCmd = case (r, lastMessage) of (Room rid, Just re) -> setReadMarkers m.apiUrl (Maybe.withDefault "" m.token) rid re.eventId <| Just re.eventId _ -> Cmd.none @@ -331,6 +332,7 @@ updateSyncResponse model r notify = roomMessages sr = case room of Just rid -> List.filter (((==) "m.room.message") << .type_) <| Maybe.withDefault [] + <| Maybe.map (List.filterMap (toMessageEvent)) <| Maybe.andThen .events <| Maybe.andThen .timeline <| Maybe.andThen (Dict.get rid) @@ -345,7 +347,7 @@ updateSyncResponse model r notify = (Just rid, Just re) -> setReadMarkers model.apiUrl token rid re.eventId <| Just re.eventId _ -> Cmd.none receivedEvents sr = List.map Just <| allTimelineEventIds sr - receivedTransactions sr = List.filterMap (Maybe.andThen .transactionId << .unsigned) + receivedTransactions sr = List.filterMap (Maybe.andThen .transactionId << getUnsigned) <| allTimelineEvents sr sending sr = Dict.filter (\tid (rid, { body, id }) -> not <| List.member (String.fromInt tid) <| receivedTransactions sr) model.sending newSync sr = mergeSyncResponse model.sync sr diff --git a/src/Scylla/AccountData.elm b/src/Scylla/AccountData.elm index 52f2356..f5d2617 100644 --- a/src/Scylla/AccountData.elm +++ b/src/Scylla/AccountData.elm @@ -1,5 +1,7 @@ module Scylla.AccountData exposing (..) -import Scylla.Sync exposing (SyncResponse, AccountData, JoinedRoom, roomAccountData) +import Scylla.Sync exposing (SyncResponse, roomAccountData) +import Scylla.Sync.AccountData exposing (AccountData) +import Scylla.Sync.Rooms exposing (JoinedRoom) import Json.Decode as Decode import Json.Encode as Encode import Dict exposing (Dict) diff --git a/src/Scylla/Messages.elm b/src/Scylla/Messages.elm index 8db10ea..d2936db 100644 --- a/src/Scylla/Messages.elm +++ b/src/Scylla/Messages.elm @@ -1,5 +1,5 @@ module Scylla.Messages exposing (..) -import Scylla.Sync exposing (RoomEvent) +import Scylla.Sync.Events exposing (RoomEvent, MessageEvent, toMessageEvent) import Scylla.Login exposing (Username) import Scylla.Route exposing (RoomId) import Dict exposing (Dict) @@ -13,7 +13,7 @@ type alias SendingMessage = type Message = Sending SendingMessage - | Received RoomEvent + | Received MessageEvent messageUsername : Username -> Message -> Username messageUsername u msg = case msg of @@ -38,7 +38,8 @@ mergeMessages du xs = receivedMessagesRoom : List RoomEvent -> List Message receivedMessagesRoom es = List.map Received - <| List.filter (\e -> e.type_ == "m.room.message") es + <| List.filter (\e -> e.type_ == "m.room.message") + <| List.filterMap toMessageEvent es sendingMessagesRoom : RoomId -> Dict Int (RoomId, SendingMessage) -> List Message sendingMessagesRoom rid ms = List.map (\(tid, (_, sm)) -> Sending sm) diff --git a/src/Scylla/Model.elm b/src/Scylla/Model.elm index 55efe5a..92a271e 100644 --- a/src/Scylla/Model.elm +++ b/src/Scylla/Model.elm @@ -1,6 +1,8 @@ module Scylla.Model exposing (..) import Scylla.Api exposing (..) -import Scylla.Sync exposing (SyncResponse, HistoryResponse, JoinedRoom, senderName, roomName, roomJoinedUsers, findFirst, AccountData) +import Scylla.Sync exposing (SyncResponse, HistoryResponse, senderName, roomName, roomJoinedUsers, findFirst) +import Scylla.Sync.Rooms exposing (JoinedRoom) +import Scylla.Sync.AccountData exposing (AccountData) import Scylla.AccountData exposing (directMessagesDecoder) import Scylla.Login exposing (LoginResponse, Username, Password) import Scylla.UserData exposing (UserData) diff --git a/src/Scylla/Notification.elm b/src/Scylla/Notification.elm index f659b15..c3b826b 100644 --- a/src/Scylla/Notification.elm +++ b/src/Scylla/Notification.elm @@ -1,5 +1,6 @@ port module Scylla.Notification exposing (..) -import Scylla.Sync exposing (SyncResponse, RoomEvent, joinedRoomsTimelineEvents) +import Scylla.Sync exposing (SyncResponse, joinedRoomsTimelineEvents) +import Scylla.Sync.Events exposing (RoomEvent, MessageEvent, toMessageEvent) import Scylla.AccountData exposing (..) import Json.Decode as Decode exposing (string, field) import Dict @@ -13,17 +14,18 @@ type alias Notification = port sendNotificationPort : Notification -> Cmd msg port onNotificationClickPort : (String -> msg) -> Sub msg -notificationText : RoomEvent -> String +notificationText : MessageEvent -> String notificationText re = case (Decode.decodeValue (field "msgtype" string) re.content) of Ok "m.text" -> Result.withDefault "" <| (Decode.decodeValue (field "body" string) re.content) _ -> "" -joinedRoomNotificationEvents : SyncResponse -> List (String, RoomEvent) +joinedRoomNotificationEvents : SyncResponse -> List (String, MessageEvent) joinedRoomNotificationEvents s = let applyPair k = List.map (\v -> (k, v)) in List.sortBy (\(k, v) -> v.originServerTs) + <| List.filterMap (\(k, e) -> Maybe.map (\me -> (k, me)) <| toMessageEvent e) <| Dict.foldl (\k v a -> a ++ applyPair k v) [] <| joinedRoomsTimelineEvents s diff --git a/src/Scylla/Sync.elm b/src/Scylla/Sync.elm index 1246208..fc7a5e3 100644 --- a/src/Scylla/Sync.elm +++ b/src/Scylla/Sync.elm @@ -2,223 +2,15 @@ module Scylla.Sync exposing (..) import Scylla.Api exposing (..) import Scylla.Login exposing (Username) import Scylla.Route exposing (RoomId) +import Scylla.Sync.DecodeTools exposing (maybeDecode) +import Scylla.Sync.Events exposing (..) +import Scylla.Sync.Rooms exposing (..) +import Scylla.Sync.AccountData exposing (..) import Dict exposing (Dict) import Json.Decode as Decode exposing (Decoder, int, string, float, list, value, dict, bool, field) import Json.Decode.Pipeline exposing (required, optional) import Set exposing (Set) --- Special Decoding -decodeJust : Decoder a -> Decoder (Maybe a) -decodeJust = Decode.map Just - -maybeDecode : String -> Decoder a -> Decoder (Maybe a -> b) -> Decoder b -maybeDecode s d = optional s (decodeJust d) Nothing - --- General Events -type alias Event = - { content : Decode.Value - , type_ : String - } - -eventDecoder : Decoder Event -eventDecoder = - Decode.succeed Event - |> required "content" value - |> required "type" string - -type alias EventContent = Decode.Value - -eventContentDecoder : Decoder EventContent -eventContentDecoder = Decode.value - --- Unsigned Data -type alias UnsignedData = - { age : Maybe Int - , redactedBecause : Maybe Event - , transactionId : Maybe String - } - -unsignedDataDecoder : Decoder UnsignedData -unsignedDataDecoder = - Decode.succeed UnsignedData - |> maybeDecode "age" int - |> maybeDecode "redacted_because" eventDecoder - |> maybeDecode "transaction_id" string - --- State -type alias State = - { events : Maybe (List StateEvent) - } - -stateDecoder : Decoder State -stateDecoder = - Decode.succeed State - |> maybeDecode "events" (list stateEventDecoder) - -type alias StateEvent = - { content : Decode.Value - , type_ : String - , eventId : String - , sender : String - , originServerTs : Int - , unsigned : Maybe UnsignedData - , prevContent : Maybe EventContent - , stateKey : String - } - -stateEventDecoder : Decoder StateEvent -stateEventDecoder = - Decode.succeed StateEvent - |> required "content" value - |> required "type" string - |> required "event_id" string - |> required "sender" string - |> required "origin_server_ts" int - |> maybeDecode "unsigned" unsignedDataDecoder - |> maybeDecode "prev_content" eventContentDecoder - |> required "state_key" string - --- Rooms -type alias Rooms = - { join : Maybe (Dict String JoinedRoom) - , invite : Maybe (Dict String InvitedRoom) - , leave : Maybe (Dict String LeftRoom) - } - -roomsDecoder : Decoder Rooms -roomsDecoder = - Decode.succeed Rooms - |> maybeDecode "join" (dict joinedRoomDecoder) - |> maybeDecode "invite" (dict invitedRoomDecoder) - |> maybeDecode "leave" (dict leftRoomDecoder) - -type alias JoinedRoom = - { state : Maybe State - , timeline : Maybe Timeline - , ephemeral : Maybe Ephemeral - , accountData : Maybe AccountData - , unreadNotifications : Maybe UnreadNotificationCounts - } - -joinedRoomDecoder : Decoder JoinedRoom -joinedRoomDecoder = - Decode.succeed JoinedRoom - |> maybeDecode "state" stateDecoder - |> maybeDecode "timeline" timelineDecoder - |> maybeDecode "ephemeral" ephemeralDecoder - |> maybeDecode "account_data" accountDataDecoder - |> maybeDecode "unread_notifications" unreadNotificationCountsDecoder - - --- Joined Room Data -type alias Timeline = - { events : Maybe (List RoomEvent) - , limited : Maybe Bool - , prevBatch : Maybe String - } - -timelineDecoder = - Decode.succeed Timeline - |> maybeDecode "events" (list roomEventDecoder) - |> maybeDecode "limited" bool - |> maybeDecode "prev_batch" string - -type alias RoomEvent = - { content : Decode.Value - , type_ : String - , eventId : String - , sender : String - , originServerTs : Int - , unsigned : Maybe UnsignedData - } - -roomEventDecoder : Decoder RoomEvent -roomEventDecoder = - Decode.succeed RoomEvent - |> required "content" value - |> required "type" string - |> required "event_id" string - |> required "sender" string - |> required "origin_server_ts" int - |> maybeDecode "unsigned" unsignedDataDecoder - -type alias Ephemeral = - { events : Maybe (List Event) - } - -ephemeralDecoder : Decoder Ephemeral -ephemeralDecoder = - Decode.succeed Ephemeral - |> maybeDecode "events" (list eventDecoder) - -type alias AccountData = - { events : Maybe (List Event) - } - -accountDataDecoder : Decoder AccountData -accountDataDecoder = - Decode.succeed AccountData - |> maybeDecode "events" (list eventDecoder) - -type alias UnreadNotificationCounts = - { highlightCount : Maybe Int - , notificationCount : Maybe Int - } - -unreadNotificationCountsDecoder : Decoder UnreadNotificationCounts -unreadNotificationCountsDecoder = - Decode.succeed UnreadNotificationCounts - |> maybeDecode "highlight_count" int - |> maybeDecode "notification_count" int - --- Invited Room Data -type alias InvitedRoom = - { inviteState : Maybe InviteState - } - -invitedRoomDecoder : Decoder InvitedRoom -invitedRoomDecoder = - Decode.succeed InvitedRoom - |> maybeDecode "invite_state" inviteStateDecoder - -type alias InviteState = - { events : Maybe (List StrippedState) - } - -inviteStateDecoder : Decoder InviteState -inviteStateDecoder = - Decode.succeed InviteState - |> maybeDecode "events" (list strippedStateDecoder) - -type alias StrippedState = - { content : EventContent - , stateKey : String - , type_ : String - , sender : String - } - -strippedStateDecoder : Decoder StrippedState -strippedStateDecoder = - Decode.succeed StrippedState - |> required "content" eventContentDecoder - |> required "state_key" string - |> required "type" string - |> required "sender" string - --- Left Room Data -type alias LeftRoom = - { state : Maybe State - , timeline : Maybe Timeline - , accountData : Maybe AccountData - } - -leftRoomDecoder : Decoder LeftRoom -leftRoomDecoder = - Decode.succeed LeftRoom - |> maybeDecode "state" stateDecoder - |> maybeDecode "timeline" timelineDecoder - |> maybeDecode "account_data" accountDataDecoder - -- General Sync Response type alias SyncResponse = { nextBatch : String @@ -315,9 +107,9 @@ mergeStateEvents : List StateEvent -> List StateEvent -> List StateEvent mergeStateEvents l1 l2 = uniqueBy .eventId <| l1 ++ l2 mergeRoomEvents : List RoomEvent -> List RoomEvent -> List RoomEvent -mergeRoomEvents l1 l2 = uniqueBy .eventId <| l1 ++ l2 +mergeRoomEvents l1 l2 = uniqueBy getEventId <| l1 ++ l2 -mergeStrippedStates : List StrippedState -> List StrippedState -> List StrippedState +mergeStrippedStates : List StrippedStateEvent -> List StrippedStateEvent -> List StrippedStateEvent mergeStrippedStates l1 l2 = l1 ++ l2 mergeAccountData : AccountData -> AccountData -> AccountData @@ -445,17 +237,7 @@ allRoomStateEvents jr = let stateEvents = Maybe.withDefault [] <| Maybe.andThen .events jr.state timelineEvents = Maybe.withDefault [] <| Maybe.andThen .events jr.timeline - roomToStateEvent re = - { content = re.content - , type_ = re.type_ - , eventId = re.eventId - , sender = re.sender - , originServerTs = re.originServerTs - , unsigned = re.unsigned - , prevContent = Nothing - , stateKey = "" - } - allStateEvents = uniqueBy .eventId (stateEvents ++ (List.map roomToStateEvent timelineEvents)) + allStateEvents = uniqueBy .eventId (stateEvents ++ (List.filterMap toStateEvent timelineEvents)) in allStateEvents @@ -465,7 +247,7 @@ allRoomDictTimelineEvents dict = List.concatMap (Maybe.withDefault [] << .events <| Dict.values dict allTimelineEventIds : SyncResponse -> List String -allTimelineEventIds s = List.map .eventId <| allTimelineEvents s +allTimelineEventIds s = List.map getEventId <| allTimelineEvents s allTimelineEvents : SyncResponse -> List RoomEvent allTimelineEvents s = @@ -476,7 +258,7 @@ allTimelineEvents s = joinedEvents = eventsFor .join leftEvents = eventsFor .leave in - uniqueBy .eventId <| leftEvents ++ joinedEvents + leftEvents ++ joinedEvents joinedRoomsTimelineEvents : SyncResponse -> Dict String (List RoomEvent) joinedRoomsTimelineEvents s = @@ -534,7 +316,7 @@ roomTypingUsers jr = Maybe.withDefault [] -- Business Logic: Users allUsers : SyncResponse -> List Username -allUsers s = uniqueBy (\u -> u) <| List.map .sender <| allTimelineEvents s +allUsers s = uniqueBy (\u -> u) <| List.map getSender <| allTimelineEvents s roomJoinedUsers : JoinedRoom -> List Username roomJoinedUsers r = diff --git a/src/Scylla/Sync/AccountData.elm b/src/Scylla/Sync/AccountData.elm new file mode 100644 index 0000000..748b09d --- /dev/null +++ b/src/Scylla/Sync/AccountData.elm @@ -0,0 +1,14 @@ +module Scylla.Sync.AccountData exposing (..) +import Scylla.Sync.DecodeTools exposing (maybeDecode) +import Scylla.Sync.Events exposing (Event, eventDecoder) +import Json.Decode as Decode exposing (Decoder, list) + +type alias AccountData = + { events : Maybe (List Event) + } + +accountDataDecoder : Decoder AccountData +accountDataDecoder = + Decode.succeed AccountData + |> maybeDecode "events" (list eventDecoder) + diff --git a/src/Scylla/Sync/DecodeTools.elm b/src/Scylla/Sync/DecodeTools.elm new file mode 100644 index 0000000..9cdc284 --- /dev/null +++ b/src/Scylla/Sync/DecodeTools.elm @@ -0,0 +1,9 @@ +module Scylla.Sync.DecodeTools exposing (..) +import Json.Decode as Decode exposing (Decoder) +import Json.Decode.Pipeline exposing (optional) + +decodeJust : Decoder a -> Decoder (Maybe a) +decodeJust = Decode.map Just + +maybeDecode : String -> Decoder a -> Decoder (Maybe a -> b) -> Decoder b +maybeDecode s d = optional s (decodeJust d) Nothing diff --git a/src/Scylla/Sync/Events.elm b/src/Scylla/Sync/Events.elm new file mode 100644 index 0000000..a17dff8 --- /dev/null +++ b/src/Scylla/Sync/Events.elm @@ -0,0 +1,143 @@ +module Scylla.Sync.Events exposing (..) +import Scylla.Sync.DecodeTools exposing (maybeDecode) +import Json.Decode as Decode exposing (Decoder, int, string, value, oneOf) +import Json.Decode.Pipeline exposing (required) + +type alias UnsignedData = + { age : Maybe Int + , redactedBecause : Maybe Event + , transactionId : Maybe String + } + +unsignedDataDecoder : Decoder UnsignedData +unsignedDataDecoder = + Decode.succeed UnsignedData + |> maybeDecode "age" int + |> maybeDecode "redacted_because" eventDecoder + |> maybeDecode "transaction_id" string + +type alias EventContent = Decode.Value + +eventContentDecoder : Decoder EventContent +eventContentDecoder = Decode.value + +type alias Event = + { content : Decode.Value + , type_ : String + } + +eventDecoder : Decoder Event +eventDecoder = + Decode.succeed Event + |> required "content" value + |> required "type" string + +type RoomEvent + = StateRoomEvent StateEvent + | MessageRoomEvent MessageEvent + +roomEventDecoder : Decoder RoomEvent +roomEventDecoder = oneOf + [ Decode.map MessageRoomEvent messageEventDecoder + , Decode.map StateRoomEvent stateEventDecoder + ] + +type alias MessageEvent = + { content : EventContent + , type_ : String + , eventId : String + , sender : String + , originServerTs : Int + , unsigned : Maybe UnsignedData + } + +messageEventDecoder : Decoder MessageEvent +messageEventDecoder = + Decode.succeed MessageEvent + |> required "content" value + |> required "type" string + |> required "event_id" string + |> required "sender" string + |> required "origin_server_ts" int + |> maybeDecode "unsigned" unsignedDataDecoder + +type alias StateEvent = + { content : EventContent + , type_ : String + , eventId : String + , sender : String + , originServerTs : Int + , unsigned : Maybe UnsignedData + , prevContent : Maybe EventContent + , stateKey : String + } + +stateEventDecoder : Decoder StateEvent +stateEventDecoder = + Decode.succeed StateEvent + |> required "content" value + |> required "type" string + |> required "event_id" string + |> required "sender" string + |> required "origin_server_ts" int + |> maybeDecode "unsigned" unsignedDataDecoder + |> maybeDecode "prev_content" eventContentDecoder + |> required "state_key" string + +type alias StrippedStateEvent = + { content : EventContent + , stateKey : String + , type_ : String + , sender : String + } + +strippedStateEventDecoder : Decoder StrippedStateEvent +strippedStateEventDecoder = + Decode.succeed StrippedStateEvent + |> required "content" eventContentDecoder + |> required "state_key" string + |> required "type" string + |> required "sender" string + +-- Operations on Room Events +getUnsigned : RoomEvent -> Maybe UnsignedData +getUnsigned re = + case re of + StateRoomEvent e -> e.unsigned + MessageRoomEvent e -> e.unsigned + +getEventId : RoomEvent -> String +getEventId re = + case re of + StateRoomEvent e -> e.eventId + MessageRoomEvent e -> e.eventId + +getSender : RoomEvent -> String +getSender re = + case re of + StateRoomEvent e -> e.sender + MessageRoomEvent e -> e.sender + +getType : RoomEvent -> String +getType re = + case re of + StateRoomEvent e -> e.type_ + MessageRoomEvent e -> e.type_ + +toStateEvent : RoomEvent -> Maybe StateEvent +toStateEvent re = + case re of + StateRoomEvent e -> Just e + _ -> Nothing + +toMessageEvent : RoomEvent -> Maybe MessageEvent +toMessageEvent re = + case re of + MessageRoomEvent e -> Just e + _ -> Nothing + +toEvent : RoomEvent -> Event +toEvent re = + case re of + StateRoomEvent e -> { content = e.content, type_ = e.type_ } + MessageRoomEvent e -> { content = e.content, type_ = e.type_ } diff --git a/src/Scylla/Sync/Rooms.elm b/src/Scylla/Sync/Rooms.elm new file mode 100644 index 0000000..d5c49e9 --- /dev/null +++ b/src/Scylla/Sync/Rooms.elm @@ -0,0 +1,109 @@ +module Scylla.Sync.Rooms exposing (..) +import Scylla.Sync.DecodeTools exposing (maybeDecode) +import Scylla.Sync.Events exposing (Event, RoomEvent, StateEvent, StrippedStateEvent, stateEventDecoder, strippedStateEventDecoder, roomEventDecoder, eventDecoder) +import Scylla.Sync.AccountData exposing (AccountData, accountDataDecoder) +import Json.Decode as Decode exposing (Decoder, int, string, dict, list, bool) +import Json.Decode.Pipeline exposing (required) +import Dict exposing (Dict) + +type alias Rooms = + { join : Maybe (Dict String JoinedRoom) + , invite : Maybe (Dict String InvitedRoom) + , leave : Maybe (Dict String LeftRoom) + } + +roomsDecoder : Decoder Rooms +roomsDecoder = + Decode.succeed Rooms + |> maybeDecode "join" (dict joinedRoomDecoder) + |> maybeDecode "invite" (dict invitedRoomDecoder) + |> maybeDecode "leave" (dict leftRoomDecoder) + +type alias JoinedRoom = + { state : Maybe State + , timeline : Maybe Timeline + , ephemeral : Maybe Ephemeral + , accountData : Maybe AccountData + , unreadNotifications : Maybe UnreadNotificationCounts + } + +joinedRoomDecoder : Decoder JoinedRoom +joinedRoomDecoder = + Decode.succeed JoinedRoom + |> maybeDecode "state" stateDecoder + |> maybeDecode "timeline" timelineDecoder + |> maybeDecode "ephemeral" ephemeralDecoder + |> maybeDecode "account_data" accountDataDecoder + |> maybeDecode "unread_notifications" unreadNotificationCountsDecoder + +type alias InvitedRoom = + { inviteState : Maybe InviteState + } + +invitedRoomDecoder : Decoder InvitedRoom +invitedRoomDecoder = + Decode.succeed InvitedRoom + |> maybeDecode "invite_state" inviteStateDecoder + +type alias LeftRoom = + { state : Maybe State + , timeline : Maybe Timeline + , accountData : Maybe AccountData + } + +leftRoomDecoder : Decoder LeftRoom +leftRoomDecoder = + Decode.succeed LeftRoom + |> maybeDecode "state" stateDecoder + |> maybeDecode "timeline" timelineDecoder + |> maybeDecode "account_data" accountDataDecoder + +type alias State = + { events : Maybe (List StateEvent) + } + +stateDecoder : Decoder State +stateDecoder = + Decode.succeed State + |> maybeDecode "events" (list stateEventDecoder) + +type alias InviteState = + { events : Maybe (List StrippedStateEvent) + } + +inviteStateDecoder : Decoder InviteState +inviteStateDecoder = + Decode.succeed InviteState + |> maybeDecode "events" (list strippedStateEventDecoder) + +type alias Timeline = + { events : Maybe (List RoomEvent) + , limited : Maybe Bool + , prevBatch : Maybe String + } + +timelineDecoder = + Decode.succeed Timeline + |> maybeDecode "events" (list roomEventDecoder) + |> maybeDecode "limited" bool + |> maybeDecode "prev_batch" string + +type alias Ephemeral = + { events : Maybe (List Event) + } + +ephemeralDecoder : Decoder Ephemeral +ephemeralDecoder = + Decode.succeed Ephemeral + |> maybeDecode "events" (list eventDecoder) + +type alias UnreadNotificationCounts = + { highlightCount : Maybe Int + , notificationCount : Maybe Int + } + +unreadNotificationCountsDecoder : Decoder UnreadNotificationCounts +unreadNotificationCountsDecoder = + Decode.succeed UnreadNotificationCounts + |> maybeDecode "highlight_count" int + |> maybeDecode "notification_count" int diff --git a/src/Scylla/Views.elm b/src/Scylla/Views.elm index 5045a03..9cea669 100644 --- a/src/Scylla/Views.elm +++ b/src/Scylla/Views.elm @@ -1,6 +1,8 @@ module Scylla.Views exposing (..) import Scylla.Model exposing (..) import Scylla.Sync exposing (..) +import Scylla.Sync.Events exposing (..) +import Scylla.Sync.Rooms exposing (..) import Scylla.Route exposing (..) import Scylla.Fnv as Fnv import Scylla.Messages exposing (..) @@ -250,7 +252,7 @@ sendingMessageView : SendingMessage -> Html Msg sendingMessageView msg = case msg.body of TextMessage t -> span [ class "sending"] [ text t ] -roomEventView : Dict String UserData -> ApiUrl -> RoomEvent -> Maybe (Html Msg) +roomEventView : Dict String UserData -> ApiUrl -> MessageEvent -> Maybe (Html Msg) roomEventView ud apiUrl re = let msgtype = Decode.decodeValue (Decode.field "msgtype" Decode.string) re.content @@ -264,13 +266,13 @@ roomEventView ud apiUrl re = Ok "m.video" -> roomEventVideoView apiUrl re _ -> Nothing -roomEventFormattedContent : RoomEvent -> Maybe (List (Html Msg)) +roomEventFormattedContent : MessageEvent -> Maybe (List (Html Msg)) roomEventFormattedContent re = Maybe.map Html.Parser.Util.toVirtualDom <| Maybe.andThen (Result.toMaybe << Html.Parser.run ) <| Result.toMaybe <| Decode.decodeValue (Decode.field "formatted_body" Decode.string) re.content -roomEventContent : (List (Html Msg) -> Html Msg) -> RoomEvent -> Maybe (Html Msg) +roomEventContent : (List (Html Msg) -> Html Msg) -> MessageEvent -> Maybe (Html Msg) roomEventContent f re = let body = Decode.decodeValue (Decode.field "body" Decode.string) re.content @@ -280,20 +282,20 @@ roomEventContent f re = Just c -> Just <| f c Nothing -> Maybe.map (f << List.singleton << text) <| Result.toMaybe body -roomEventEmoteView : Dict String UserData -> RoomEvent -> Maybe (Html Msg) +roomEventEmoteView : Dict String UserData -> MessageEvent -> Maybe (Html Msg) roomEventEmoteView ud re = let emoteText = "* " ++ displayName ud re.sender ++ " " in roomEventContent (\cs -> span [] (text emoteText :: cs)) re -roomEventNoticeView : RoomEvent -> Maybe (Html Msg) +roomEventNoticeView : MessageEvent -> Maybe (Html Msg) roomEventNoticeView = roomEventContent (span [ class "message-notice" ]) -roomEventTextView : RoomEvent -> Maybe (Html Msg) +roomEventTextView : MessageEvent -> Maybe (Html Msg) roomEventTextView = roomEventContent (span []) -roomEventImageView : ApiUrl -> RoomEvent -> Maybe (Html Msg) +roomEventImageView : ApiUrl -> MessageEvent -> Maybe (Html Msg) roomEventImageView apiUrl re = let body = Decode.decodeValue (Decode.field "url" Decode.string) re.content @@ -302,7 +304,7 @@ roomEventImageView apiUrl re = <| Maybe.map (contentRepositoryDownloadUrl apiUrl) <| Result.toMaybe body -roomEventFileView : ApiUrl -> RoomEvent -> Maybe (Html Msg) +roomEventFileView : ApiUrl -> MessageEvent -> Maybe (Html Msg) roomEventFileView apiUrl re = let decoder = Decode.map2 (\l r -> (l, r)) (Decode.field "url" Decode.string) (Decode.field "body" Decode.string) @@ -312,7 +314,7 @@ roomEventFileView apiUrl re = <| Maybe.map (\(url, name) -> (contentRepositoryDownloadUrl apiUrl url, name)) <| Result.toMaybe fileData -roomEventVideoView : ApiUrl -> RoomEvent -> Maybe (Html Msg) +roomEventVideoView : ApiUrl -> MessageEvent -> Maybe (Html Msg) roomEventVideoView apiUrl re = let decoder = Decode.map2 (\l r -> (l, r))