1
0
Fork 0

Fix #134: Paginate notifications. (#136)

This commit is contained in:
Nicolas Perriault 2017-05-05 23:35:54 +02:00 committed by GitHub
parent 102210aebb
commit 56ade98158
7 changed files with 86 additions and 71 deletions

View File

@ -121,15 +121,14 @@ saveRegistration registration =
|> Ports.saveRegistration |> Ports.saveRegistration
loadNotifications : Maybe Client -> Cmd Msg loadNotifications : Maybe Client -> Maybe String -> Cmd Msg
loadNotifications client = loadNotifications client url =
-- TODO: handle link (see loadUserTimeline)
case client of case client of
Just client -> Just client ->
HttpBuilder.get ApiUrl.notifications HttpBuilder.get (Maybe.withDefault ApiUrl.notifications url)
|> withClient client |> withClient client
|> withBodyDecoder (Decode.list notificationDecoder) |> withBodyDecoder (Decode.list notificationDecoder)
|> send (MastodonEvent << Notifications) |> send (MastodonEvent << Notifications (url /= Nothing))
Nothing -> Nothing ->
Cmd.none Cmd.none
@ -312,26 +311,29 @@ loadTimelines client =
[ loadUserTimeline client Nothing [ loadUserTimeline client Nothing
, loadLocalTimeline client Nothing , loadLocalTimeline client Nothing
, loadGlobalTimeline client Nothing , loadGlobalTimeline client Nothing
, loadNotifications client , loadNotifications client Nothing
] ]
loadNextTimeline : Maybe Client -> CurrentView -> Timeline -> Cmd Msg loadNextTimeline : Maybe Client -> CurrentView -> String -> String -> Cmd Msg
loadNextTimeline client currentView { id, links } = loadNextTimeline client currentView id next =
case id of case id of
"notifications" ->
loadNotifications client (Just next)
"home-timeline" -> "home-timeline" ->
loadUserTimeline client links.next loadUserTimeline client (Just next)
"local-timeline" -> "local-timeline" ->
loadLocalTimeline client links.next loadLocalTimeline client (Just next)
"global-timeline" -> "global-timeline" ->
loadGlobalTimeline client links.next loadGlobalTimeline client (Just next)
"account-timeline" -> "account-timeline" ->
case currentView of case currentView of
AccountView account -> AccountView account ->
loadAccountTimeline client account.id links.next loadAccountTimeline client account.id (Just next)
_ -> _ ->
Cmd.none Cmd.none

View File

@ -64,7 +64,7 @@ init flags location =
, accountFollowing = [] , accountFollowing = []
, accountRelationships = [] , accountRelationships = []
, accountRelationship = Nothing , accountRelationship = Nothing
, notifications = [] , notifications = emptyTimeline "notifications"
, draft = defaultDraft , draft = defaultDraft
, errors = [] , errors = []
, location = location , location = location
@ -77,10 +77,10 @@ init flags location =
! [ Command.initCommands flags.registration flags.client authCode ] ! [ Command.initCommands flags.registration flags.client authCode ]
emptyTimeline : String -> Timeline emptyTimeline : String -> Timeline a
emptyTimeline id = emptyTimeline id =
{ id = id { id = id
, statuses = [] , entries = []
, links = Links Nothing Nothing , links = Links Nothing Nothing
} }
@ -135,7 +135,7 @@ updateTimelinesWithBoolFlag statusId flag statusUpdater model =
status status
updateTimeline timeline = updateTimeline timeline =
{ timeline | statuses = List.map update timeline.statuses } { timeline | entries = List.map update timeline.entries }
in in
{ model { model
| userTimeline = updateTimeline model.userTimeline | userTimeline = updateTimeline model.userTimeline
@ -198,7 +198,7 @@ processReblog statusId flag model =
model model
deleteStatusFromTimeline : Int -> Timeline -> Timeline deleteStatusFromTimeline : Int -> Timeline Status -> Timeline Status
deleteStatusFromTimeline statusId timeline = deleteStatusFromTimeline statusId timeline =
let let
update status = update status =
@ -207,7 +207,7 @@ deleteStatusFromTimeline statusId timeline =
&& (Mastodon.Helper.extractReblog status).id && (Mastodon.Helper.extractReblog status).id
/= statusId /= statusId
in in
{ timeline | statuses = List.filter update timeline.statuses } { timeline | entries = List.filter update timeline.entries }
deleteStatusFromAllTimelines : Int -> Model -> Model deleteStatusFromAllTimelines : Int -> Model -> Model
@ -218,12 +218,13 @@ deleteStatusFromAllTimelines id model =
, localTimeline = deleteStatusFromTimeline id model.localTimeline , localTimeline = deleteStatusFromTimeline id model.localTimeline
, globalTimeline = deleteStatusFromTimeline id model.globalTimeline , globalTimeline = deleteStatusFromTimeline id model.globalTimeline
, accountTimeline = deleteStatusFromTimeline id model.accountTimeline , accountTimeline = deleteStatusFromTimeline id model.accountTimeline
, currentView = deleteStatusFromThread id model , currentView = deleteStatusFromCurrentView id model
} }
deleteStatusFromThread : Int -> Model -> CurrentView deleteStatusFromCurrentView : Int -> Model -> CurrentView
deleteStatusFromThread id model = deleteStatusFromCurrentView id model =
-- TODO: delete from current account view
case model.currentView of case model.currentView of
ThreadView thread -> ThreadView thread ->
if thread.status.id == id then if thread.status.id == id then
@ -480,21 +481,21 @@ updateViewer viewerMsg viewer =
(Just <| Viewer attachments attachment) ! [] (Just <| Viewer attachments attachment) ! []
updateTimeline : Bool -> List Status -> Links -> Timeline -> Timeline updateTimeline : Bool -> List a -> Links -> Timeline a -> Timeline a
updateTimeline append statuses links timeline = updateTimeline append entries links timeline =
let let
newStatuses = newEntries =
if append then if append then
List.concat [ timeline.statuses, statuses ] List.concat [ timeline.entries, entries ]
else else
statuses entries
in in
{ timeline | statuses = newStatuses, links = links } { timeline | entries = newEntries, links = links }
prependStatusToTimeline : Status -> Timeline -> Timeline prependToTimeline : a -> Timeline a -> Timeline a
prependStatusToTimeline status timeline = prependToTimeline entry timeline =
{ timeline | statuses = status :: timeline.statuses } { timeline | entries = entry :: timeline.entries }
processMastodonEvent : MastodonMsg -> Model -> ( Model, Cmd Msg ) processMastodonEvent : MastodonMsg -> Model -> ( Model, Cmd Msg )
@ -568,7 +569,7 @@ processMastodonEvent msg model =
FavoriteAdded result -> FavoriteAdded result ->
case result of case result of
Ok _ -> Ok _ ->
model ! [ Command.loadNotifications model.client ] model ! []
Err error -> Err error ->
{ model | errors = (errorText error) :: model.errors } ! [] { model | errors = (errorText error) :: model.errors } ! []
@ -576,7 +577,7 @@ processMastodonEvent msg model =
FavoriteRemoved result -> FavoriteRemoved result ->
case result of case result of
Ok _ -> Ok _ ->
model ! [ Command.loadNotifications model.client ] model ! []
Err error -> Err error ->
{ model | errors = (errorText error) :: model.errors } ! [] { model | errors = (errorText error) :: model.errors } ! []
@ -589,11 +590,14 @@ processMastodonEvent msg model =
Err error -> Err error ->
{ model | errors = (errorText error) :: model.errors } ! [] { model | errors = (errorText error) :: model.errors } ! []
Notifications result -> Notifications append result ->
case result of case result of
Ok { decoded } -> Ok { decoded, links } ->
-- TODO: store next link let
{ model | notifications = Mastodon.Helper.aggregateNotifications decoded } ! [] aggregated =
Mastodon.Helper.aggregateNotifications decoded
in
{ model | notifications = updateTimeline append aggregated links model.notifications } ! []
Err error -> Err error ->
{ model | errors = (errorText error) :: model.errors } ! [] { model | errors = (errorText error) :: model.errors } ! []
@ -609,7 +613,7 @@ processMastodonEvent msg model =
Reblogged result -> Reblogged result ->
case result of case result of
Ok _ -> Ok _ ->
model ! [ Command.loadNotifications model.client ] model ! []
Err error -> Err error ->
{ model | errors = (errorText error) :: model.errors } ! [] { model | errors = (errorText error) :: model.errors } ! []
@ -631,7 +635,7 @@ processMastodonEvent msg model =
Unreblogged result -> Unreblogged result ->
case result of case result of
Ok _ -> Ok _ ->
model ! [ Command.loadNotifications model.client ] model ! []
Err error -> Err error ->
{ model | errors = (errorText error) :: model.errors } ! [] { model | errors = (errorText error) :: model.errors } ! []
@ -764,7 +768,7 @@ processWebSocketMsg msg model =
Mastodon.WebSocket.StatusUpdateEvent result -> Mastodon.WebSocket.StatusUpdateEvent result ->
case result of case result of
Ok status -> Ok status ->
{ model | userTimeline = prependStatusToTimeline status model.userTimeline } ! [] { model | userTimeline = prependToTimeline status model.userTimeline } ! []
Err error -> Err error ->
{ model | errors = error :: model.errors } ! [] { model | errors = error :: model.errors } ! []
@ -781,12 +785,18 @@ processWebSocketMsg msg model =
case result of case result of
Ok notification -> Ok notification ->
let let
notifications = oldNotifications =
Mastodon.Helper.addNotificationToAggregates model.notifications
notification
model.notifications newNotifications =
{ oldNotifications
| entries =
Mastodon.Helper.addNotificationToAggregates
notification
oldNotifications.entries
}
in in
{ model | notifications = notifications } ! [] { model | notifications = newNotifications } ! []
Err error -> Err error ->
{ model | errors = error :: model.errors } ! [] { model | errors = error :: model.errors } ! []
@ -799,7 +809,7 @@ processWebSocketMsg msg model =
Mastodon.WebSocket.StatusUpdateEvent result -> Mastodon.WebSocket.StatusUpdateEvent result ->
case result of case result of
Ok status -> Ok status ->
{ model | localTimeline = prependStatusToTimeline status model.localTimeline } ! [] { model | localTimeline = prependToTimeline status model.localTimeline } ! []
Err error -> Err error ->
{ model | errors = error :: model.errors } ! [] { model | errors = error :: model.errors } ! []
@ -823,7 +833,7 @@ processWebSocketMsg msg model =
Mastodon.WebSocket.StatusUpdateEvent result -> Mastodon.WebSocket.StatusUpdateEvent result ->
case result of case result of
Ok status -> Ok status ->
{ model | globalTimeline = prependStatusToTimeline status model.globalTimeline } ! [] { model | globalTimeline = prependToTimeline status model.globalTimeline } ! []
Err error -> Err error ->
{ model | errors = error :: model.errors } ! [] { model | errors = error :: model.errors } ! []
@ -924,8 +934,8 @@ update msg model =
} }
! [ Command.loadAccount model.client accountId ] ! [ Command.loadAccount model.client accountId ]
LoadNext timeline -> TimelineLoadNext id next ->
model ! [ Command.loadNextTimeline model.client model.currentView timeline ] model ! [ Command.loadNextTimeline model.client model.currentView id next ]
ViewAccountFollowers account -> ViewAccountFollowers account ->
{ model | currentView = AccountFollowersView account model.accountFollowers } { model | currentView = AccountFollowersView account model.accountFollowers }

View File

@ -52,7 +52,7 @@ type MastodonMsg
| FavoriteRemoved (MastodonResult Status) | FavoriteRemoved (MastodonResult Status)
| GlobalTimeline Bool (MastodonResult (List Status)) | GlobalTimeline Bool (MastodonResult (List Status))
| LocalTimeline Bool (MastodonResult (List Status)) | LocalTimeline Bool (MastodonResult (List Status))
| Notifications (MastodonResult (List Notification)) | Notifications Bool (MastodonResult (List Notification))
| Reblogged (MastodonResult Status) | Reblogged (MastodonResult Status)
| StatusDeleted (MastodonResult Int) | StatusDeleted (MastodonResult Int)
| StatusPosted (MastodonResult Status) | StatusPosted (MastodonResult Status)
@ -75,7 +75,7 @@ type Msg
| FilterNotifications NotificationFilter | FilterNotifications NotificationFilter
| FollowAccount Int | FollowAccount Int
| LoadAccount Int | LoadAccount Int
| LoadNext Timeline | TimelineLoadNext String String
| MastodonEvent MastodonMsg | MastodonEvent MastodonMsg
| NoOp | NoOp
| OpenThread Status | OpenThread Status
@ -150,9 +150,9 @@ type alias Viewer =
} }
type alias Timeline = type alias Timeline a =
{ id : String { id : String
, statuses : List Status , entries : List a
, links : Links , links : Links
} }
@ -161,15 +161,15 @@ type alias Model =
{ server : String { server : String
, registration : Maybe AppRegistration , registration : Maybe AppRegistration
, client : Maybe Client , client : Maybe Client
, userTimeline : Timeline , userTimeline : Timeline Status
, localTimeline : Timeline , localTimeline : Timeline Status
, globalTimeline : Timeline , globalTimeline : Timeline Status
, accountTimeline : Timeline , accountTimeline : Timeline Status
, accountFollowers : List Account , accountFollowers : List Account
, accountFollowing : List Account , accountFollowing : List Account
, accountRelationships : List Relationship , accountRelationships : List Relationship
, accountRelationship : Maybe Relationship , accountRelationship : Maybe Relationship
, notifications : List NotificationAggregate , notifications : Timeline NotificationAggregate
, draft : Draft , draft : Draft
, errors : List String , errors : List String
, location : Navigation.Location , location : Navigation.Location

View File

@ -122,7 +122,7 @@ accountFollowView currentUser accounts relationships relationship account =
List.map keyedEntry accounts List.map keyedEntry accounts
accountTimelineView : CurrentUser -> Timeline -> CurrentUserRelation -> Account -> Html Msg accountTimelineView : CurrentUser -> Timeline Status -> CurrentUserRelation -> Account -> Html Msg
accountTimelineView currentUser timeline relationship account = accountTimelineView currentUser timeline relationship account =
let let
keyedEntry status = keyedEntry status =
@ -131,7 +131,7 @@ accountTimelineView currentUser timeline relationship account =
) )
entries = entries =
List.map keyedEntry timeline.statuses List.map keyedEntry timeline.entries
in in
accountView currentUser account relationship <| accountView currentUser account relationship <|
Keyed.ul [ id timeline.id, class "list-group" ] <| Keyed.ul [ id timeline.id, class "list-group" ] <|

View File

@ -27,14 +27,14 @@ type alias CurrentUserRelation =
Maybe Relationship Maybe Relationship
timelineView : ( String, String, CurrentUser, Timeline ) -> Html Msg timelineView : ( String, String, CurrentUser, Timeline Status ) -> Html Msg
timelineView ( label, iconName, currentUser, timeline ) = timelineView ( label, iconName, currentUser, timeline ) =
let let
keyedEntry status = keyedEntry status =
( toString id, statusEntryView timeline.id "" currentUser status ) ( toString id, statusEntryView timeline.id "" currentUser status )
entries = entries =
List.map keyedEntry timeline.statuses List.map keyedEntry timeline.entries
in in
div [ class "col-md-3 column" ] div [ class "col-md-3 column" ]
[ div [ class "panel panel-default" ] [ div [ class "panel panel-default" ]
@ -47,7 +47,7 @@ timelineView ( label, iconName, currentUser, timeline ) =
] ]
userTimelineView : CurrentUser -> Timeline -> Html Msg userTimelineView : CurrentUser -> Timeline Status -> Html Msg
userTimelineView currentUser timeline = userTimelineView currentUser timeline =
Lazy.lazy timelineView Lazy.lazy timelineView
( "Home timeline" ( "Home timeline"
@ -57,7 +57,7 @@ userTimelineView currentUser timeline =
) )
localTimelineView : CurrentUser -> Timeline -> Html Msg localTimelineView : CurrentUser -> Timeline Status -> Html Msg
localTimelineView currentUser timeline = localTimelineView currentUser timeline =
Lazy.lazy timelineView Lazy.lazy timelineView
( "Local timeline" ( "Local timeline"
@ -67,7 +67,7 @@ localTimelineView currentUser timeline =
) )
globalTimelineView : CurrentUser -> Timeline -> Html Msg globalTimelineView : CurrentUser -> Timeline Status -> Html Msg
globalTimelineView currentUser timeline = globalTimelineView currentUser timeline =
Lazy.lazy timelineView Lazy.lazy timelineView
( "Global timeline" ( "Global timeline"

View File

@ -10,6 +10,7 @@ module View.Common
import Html exposing (..) import Html exposing (..)
import Html.Attributes exposing (..) import Html.Attributes exposing (..)
import Mastodon.Http exposing (Links)
import Mastodon.Model exposing (..) import Mastodon.Model exposing (..)
import Types exposing (..) import Types exposing (..)
import View.Events exposing (..) import View.Events exposing (..)
@ -81,14 +82,14 @@ justifiedButtonGroup cls buttons =
List.map (\b -> div [ class "btn-group" ] [ b ]) buttons List.map (\b -> div [ class "btn-group" ] [ b ]) buttons
loadMoreBtn : Timeline -> Html Msg loadMoreBtn : { timeline | id : String, links : Links } -> Html Msg
loadMoreBtn timeline = loadMoreBtn timeline =
case timeline.links.next of case timeline.links.next of
Just next -> Just next ->
li [ class "list-group-item load-more text-center" ] li [ class "list-group-item load-more text-center" ]
[ a [ a
[ href next [ href next
, onClickWithPreventAndStop <| LoadNext timeline , onClickWithPreventAndStop <| TimelineLoadNext timeline.id next
] ]
[ text "Load more" ] [ text "Load more" ]
] ]

View File

@ -130,13 +130,18 @@ notificationFilterView filter =
] ]
notificationListView : CurrentUser -> NotificationFilter -> List NotificationAggregate -> Html Msg notificationListView : CurrentUser -> NotificationFilter -> Timeline NotificationAggregate -> Html Msg
notificationListView currentUser filter notifications = notificationListView currentUser filter notifications =
let let
keyedEntry notification = keyedEntry notification =
( toString notification.id ( toString notification.id
, Lazy.lazy2 notificationEntryView currentUser notification , Lazy.lazy2 notificationEntryView currentUser notification
) )
entries =
notifications.entries
|> filterNotifications filter
|> List.map keyedEntry
in in
div [ class "col-md-3 column" ] div [ class "col-md-3 column" ]
[ div [ class "panel panel-default notifications-panel" ] [ div [ class "panel panel-default notifications-panel" ]
@ -145,9 +150,6 @@ notificationListView currentUser filter notifications =
[ div [ class "panel-heading" ] [ Common.icon "bell", text "Notifications" ] ] [ div [ class "panel-heading" ] [ Common.icon "bell", text "Notifications" ] ]
, notificationFilterView filter , notificationFilterView filter
, Keyed.ul [ id "notifications", class "list-group timeline" ] <| , Keyed.ul [ id "notifications", class "list-group timeline" ] <|
(notifications (entries ++ [ ( "load-more", Common.loadMoreBtn notifications ) ])
|> filterNotifications filter
|> List.map keyedEntry
)
] ]
] ]