From 00ffcecf1d51db36c96ca2c98a37e6585788f228 Mon Sep 17 00:00:00 2001 From: Vincent Jousse Date: Tue, 25 Apr 2017 23:33:37 +0200 Subject: [PATCH] Add websocket for local and global timeline (#66) * Connect to the websocket API * Enable user timeline update through websockets * Update elm-html-parser to latest * Listem to local and global timelines * Subscribe to global timeline only if it's displayed * Some review changes * Add elm-test and test notification aggregates * Add new follow notification * Fex addNotificationToAggregates * Add test * Clarify logic * Update local and global timelines using WS I've renamed the "public" timeline to "global", and removed the HTTP reload of the user timeline when posting a Toot. We only rely on websockets now. --- src/Mastodon.elm | 6 +++--- src/Model.elm | 52 +++++++++++++++++++++++++++++++++++------------- src/View.elm | 9 ++++----- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/Mastodon.elm b/src/Mastodon.elm index 981cd3f..513dac1 100644 --- a/src/Mastodon.elm +++ b/src/Mastodon.elm @@ -30,7 +30,7 @@ module Mastodon , fetchAccount , fetchLocalTimeline , fetchNotifications - , fetchPublicTimeline + , fetchGlobalTimeline , fetchUserTimeline , postStatus , send @@ -662,8 +662,8 @@ fetchLocalTimeline client = fetch client "/api/v1/timelines/public?local=true" <| Decode.list statusDecoder -fetchPublicTimeline : Client -> Request (List Status) -fetchPublicTimeline client = +fetchGlobalTimeline : Client -> Request (List Status) +fetchGlobalTimeline client = fetch client "/api/v1/timelines/public" <| Decode.list statusDecoder diff --git a/src/Model.elm b/src/Model.elm index f3fe950..11fbdea 100644 --- a/src/Model.elm +++ b/src/Model.elm @@ -37,7 +37,7 @@ type MastodonMsg | FavoriteRemoved (Result Mastodon.Error Mastodon.Status) | LocalTimeline (Result Mastodon.Error (List Mastodon.Status)) | Notifications (Result Mastodon.Error (List Mastodon.Notification)) - | PublicTimeline (Result Mastodon.Error (List Mastodon.Status)) + | GlobalTimeline (Result Mastodon.Error (List Mastodon.Status)) | Reblogged (Result Mastodon.Error Mastodon.Status) | StatusPosted (Result Mastodon.Error Mastodon.Status) | Unreblogged (Result Mastodon.Error Mastodon.Status) @@ -92,7 +92,7 @@ type alias Model = , client : Maybe Mastodon.Client , userTimeline : List Mastodon.Status , localTimeline : List Mastodon.Status - , publicTimeline : List Mastodon.Status + , globalTimeline : List Mastodon.Status , notifications : List Mastodon.NotificationAggregate , draft : Draft , account : Maybe Mastodon.Account @@ -134,7 +134,7 @@ init flags location = , client = flags.client , userTimeline = [] , localTimeline = [] - , publicTimeline = [] + , globalTimeline = [] , notifications = [] , draft = defaultDraft , account = Nothing @@ -217,7 +217,7 @@ loadTimelines client = Cmd.batch [ Mastodon.fetchUserTimeline client |> Mastodon.send (MastodonEvent << UserTimeline) , Mastodon.fetchLocalTimeline client |> Mastodon.send (MastodonEvent << LocalTimeline) - , Mastodon.fetchPublicTimeline client |> Mastodon.send (MastodonEvent << PublicTimeline) + , Mastodon.fetchGlobalTimeline client |> Mastodon.send (MastodonEvent << GlobalTimeline) , loadNotifications <| Just client ] @@ -275,7 +275,7 @@ updateTimelinesWithBoolFlag statusId flag statusUpdater model = { model | userTimeline = List.map (update flag) model.userTimeline , localTimeline = List.map (update flag) model.localTimeline - , publicTimeline = List.map (update flag) model.publicTimeline + , globalTimeline = List.map (update flag) model.globalTimeline } @@ -417,13 +417,13 @@ processMastodonEvent msg model = Err error -> { model | notifications = [], errors = (errorText error) :: model.errors } ! [] - PublicTimeline result -> + GlobalTimeline result -> case result of - Ok publicTimeline -> - { model | publicTimeline = publicTimeline } ! [] + Ok globalTimeline -> + { model | globalTimeline = globalTimeline } ! [] Err error -> - { model | publicTimeline = [], errors = (errorText error) :: model.errors } ! [] + { model | globalTimeline = [], errors = (errorText error) :: model.errors } ! [] Reblogged result -> case result of @@ -434,7 +434,7 @@ processMastodonEvent msg model = { model | errors = (errorText error) :: model.errors } ! [] StatusPosted _ -> - { model | draft = defaultDraft } ! [ loadTimelines model.client ] + { model | draft = defaultDraft } ! [] Unreblogged result -> case result of @@ -601,12 +601,36 @@ update msg model = { model | errors = (logError "StatusResult" error message) :: model.errors } ! [] NewWebsocketLocalMessage message -> - -- @TODO - model ! [] + case (Mastodon.decodeWebSocketMessage message) of + Mastodon.EventError error -> + { model | errors = error :: model.errors } ! [] + + Mastodon.StatusResult result -> + case result of + Ok status -> + { model | localTimeline = status :: model.localTimeline } ! [] + + Err error -> + { model | errors = error :: model.errors } ! [] + + _ -> + model ! [] NewWebsocketGlobalMessage message -> - -- @TODO - model ! [] + case (Mastodon.decodeWebSocketMessage message) of + Mastodon.EventError error -> + { model | errors = error :: model.errors } ! [] + + Mastodon.StatusResult result -> + case result of + Ok status -> + { model | globalTimeline = status :: model.globalTimeline } ! [] + + Err error -> + { model | errors = error :: model.errors } ! [] + + _ -> + model ! [] subscriptions : Model -> Sub Msg diff --git a/src/View.elm b/src/View.elm index 2fb0471..78e43df 100644 --- a/src/View.elm +++ b/src/View.elm @@ -153,10 +153,9 @@ statusView context ({ account, content, media_attachments, reblog, mentions } as let accountLinkAttributes = [ href account.url - - -- When clicking on a status, we should not let the browser - -- redirect to a new page. That's why we're preventing the default - -- behavior here + -- When clicking on a status, we should not let the browser + -- redirect to a new page. That's why we're preventing the default + -- behavior here , ViewHelper.onClickWithPreventAndStop (OnLoadUserAccount account.id) ] in @@ -575,7 +574,7 @@ homepageView model = Nothing -> if model.useGlobalTimeline then - timelineView "Global timeline" "globe" "global" model.publicTimeline + timelineView "Global timeline" "globe" "global" model.globalTimeline else timelineView "Local timeline" "th-large" "local" model.localTimeline ]