265 lines
8.9 KiB
Elm
265 lines
8.9 KiB
Elm
module Internal.Room exposing (..)
|
|
|
|
{-| The `Room` type represents a Matrix Room. In here, you will find utilities to ask information about a room.
|
|
-}
|
|
|
|
import Dict
|
|
import Internal.Api.Snackbar as Snackbar
|
|
import Internal.Api.Sync.V2.SpecObjects as Sync
|
|
import Internal.Api.Task as Api
|
|
import Internal.Api.VaultUpdate exposing (VaultUpdate(..), Vnackbar)
|
|
import Internal.Event as Event exposing (Event)
|
|
import Internal.Tools.Hashdict as Hashdict
|
|
import Internal.Tools.SpecEnums as Enums
|
|
import Internal.Values.Event as IEvent
|
|
import Internal.Values.Room as Internal
|
|
import Internal.Values.StateManager as StateManager
|
|
import Internal.Values.Timeline as Timeline
|
|
import Json.Encode as E
|
|
import Task exposing (Task)
|
|
|
|
|
|
{-| The `Room` type represents a Matrix Room. It contains context information
|
|
such as the `accessToken` that allows the retrieval of new information from
|
|
the Matrix API if necessary.
|
|
|
|
The `Room` type contains utilities to inquire about the room and send messages
|
|
to it.
|
|
|
|
-}
|
|
type alias Room =
|
|
Vnackbar Internal.IRoom
|
|
|
|
|
|
{-| Create a new object from a joined room.
|
|
-}
|
|
initFromJoinedRoom : { roomId : String, nextBatch : String } -> Sync.JoinedRoom -> Internal.IRoom
|
|
initFromJoinedRoom data jroom =
|
|
Internal.IRoom
|
|
{ accountData =
|
|
jroom.accountData
|
|
|> Maybe.map .events
|
|
|> Maybe.withDefault []
|
|
|> List.map (\{ eventType, content } -> ( eventType, content ))
|
|
|> Dict.fromList
|
|
, ephemeral =
|
|
jroom.ephemeral
|
|
|> Maybe.map .events
|
|
|> Maybe.withDefault []
|
|
|> List.map IEvent.BlindEvent
|
|
, events =
|
|
jroom.timeline
|
|
|> Maybe.map .events
|
|
|> Maybe.withDefault []
|
|
|> List.map (Event.initFromClientEventWithoutRoomId data.roomId)
|
|
|> Hashdict.fromList IEvent.eventId
|
|
, roomId = data.roomId
|
|
, tempEvents = []
|
|
, timeline =
|
|
jroom.timeline
|
|
|> Maybe.map
|
|
(\timeline ->
|
|
Timeline.newFromEvents
|
|
{ events = List.map (Event.initFromClientEventWithoutRoomId data.roomId) timeline.events
|
|
, nextBatch = data.nextBatch
|
|
, prevBatch = timeline.prevBatch
|
|
, stateDelta =
|
|
jroom.state
|
|
|> Maybe.map
|
|
(.events
|
|
>> List.map (Event.initFromClientEventWithoutRoomId data.roomId)
|
|
>> StateManager.fromEventList
|
|
)
|
|
}
|
|
)
|
|
|> Maybe.withDefault
|
|
(Timeline.newFromEvents
|
|
{ events = []
|
|
, nextBatch = data.nextBatch
|
|
, prevBatch = Nothing
|
|
, stateDelta = Nothing
|
|
}
|
|
)
|
|
}
|
|
|
|
|
|
accountData : String -> Room -> Maybe E.Value
|
|
accountData key =
|
|
Snackbar.withoutCandy >> Internal.accountData key
|
|
|
|
|
|
{-| Add account data to the room.
|
|
-}
|
|
addAccountData : String -> E.Value -> Room -> Room
|
|
addAccountData eventType content =
|
|
Snackbar.map (Internal.addAccountData eventType content)
|
|
|
|
|
|
{-| Adds an internal event to the `Room`. An internal event is a custom event
|
|
that has been generated by the client.
|
|
-}
|
|
addInternalEvent : IEvent.IEvent -> Room -> Room
|
|
addInternalEvent ievent =
|
|
Snackbar.map (Internal.addEvent ievent)
|
|
|
|
|
|
{-| Adds an `Event` object to the `Room`. An `Event` is a value from the
|
|
`Internal.Event` module that is used to represent an event in a Matrix room.
|
|
-}
|
|
addEvent : Event -> Room -> Room
|
|
addEvent =
|
|
Snackbar.withoutCandy >> addInternalEvent
|
|
|
|
|
|
{-| Get a given state event.
|
|
-}
|
|
getStateEvent : { eventType : String, stateKey : String } -> Room -> Maybe Event
|
|
getStateEvent data =
|
|
Snackbar.mapMaybe (Internal.getStateEvent data)
|
|
|
|
|
|
{-| Get older events from the Matrix API.
|
|
-}
|
|
findOlderEvents : { limit : Maybe Int, onResponse : VaultUpdate -> msg } -> Room -> Cmd msg
|
|
findOlderEvents { limit, onResponse } room =
|
|
case Internal.latestGap (Snackbar.withoutCandy room) of
|
|
Nothing ->
|
|
Task.succeed (MultipleUpdates []) |> Task.perform onResponse
|
|
|
|
Just { from, to } ->
|
|
Api.getMessages
|
|
{ direction = Enums.ReverseChronological
|
|
, filter = Nothing
|
|
, from = Just to
|
|
, limit = limit
|
|
, roomId = roomId room
|
|
, to = from
|
|
}
|
|
room
|
|
|> Task.perform onResponse
|
|
|
|
|
|
{-| Get the most recent events.
|
|
-}
|
|
mostRecentEvents : Room -> List Event
|
|
mostRecentEvents =
|
|
Snackbar.mapList Internal.mostRecentEvents
|
|
|
|
|
|
{-| Retrieves the ID of the Matrix room associated with the given `Room`.
|
|
-}
|
|
roomId : Room -> String
|
|
roomId =
|
|
Snackbar.withoutCandy >> Internal.roomId
|
|
|
|
|
|
{-| Sends a new event to the Matrix room associated with the given `Room`.
|
|
-}
|
|
sendEvent : { content : E.Value, eventType : String, stateKey : Maybe String, onResponse : VaultUpdate -> msg, room : Room } -> Cmd msg
|
|
sendEvent { eventType, content, stateKey, onResponse, room } =
|
|
case stateKey of
|
|
Nothing ->
|
|
Api.sendMessageEvent
|
|
{ content = content
|
|
, eventType = eventType
|
|
, extraTransactionNoise = "send-one-message"
|
|
, roomId = roomId room
|
|
}
|
|
room
|
|
|> Task.perform onResponse
|
|
|
|
Just s ->
|
|
Api.sendStateEvent
|
|
{ content = content
|
|
, eventType = eventType
|
|
, stateKey = s
|
|
, roomId = roomId room
|
|
}
|
|
room
|
|
|> Task.perform onResponse
|
|
|
|
|
|
sendEvents : List { content : E.Value, eventType : String, stateKey : Maybe String, onResponse : VaultUpdate -> msg } -> Room -> Cmd msg
|
|
sendEvents events room =
|
|
List.indexedMap Tuple.pair events
|
|
|> List.map
|
|
(\( i, { eventType, content, stateKey, onResponse } ) ->
|
|
case stateKey of
|
|
Nothing ->
|
|
Api.sendMessageEvent
|
|
{ content = content
|
|
, eventType = eventType
|
|
, extraTransactionNoise = "send-message-" ++ String.fromInt i
|
|
, roomId = roomId room
|
|
}
|
|
room
|
|
|> Task.perform onResponse
|
|
|
|
Just s ->
|
|
Api.sendStateEvent
|
|
{ content = content
|
|
, eventType = eventType
|
|
, stateKey = s
|
|
, roomId = roomId room
|
|
}
|
|
room
|
|
|> Task.perform onResponse
|
|
)
|
|
|> Cmd.batch
|
|
|
|
|
|
{-| Sends a new text message to the Matrix room associated with the given `Room`.
|
|
-}
|
|
sendMessage : { text : String, onResponse : VaultUpdate -> msg } -> Room -> Cmd msg
|
|
sendMessage { text, onResponse } room =
|
|
Api.sendMessageEvent
|
|
{ content =
|
|
E.object
|
|
[ ( "msgtype", E.string "m.text" )
|
|
, ( "body", E.string text )
|
|
]
|
|
, eventType = "m.room.message"
|
|
, extraTransactionNoise = "literal-message:" ++ text
|
|
, roomId = roomId room
|
|
}
|
|
room
|
|
|> Task.perform onResponse
|
|
|
|
|
|
sendMessages : { textPieces : List String, onResponse : VaultUpdate -> msg } -> Room -> Cmd msg
|
|
sendMessages { textPieces, onResponse } room =
|
|
textPieces
|
|
|> List.indexedMap Tuple.pair
|
|
|> List.map
|
|
(\( i, piece ) ->
|
|
Api.sendMessageEvent
|
|
{ content =
|
|
E.object
|
|
[ ( "msgtype", E.string "m.text" )
|
|
, ( "body", E.string piece )
|
|
]
|
|
, eventType = "m.room.message"
|
|
, extraTransactionNoise = "literal-message-" ++ String.fromInt i ++ ":" ++ piece
|
|
, roomId = roomId room
|
|
}
|
|
room
|
|
)
|
|
|> List.map (Task.perform onResponse)
|
|
|> Cmd.batch
|
|
|
|
|
|
{-| Leave this room.
|
|
-}
|
|
leave : (VaultUpdate -> msg) -> Room -> Cmd msg
|
|
leave onResponse room =
|
|
Api.leave { roomId = roomId room, reason = Nothing } room
|
|
|> Task.perform onResponse
|
|
|
|
|
|
{-| Set account data.
|
|
-}
|
|
setAccountData : { key : String, value : E.Value, onResponse : VaultUpdate -> msg, room : Room } -> Cmd msg
|
|
setAccountData { key, value, onResponse, room } =
|
|
Api.setAccountData { content = value, eventType = key, roomId = Just (roomId room) } room
|
|
|> Task.perform onResponse
|