Compare commits
No commits in common. "36ad2cc93c7b678def39cc249df3f4e2bff14be7" and "471f5b301ba972ef8fbe2d350eb9cc936835a287" have entirely different histories.
36ad2cc93c
...
471f5b301b
2
elm.json
2
elm.json
|
@ -13,12 +13,12 @@
|
|||
"elm/http": "2.0.0",
|
||||
"elm/json": "1.1.2",
|
||||
"elm/svg": "1.0.1",
|
||||
"elm/time": "1.0.0",
|
||||
"elm/url": "1.0.0"
|
||||
},
|
||||
"indirect": {
|
||||
"elm/bytes": "1.0.7",
|
||||
"elm/file": "1.0.1",
|
||||
"elm/time": "1.0.0",
|
||||
"elm/virtual-dom": "1.0.2"
|
||||
}
|
||||
},
|
||||
|
|
91
src/Main.elm
91
src/Main.elm
|
@ -7,7 +7,7 @@ import Scylla.Api exposing (..)
|
|||
import Scylla.Model exposing (..)
|
||||
import Scylla.Http exposing (..)
|
||||
import Scylla.Views exposing (viewFull)
|
||||
import Scylla.Route exposing (Route(..), RoomId)
|
||||
import Scylla.Route exposing (Route(..))
|
||||
import Scylla.UserData exposing (..)
|
||||
import Scylla.Notification exposing (..)
|
||||
import Scylla.Storage exposing (..)
|
||||
|
@ -15,16 +15,11 @@ import Url exposing (Url)
|
|||
import Url.Parser exposing (parse)
|
||||
import Url.Builder
|
||||
import Json.Encode
|
||||
import Json.Decode
|
||||
import Time exposing (every)
|
||||
import Html exposing (div, text)
|
||||
import Http
|
||||
import Dict
|
||||
import Task
|
||||
|
||||
syncTimeout = 10000
|
||||
typingTimeout = 2000
|
||||
|
||||
type alias Flags =
|
||||
{ token : Maybe String
|
||||
}
|
||||
|
@ -52,7 +47,7 @@ init flags url key =
|
|||
}
|
||||
cmd = case flags.token of
|
||||
Just _ -> Cmd.none
|
||||
Nothing -> getStoreValuePort "scylla.loginInfo"
|
||||
Nothing -> Nav.pushUrl key <| Url.Builder.absolute [ "login" ] []
|
||||
in
|
||||
(model, cmd)
|
||||
|
||||
|
@ -77,58 +72,10 @@ update msg model = case msg of
|
|||
ReceiveFirstSyncResponse r -> updateSyncResponse model r False
|
||||
ReceiveSyncResponse r -> updateSyncResponse model r True
|
||||
ReceiveUserData s r -> updateUserData model s r
|
||||
ChangeRoomText r t -> updateChangeRoomText model r t
|
||||
ChangeRoomText r t -> ({ model | roomText = Dict.insert r t model.roomText}, Cmd.none)
|
||||
SendRoomText r -> updateSendRoomText model r
|
||||
SendRoomTextResponse r -> (model, Cmd.none)
|
||||
ReceiveCompletedReadMarker r -> (model, Cmd.none)
|
||||
ReceiveCompletedTypingIndicator r -> (model, Cmd.none)
|
||||
ReceiveStoreData d -> updateStoreData model d
|
||||
TypingTick _ -> updateTypingTick model
|
||||
|
||||
|
||||
updateChangeRoomText : Model -> RoomId -> String -> (Model, Cmd Msg)
|
||||
updateChangeRoomText m roomId text =
|
||||
let
|
||||
typingIndicator = case (text, Dict.get roomId m.roomText) of
|
||||
("", _) -> Just False
|
||||
(_, Just "") -> Just True
|
||||
(_, Nothing) -> Just True
|
||||
_ -> Nothing
|
||||
command = case typingIndicator of
|
||||
Just b -> sendTypingIndicator m.apiUrl (Maybe.withDefault "" m.token) roomId m.loginUsername b typingTimeout
|
||||
_ -> Cmd.none
|
||||
in
|
||||
({ m | roomText = Dict.insert roomId text m.roomText}, command)
|
||||
|
||||
updateTypingTick : Model -> (Model, Cmd Msg)
|
||||
updateTypingTick m =
|
||||
let
|
||||
command = case currentRoomId m of
|
||||
Just rid -> sendTypingIndicator m.apiUrl (Maybe.withDefault "" m.token) rid m.loginUsername True typingTimeout
|
||||
Nothing -> Cmd.none
|
||||
in
|
||||
(m, command)
|
||||
|
||||
|
||||
updateStoreData : Model -> Json.Encode.Value -> (Model, Cmd Msg)
|
||||
updateStoreData m d = case (Json.Decode.decodeValue storeDataDecoder d) of
|
||||
Ok { key, value } -> case key of
|
||||
"scylla.loginInfo" -> updateLoginInfo m value
|
||||
_ -> (m, Cmd.none)
|
||||
Err _ -> (m, Cmd.none)
|
||||
|
||||
updateLoginInfo : Model -> Json.Encode.Value -> (Model, Cmd Msg)
|
||||
updateLoginInfo m s = case Json.Decode.decodeValue (Json.Decode.map decodeLoginInfo Json.Decode.string) s of
|
||||
Ok (Just { token, apiUrl, username, transactionId }) ->
|
||||
(
|
||||
{ m | token = Just token
|
||||
, apiUrl = apiUrl
|
||||
, loginUsername = username
|
||||
, transactionId = transactionId
|
||||
}
|
||||
, firstSync apiUrl token
|
||||
)
|
||||
_ -> (m, Nav.pushUrl m.key <| Url.Builder.absolute [ "login" ] [])
|
||||
|
||||
updateChangeRoute : Model -> Route -> (Model, Cmd Msg)
|
||||
updateChangeRoute m r =
|
||||
|
@ -157,23 +104,16 @@ updateUserData m s r = case r of
|
|||
Ok ud -> ({ m | userData = Dict.insert s ud m.userData }, Cmd.none)
|
||||
Err e -> (m, userData m.apiUrl (Maybe.withDefault "" m.token) s)
|
||||
|
||||
updateSendRoomText : Model -> RoomId -> (Model, Cmd Msg)
|
||||
updateSendRoomText : Model -> String -> (Model, Cmd Msg)
|
||||
updateSendRoomText m r =
|
||||
let
|
||||
token = Maybe.withDefault "" m.token
|
||||
message = Maybe.andThen (\s -> if s == "" then Nothing else Just s)
|
||||
<| Dict.get r m.roomText
|
||||
combinedCmd = case message of
|
||||
Nothing -> Cmd.none
|
||||
Just s -> Cmd.batch
|
||||
[ sendTextMessage m.apiUrl token m.transactionId r s
|
||||
, sendTypingIndicator m.apiUrl token r m.loginUsername False typingTimeout
|
||||
, setStoreValuePort ("scylla.loginInfo", Json.Encode.string
|
||||
<| encodeLoginInfo
|
||||
<| LoginInfo (Maybe.withDefault "" m.token) m.apiUrl m.loginUsername (m.transactionId + 1))
|
||||
]
|
||||
command = Maybe.withDefault Cmd.none
|
||||
<| Maybe.map (sendTextMessage m.apiUrl token m.transactionId r) message
|
||||
in
|
||||
({ m | roomText = Dict.insert r "" m.roomText, transactionId = m.transactionId + 1 }, combinedCmd)
|
||||
({ m | roomText = Dict.insert r "" m.roomText, transactionId = m.transactionId + 1 }, command)
|
||||
|
||||
updateTryUrl : Model -> Browser.UrlRequest -> (Model, Cmd Msg)
|
||||
updateTryUrl m ur = case ur of
|
||||
|
@ -185,7 +125,7 @@ updateLoginResponse model a r = case r of
|
|||
Ok lr -> ( { model | token = Just lr.accessToken, loginUsername = lr.userId, apiUrl = a }, Cmd.batch
|
||||
[ firstSync model.apiUrl lr.accessToken
|
||||
, Nav.pushUrl model.key <| Url.Builder.absolute [] []
|
||||
, setStoreValuePort ("scylla.loginInfo", Json.Encode.string <| encodeLoginInfo (lr.accessToken, model.apiUrl, lr.userId))
|
||||
, setStoreValuePort ("scylla.loginInfo", Json.Encode.string (lr.accessToken ++ "\n" ++ model.apiUrl))
|
||||
] )
|
||||
Err e -> (model, Cmd.none)
|
||||
|
||||
|
@ -242,20 +182,7 @@ updateSyncResponse model r notify =
|
|||
_ -> (model, syncCmd)
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions m =
|
||||
let
|
||||
currentText = Maybe.withDefault ""
|
||||
<| Maybe.andThen (\rid -> Dict.get rid m.roomText)
|
||||
<| currentRoomId m
|
||||
typingTimer = case currentText of
|
||||
"" -> Sub.none
|
||||
_ -> every typingTimeout TypingTick
|
||||
in
|
||||
Sub.batch
|
||||
[ onNotificationClickPort OpenRoom
|
||||
, receiveStoreValuePort ReceiveStoreData
|
||||
, typingTimer
|
||||
]
|
||||
subscriptions m = onNotificationClickPort OpenRoom
|
||||
|
||||
onUrlRequest : Browser.UrlRequest -> Msg
|
||||
onUrlRequest = TryUrl
|
||||
|
|
|
@ -5,7 +5,7 @@ import Scylla.Route exposing (RoomId)
|
|||
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, bool)
|
||||
import Json.Encode exposing (object, string, int)
|
||||
import Http exposing (request, emptyBody, jsonBody, expectJson, expectWhatever)
|
||||
|
||||
fullClientUrl : ApiUrl -> ApiUrl
|
||||
|
@ -99,14 +99,3 @@ setReadMarkers apiUrl token roomId fullyRead readReceipt =
|
|||
, timeout = Nothing
|
||||
, tracker = Nothing
|
||||
}
|
||||
|
||||
sendTypingIndicator : ApiUrl -> ApiToken -> RoomId -> Username -> Bool -> Int -> Cmd Msg
|
||||
sendTypingIndicator apiUrl token room user isTyping timeout = request
|
||||
{ method = "PUT"
|
||||
, headers = authenticatedHeaders token
|
||||
, url = (fullClientUrl apiUrl) ++ "/rooms/" ++ room ++ "/typing/" ++ user
|
||||
, body = jsonBody <| object [ ("timeout", int timeout), ("typing", bool isTyping) ]
|
||||
, expect = expectWhatever ReceiveCompletedTypingIndicator
|
||||
, timeout = Nothing
|
||||
, tracker = Nothing
|
||||
}
|
||||
|
|
|
@ -1,32 +1,11 @@
|
|||
module Scylla.Login exposing (..)
|
||||
import Scylla.Api exposing (ApiUrl, ApiToken)
|
||||
import Scylla.Api exposing (ApiToken)
|
||||
import Json.Decode as Decode exposing (Decoder, int, string, float, list, value, dict, bool)
|
||||
import Json.Decode.Pipeline exposing (required, optional)
|
||||
import Json.Encode as Encode
|
||||
|
||||
type alias Username = String
|
||||
type alias Password = String
|
||||
|
||||
type alias LoginInfo =
|
||||
{ token : ApiToken
|
||||
, apiUrl : ApiUrl
|
||||
, username : Username
|
||||
, transactionId : Int
|
||||
}
|
||||
|
||||
encodeLoginInfo : LoginInfo -> String
|
||||
encodeLoginInfo {token, apiUrl, username, transactionId} =
|
||||
token ++ "," ++ apiUrl ++ "," ++ username ++ "," ++ (String.fromInt transactionId)
|
||||
|
||||
decodeLoginInfo : String -> Maybe LoginInfo
|
||||
decodeLoginInfo s = case String.indexes "," s of
|
||||
[ fst, snd, thd ] -> Just <| LoginInfo
|
||||
(String.slice 0 fst s)
|
||||
(String.slice (fst + 1) snd s)
|
||||
(String.slice (snd + 1) thd s)
|
||||
(Maybe.withDefault 0 <| String.toInt <| String.dropLeft (thd + 1) s)
|
||||
_ -> Nothing
|
||||
|
||||
type alias LoginResponse =
|
||||
{ userId : String
|
||||
, accessToken : ApiToken
|
||||
|
|
|
@ -4,13 +4,10 @@ import Scylla.Sync exposing (SyncResponse, JoinedRoom, senderName)
|
|||
import Scylla.Login exposing (LoginResponse, Username, Password)
|
||||
import Scylla.UserData exposing (UserData)
|
||||
import Scylla.Route exposing (Route(..), RoomId)
|
||||
import Scylla.Storage exposing (..)
|
||||
import Browser.Navigation as Nav
|
||||
import Browser.Dom exposing (Viewport)
|
||||
import Url.Builder
|
||||
import Dict exposing (Dict)
|
||||
import Time exposing (Posix)
|
||||
import Json.Decode
|
||||
import Browser
|
||||
import Http
|
||||
import Url exposing (Url)
|
||||
|
@ -45,11 +42,8 @@ type Msg =
|
|||
| ReceiveFirstSyncResponse (Result Http.Error SyncResponse) -- HTTP, Sync has finished
|
||||
| ReceiveSyncResponse (Result Http.Error SyncResponse) -- HTTP, Sync has finished
|
||||
| ReceiveLoginResponse ApiUrl (Result Http.Error LoginResponse) -- HTTP, Login has finished
|
||||
| ReceiveUserData Username (Result Http.Error UserData) -- HTTP, receive user data
|
||||
| ReceiveCompletedReadMarker (Result Http.Error ()) -- HTTP, read marker request completed
|
||||
| ReceiveCompletedTypingIndicator (Result Http.Error ()) -- HTTP, typing indicator request completed
|
||||
| ReceiveStoreData Json.Decode.Value -- We are send back a value on request from localStorage.
|
||||
| TypingTick Posix -- Tick for updating the typing status
|
||||
| ReceiveUserData Username (Result Http.Error UserData)
|
||||
| ReceiveCompletedReadMarker (Result Http.Error ())
|
||||
|
||||
displayName : Model -> Username -> String
|
||||
displayName m s = Maybe.withDefault (senderName s) <| Maybe.andThen .displayName <| Dict.get s m.userData
|
||||
|
|
|
@ -1,17 +1,5 @@
|
|||
port module Scylla.Storage exposing (..)
|
||||
import Json.Encode
|
||||
import Json.Decode as Decode exposing (Decoder, int, string, float, list, value, dict, bool)
|
||||
import Json.Decode.Pipeline exposing (required, optional)
|
||||
|
||||
type alias StoreData =
|
||||
{ key : String
|
||||
, value: Decode.Value
|
||||
}
|
||||
|
||||
storeDataDecoder : Decoder StoreData
|
||||
storeDataDecoder = Decode.succeed StoreData
|
||||
|> required "key" string
|
||||
|> required "value" value
|
||||
|
||||
port setStoreValuePort : (String, Json.Encode.Value) -> Cmd msg
|
||||
port getStoreValuePort : (String) -> Cmd msg
|
||||
|
|
|
@ -5,6 +5,6 @@ function setupStorage(app) {
|
|||
localStorage.setItem(key, value);
|
||||
});
|
||||
app.ports.getStoreValuePort.subscribe(function(data) {
|
||||
app.ports.receiveStoreValuePort.send({ "key" : data, "value" : localStorage.getItem(data) });
|
||||
app.ports.receiveStoreValuePort.send(localStorage.getItem(data));
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user