Compare commits
3 Commits
3e7d12b6e4
...
996da079e2
Author | SHA1 | Date | |
---|---|---|---|
996da079e2 | |||
2449a3c8c4 | |||
2505610aa2 |
|
@ -36,6 +36,7 @@ init flags url key =
|
|||
, errors = []
|
||||
, roomText = Dict.empty
|
||||
, transactionId = 0
|
||||
, userData = Dict.empty
|
||||
}
|
||||
cmd = case flags.token of
|
||||
Just _ -> Cmd.none
|
||||
|
@ -58,7 +59,9 @@ update msg model = case msg of
|
|||
TryUrl urlRequest -> updateTryUrl model urlRequest
|
||||
ChangeRoute r -> ({ model | route = r }, Cmd.none)
|
||||
ReceiveLoginResponse r -> updateLoginResponse model r
|
||||
ReceiveSyncResponse r -> updateSyncResponse model r
|
||||
ReceiveFirstSyncResponse r -> updateSyncResponse model r False
|
||||
ReceiveSyncResponse r -> updateSyncResponse model r True
|
||||
ReceiveUserData s r -> (model, Cmd.none)
|
||||
ChangeRoomText r t -> ({ model | roomText = Dict.insert r t model.roomText}, Cmd.none)
|
||||
SendRoomText r -> updateSendRoomText model r
|
||||
SendRoomTextResponse r -> (model, Cmd.none)
|
||||
|
@ -87,8 +90,8 @@ updateLoginResponse model r = case r of
|
|||
] )
|
||||
Err e -> (model, Cmd.none)
|
||||
|
||||
updateSyncResponse : Model -> Result Http.Error SyncResponse -> (Model, Cmd Msg)
|
||||
updateSyncResponse model r =
|
||||
updateSyncResponse : Model -> Result Http.Error SyncResponse -> Bool -> (Model, Cmd Msg)
|
||||
updateSyncResponse model r notify =
|
||||
let
|
||||
token = Maybe.withDefault "" model.token
|
||||
nextBatch = Result.withDefault model.sync.nextBatch
|
||||
|
|
|
@ -3,6 +3,7 @@ import Scylla.Model exposing (..)
|
|||
import Scylla.Api exposing (..)
|
||||
import Scylla.Sync exposing (syncResponseDecoder)
|
||||
import Scylla.Login exposing (loginResponseDecoder, Username, Password)
|
||||
import Scylla.UserData exposing (userDataDecoder, UserData)
|
||||
import Json.Encode exposing (object, string, int)
|
||||
import Http exposing (request, emptyBody, jsonBody, expectJson, expectWhatever)
|
||||
|
||||
|
@ -16,7 +17,7 @@ firstSync apiUrl token = request
|
|||
, headers = authenticatedHeaders token
|
||||
, url = (fullUrl apiUrl) ++ "/sync"
|
||||
, body = emptyBody
|
||||
, expect = expectJson ReceiveSyncResponse syncResponseDecoder
|
||||
, expect = expectJson ReceiveFirstSyncResponse syncResponseDecoder
|
||||
, timeout = Nothing
|
||||
, tracker = Nothing
|
||||
}
|
||||
|
@ -66,3 +67,14 @@ login apiUrl username password = request
|
|||
, timeout = Nothing
|
||||
, tracker = Nothing
|
||||
}
|
||||
|
||||
userData : ApiUrl -> ApiToken -> Username -> Cmd Msg
|
||||
userData apiUrl token username = request
|
||||
{ method = "GET"
|
||||
, headers = authenticatedHeaders token
|
||||
, url = (fullUrl apiUrl) ++ "/profile/" ++ username
|
||||
, body = emptyBody
|
||||
, expect = expectJson (ReceiveUserData username) userDataDecoder
|
||||
, timeout = Nothing
|
||||
, tracker = Nothing
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ module Scylla.Model exposing (..)
|
|||
import Scylla.Api exposing (..)
|
||||
import Scylla.Sync exposing (SyncResponse, JoinedRoom)
|
||||
import Scylla.Login exposing (LoginResponse, Username, Password)
|
||||
import Scylla.UserData exposing (UserData)
|
||||
import Scylla.Route exposing (Route)
|
||||
import Browser.Navigation as Nav
|
||||
import Dict exposing (Dict)
|
||||
|
@ -20,6 +21,7 @@ type alias Model =
|
|||
, errors : List String
|
||||
, roomText : Dict String String
|
||||
, transactionId : Int
|
||||
, userData : Dict Username UserData
|
||||
}
|
||||
|
||||
type Msg =
|
||||
|
@ -32,6 +34,8 @@ type Msg =
|
|||
| ChangeRoomText String String -- Change to a room's input text
|
||||
| SendRoomText String -- Sends a message typed into a given room's input
|
||||
| SendRoomTextResponse (Result Http.Error ()) -- A send message response finished
|
||||
| ReceiveFirstSyncResponse (Result Http.Error SyncResponse) -- HTTP, Sync has finished
|
||||
| ReceiveSyncResponse (Result Http.Error SyncResponse) -- HTTP, Sync has finished
|
||||
| ReceiveLoginResponse (Result Http.Error LoginResponse) -- HTTP, Login has finished
|
||||
| ReceiveUserData Username (Result Http.Error UserData)
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
port module Scylla.Notification exposing (..)
|
||||
import Scylla.Model exposing (..)
|
||||
import Json.Decode
|
||||
|
||||
type alias Notification =
|
||||
{ name : String
|
||||
, text : String
|
||||
, room : String
|
||||
}
|
||||
|
||||
port sendNotificationPort : Notification -> Cmd msg
|
||||
port onNotificationClockPort : (Json.Decode.Value -> msg) -> Sub msg
|
||||
port onNotificationClickPort : (Json.Decode.Value -> msg) -> Sub msg
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
module Scylla.Sync exposing (..)
|
||||
import Scylla.Api exposing (..)
|
||||
import Scylla.Notification exposing (..)
|
||||
import Scylla.Login exposing (Username)
|
||||
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)
|
||||
|
@ -267,6 +269,7 @@ uniqueByRecursive f l s = case l of
|
|||
uniqueBy : (a -> comparable) -> List a -> List a
|
||||
uniqueBy f l = uniqueByRecursive f l Set.empty
|
||||
|
||||
-- Business Logic: Merging
|
||||
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
|
||||
|
@ -347,6 +350,16 @@ mergeSyncResponse l r =
|
|||
, accountData = mergeMaybe mergeAccountData l.accountData r.accountData
|
||||
}
|
||||
|
||||
-- Business Logic: Names
|
||||
senderName : String -> String
|
||||
senderName s =
|
||||
let
|
||||
colonIndex = Maybe.withDefault -1
|
||||
<| List.head
|
||||
<| String.indexes ":" s
|
||||
in
|
||||
String.slice 1 colonIndex s
|
||||
|
||||
roomName : JoinedRoom -> Maybe String
|
||||
roomName jr =
|
||||
let
|
||||
|
@ -355,3 +368,35 @@ roomName jr =
|
|||
name e = Result.toMaybe <| Decode.decodeValue (field "name" string) e.content
|
||||
in
|
||||
Maybe.andThen name <| Maybe.andThen nameEvent <| Maybe.andThen .events <| state
|
||||
|
||||
-- Business Logic: Event Extraction
|
||||
notificationEvent : SyncResponse -> Maybe (String, RoomEvent)
|
||||
notificationEvent s =
|
||||
let
|
||||
applyPair k = List.map (\v -> (k, v))
|
||||
in
|
||||
List.head
|
||||
<| List.sortBy (\(k, v) -> v.originServerTs)
|
||||
<| Dict.foldl (\k v a -> a ++ applyPair k v) []
|
||||
<| joinedRoomsEvents s
|
||||
|
||||
joinedRoomsEvents : SyncResponse -> Dict String (List RoomEvent)
|
||||
joinedRoomsEvents s =
|
||||
Maybe.withDefault Dict.empty
|
||||
<| Maybe.map (Dict.map (\k v -> Maybe.withDefault [] <| Maybe.andThen .events v.timeline))
|
||||
<| Maybe.andThen .join s.rooms
|
||||
|
||||
-- Business Logic: User Extraction
|
||||
roomsUsers : SyncResponse -> List Username
|
||||
roomsUsers s =
|
||||
let
|
||||
users dict =
|
||||
List.map .sender
|
||||
<| (List.concatMap <| Maybe.withDefault [] << .events)
|
||||
<| (List.filterMap .timeline)
|
||||
<| Dict.values dict
|
||||
usersFor f = Maybe.withDefault [] <| Maybe.map users <| Maybe.andThen f s.rooms
|
||||
joinedUsers = usersFor .join
|
||||
leftUsers = usersFor .leave
|
||||
in
|
||||
leftUsers ++ joinedUsers
|
||||
|
|
14
src/Scylla/UserData.elm
Normal file
14
src/Scylla/UserData.elm
Normal file
|
@ -0,0 +1,14 @@
|
|||
module Scylla.UserData exposing (..)
|
||||
import Json.Decode as Decode exposing (Decoder, int, string, float, list, value, dict, bool, field)
|
||||
import Json.Decode.Pipeline exposing (required, optional)
|
||||
|
||||
type alias UserData =
|
||||
{ displayName : Maybe String
|
||||
, avatarUrl : Maybe String
|
||||
}
|
||||
|
||||
userDataDecoder : Decoder UserData
|
||||
userDataDecoder =
|
||||
Decode.succeed UserData
|
||||
|> optional "displayname" (Decode.map Just string) Nothing
|
||||
|> optional "avatar_url" (Decode.map Just string) Nothing
|
|
@ -19,15 +19,6 @@ stringColor s =
|
|||
in
|
||||
"hsl(" ++ hue ++ ", 82%, 71%)"
|
||||
|
||||
senderName : String -> String
|
||||
senderName s =
|
||||
let
|
||||
colonIndex = Maybe.withDefault -1
|
||||
<| List.head
|
||||
<| String.indexes ":" s
|
||||
in
|
||||
String.slice 1 colonIndex s
|
||||
|
||||
viewFull : Model -> List (Html Msg)
|
||||
viewFull model =
|
||||
let
|
||||
|
|
|
@ -7,6 +7,11 @@ function setupNotificationPorts(app) {
|
|||
var options = {
|
||||
"body" : data.text
|
||||
}
|
||||
new Notification(data.name, options)
|
||||
var n = new Notification(data.name, options)
|
||||
n.onclick = function() {
|
||||
app.ports.onNotificationClickPort.send({
|
||||
"room" : data.room
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user