elm-matrix-sdk-alpha/src/Internal/Room.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