Scylla/src/Scylla/Room.elm

188 lines
6.3 KiB
Elm
Raw Normal View History

module Scylla.Room exposing (..)
import Scylla.Route exposing (RoomId)
import Scylla.Sync exposing (SyncResponse)
2019-09-10 23:24:47 -07:00
import Scylla.Login exposing (Username)
2019-10-09 12:52:59 -07:00
import Scylla.UserData exposing (getSenderName)
2019-09-11 00:52:42 -07:00
import Scylla.Sync exposing (HistoryResponse)
import Scylla.Sync.Events exposing (MessageEvent, StateEvent, toStateEvent, toMessageEvent)
2019-09-11 00:52:42 -07:00
import Scylla.Sync.AccountData exposing (AccountData, getDirectMessages, applyAccountData)
import Scylla.Sync.Rooms exposing (JoinedRoom, UnreadNotificationCounts, Ephemeral)
2019-09-11 00:52:42 -07:00
import Scylla.ListUtils exposing (findFirst, uniqueBy)
import Json.Decode as Decode exposing (Decoder, Value, decodeValue, field, string, list)
import Dict exposing (Dict)
type alias RoomState = Dict (String, String) Value
type alias RoomData =
{ roomState : RoomState
, messages : List (MessageEvent)
, accountData : AccountData
, ephemeral : Ephemeral
, unreadNotifications : UnreadNotificationCounts
2019-09-11 00:52:42 -07:00
, prevHistoryBatch : Maybe String
, text : String
}
type alias OpenRooms = Dict RoomId RoomData
emptyOpenRooms : OpenRooms
emptyOpenRooms = Dict.empty
emptyRoomData : RoomData
emptyRoomData =
{ roomState = Dict.empty
, messages = []
, accountData = { events = Just [] }
, ephemeral = { events = Just [] }
, unreadNotifications =
{ highlightCount = Just 0
, notificationCount = Just 0
}
2019-09-11 00:52:42 -07:00
, prevHistoryBatch = Nothing
, text = ""
}
changeRoomStateEvent : StateEvent -> RoomState -> RoomState
changeRoomStateEvent se = Dict.insert (se.type_, se.stateKey) se.content
changeRoomStateEvents : List StateEvent -> RoomState -> RoomState
changeRoomStateEvents es rs = List.foldr (changeRoomStateEvent) rs es
changeRoomState : JoinedRoom -> RoomState -> RoomState
changeRoomState jr rs =
let
stateDiff = jr.state
|> Maybe.andThen .events
|> Maybe.withDefault []
timelineDiff = jr.timeline
|> Maybe.andThen .events
|> Maybe.map (List.filterMap toStateEvent)
|> Maybe.withDefault []
in
rs
|> changeRoomStateEvents stateDiff
|> changeRoomStateEvents timelineDiff
changeTimeline : JoinedRoom -> List (MessageEvent) -> List (MessageEvent)
changeTimeline jr tl =
let
newMessages = jr.timeline
|> Maybe.andThen .events
|> Maybe.map (List.filterMap toMessageEvent)
|> Maybe.withDefault []
in
2019-09-11 00:52:42 -07:00
tl ++ newMessages
changeEphemeral : JoinedRoom -> Ephemeral -> Ephemeral
changeEphemeral jr e = Maybe.withDefault e jr.ephemeral
changeNotifications : JoinedRoom -> UnreadNotificationCounts -> UnreadNotificationCounts
changeNotifications jr un = Maybe.withDefault un jr.unreadNotifications
changeRoomData : JoinedRoom -> RoomData -> RoomData
changeRoomData jr rd =
2019-09-11 00:52:42 -07:00
{ rd | accountData = applyAccountData jr.accountData rd.accountData
, roomState = changeRoomState jr rd.roomState
, messages = changeTimeline jr rd.messages
, ephemeral = changeEphemeral jr rd.ephemeral
, unreadNotifications = changeNotifications jr rd.unreadNotifications
2019-09-12 20:32:59 -07:00
, prevHistoryBatch =
case rd.prevHistoryBatch of
Nothing -> Maybe.andThen .prevBatch jr.timeline
Just _ -> rd.prevHistoryBatch
}
updateRoomData : JoinedRoom -> Maybe RoomData -> Maybe RoomData
updateRoomData jr mrd = Maybe.withDefault emptyRoomData mrd
|> changeRoomData jr
|> Just
applyJoinedRoom : RoomId -> JoinedRoom -> OpenRooms -> OpenRooms
applyJoinedRoom rid jr = Dict.update rid (updateRoomData jr)
applySync : SyncResponse -> OpenRooms -> OpenRooms
applySync sr or =
let
joinedRooms = sr.rooms
|> Maybe.andThen .join
|> Maybe.withDefault Dict.empty
in
Dict.foldl applyJoinedRoom or joinedRooms
2019-09-10 23:24:47 -07:00
2019-09-11 00:52:42 -07:00
addHistoryRoomData : HistoryResponse -> Maybe RoomData -> Maybe RoomData
addHistoryRoomData hr = Maybe.map
(\rd ->
{ rd | messages = uniqueBy .eventId
<| (List.reverse <| List.filterMap toMessageEvent hr.chunk) ++ rd.messages
, prevHistoryBatch = Just hr.end
})
applyHistoryResponse : RoomId -> HistoryResponse -> OpenRooms -> OpenRooms
applyHistoryResponse rid hr = Dict.update rid (addHistoryRoomData hr)
2019-09-10 23:24:47 -07:00
getStateData : (String, String) -> Decoder a -> RoomData -> Maybe a
getStateData k d rd = Dict.get k rd.roomState
|> Maybe.andThen (Result.toMaybe << decodeValue d)
2019-09-11 00:52:42 -07:00
getEphemeralData : String -> Decoder a -> RoomData -> Maybe a
getEphemeralData k d rd = rd.ephemeral.events
|> Maybe.andThen (findFirst ((==) k << .type_))
|> Maybe.andThen (Result.toMaybe << decodeValue d << .content)
getRoomTypingUsers : RoomData -> List String
getRoomTypingUsers = Maybe.withDefault []
<< getEphemeralData "m.typing" (field "user_ids" (list string))
getRoomName : AccountData -> RoomId -> RoomData -> String
getRoomName ad rid rd =
2019-09-10 23:24:47 -07:00
let
2019-09-11 00:52:42 -07:00
customName = getStateData ("m.room.name", "") (field "name" (string)) rd
direct = getDirectMessages ad
2019-09-10 23:24:47 -07:00
|> Maybe.andThen (Dict.get rid)
in
case (customName, direct) of
(Just cn, _) -> cn
(_, Just d) -> getLocalDisplayName rd d
2019-09-10 23:24:47 -07:00
_ -> rid
2019-09-11 00:52:42 -07:00
getLocalDisplayName : RoomData -> Username -> String
getLocalDisplayName rd u =
getStateData ("m.room.member", u) (field "displayname" string) rd
2019-10-09 12:52:59 -07:00
|> Maybe.withDefault (getSenderName u)
2019-09-12 15:56:21 -07:00
getNotificationCount : RoomData -> (Int, Int)
getNotificationCount rd =
2019-09-11 00:52:42 -07:00
( Maybe.withDefault 0 rd.unreadNotifications.notificationCount
, Maybe.withDefault 0 rd.unreadNotifications.highlightCount
)
getTotalNotificationCount : OpenRooms -> (Int, Int)
getTotalNotificationCount =
let
sumTuples (x1, y1) (x2, y2) = (x1+x2, y1+y2)
in
2019-09-12 15:56:21 -07:00
Dict.foldl (\_ -> sumTuples << getNotificationCount) (0, 0)
2019-09-11 00:52:42 -07:00
getTotalNotificationCountString : OpenRooms -> Maybe String
getTotalNotificationCountString or =
let
(n, h) = getTotalNotificationCount or
suffix = case h of
0 -> ""
_ -> "!"
in
case n of
0 -> Nothing
_ -> Just <| "(" ++ String.fromInt n ++ suffix ++ ")"
2019-09-11 01:11:08 -07:00
getHomeserver : String -> String
getHomeserver s =
let
colonIndex = Maybe.withDefault 0
<| Maybe.map ((+) 1)
<| List.head
<| String.indexes ":" s
in
String.dropLeft colonIndex s