Aggregate notifications. (#37)

This commit is contained in:
Nicolas Perriault 2017-04-23 21:49:04 +02:00 committed by GitHub
parent 3a697f07bb
commit 6b75c90ef6
5 changed files with 114 additions and 28 deletions

View File

@ -9,6 +9,7 @@
"exposed-modules": [], "exposed-modules": [],
"dependencies": { "dependencies": {
"NoRedInk/elm-decode-pipeline": "3.0.0 <= v < 4.0.0", "NoRedInk/elm-decode-pipeline": "3.0.0 <= v < 4.0.0",
"elm-community/list-extra": "6.0.0 <= v < 7.0.0",
"elm-lang/core": "5.1.1 <= v < 6.0.0", "elm-lang/core": "5.1.1 <= v < 6.0.0",
"elm-lang/dom": "1.1.1 <= v < 2.0.0", "elm-lang/dom": "1.1.1 <= v < 2.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0", "elm-lang/html": "2.0.0 <= v < 3.0.0",

View File

@ -17,16 +17,32 @@ body {
color: #999; color: #999;
margin-bottom: 8px; margin-bottom: 8px;
} }
.reblog > p:first-of-type > a,
.notification > p:first-of-type > a { .status-info, .status-info a {
color: #ccc; color: #ccc;
line-height: 1.6em;
}
.status-info > .avatars {
margin-bottom: 8px;
}
.status-info > .avatars img {
width: 24px;
height: 24px;
margin-right: 5px;
border-radius: 2px;
}
.notification.reblog,
.notification.favourite {
opacity: .75;
} }
.notification.follow > p { .notification.follow > p {
margin-bottom: 0; margin-bottom: 0;
} }
.notification .spoiled, .notification .spoiled {
.notification .attachments {
display: none; display: none;
} }

View File

@ -8,6 +8,7 @@ module Mastodon
, Error(..) , Error(..)
, Mention , Mention
, Notification , Notification
, NotificationAggregate
, Reblog(..) , Reblog(..)
, Status , Status
, StatusRequestBody , StatusRequestBody
@ -19,6 +20,7 @@ module Mastodon
, extractReblog , extractReblog
, register , register
, registrationEncoder , registrationEncoder
, aggregateNotifications
, clientEncoder , clientEncoder
, getAuthorizationUrl , getAuthorizationUrl
, getAccessToken , getAccessToken
@ -36,6 +38,7 @@ import HttpBuilder
import Json.Decode.Pipeline as Pipe import Json.Decode.Pipeline as Pipe
import Json.Decode as Decode import Json.Decode as Decode
import Json.Encode as Encode import Json.Encode as Encode
import List.Extra exposing (groupWhile)
-- Types -- Types
@ -148,6 +151,14 @@ type alias Notification =
} }
type alias NotificationAggregate =
{ type_ : String
, status : Maybe Status
, accounts : List Account
, created_at : String
}
type alias Tag = type alias Tag =
{ name : String { name : String
, url : String , url : String
@ -437,6 +448,53 @@ fetch client endpoint decoder =
-- Public API -- Public API
aggregateNotifications : List Notification -> List NotificationAggregate
aggregateNotifications notifications =
let
only type_ notifications =
List.filter (\n -> n.type_ == type_) notifications
sameStatus n1 n2 =
case ( n1.status, n2.status ) of
( Just r1, Just r2 ) ->
r1.id == r2.id
_ ->
False
sameAccount n1 n2 =
n1.account.id == n2.account.id
extractAggregate statusGroup =
let
accounts =
List.map .account statusGroup
in
case statusGroup of
notification :: _ ->
[ NotificationAggregate
notification.type_
notification.status
accounts
notification.created_at
]
[] ->
[]
aggregate statusGroups =
List.map extractAggregate statusGroups |> List.concat
in
[ notifications |> only "reblog" |> groupWhile sameStatus |> aggregate
, notifications |> only "favourite" |> groupWhile sameStatus |> aggregate
, notifications |> only "mention" |> groupWhile sameStatus |> aggregate
, notifications |> only "follow" |> groupWhile sameAccount |> aggregate
]
|> List.concat
|> List.sortBy .created_at
|> List.reverse
clientEncoder : Client -> Encode.Value clientEncoder : Client -> Encode.Value
clientEncoder client = clientEncoder client =
Encode.object Encode.object

View File

@ -58,11 +58,6 @@ type
| UserTimeline (Result Mastodon.Error (List Mastodon.Status)) | UserTimeline (Result Mastodon.Error (List Mastodon.Status))
type Crud
= Add
| Remove
type alias Draft = type alias Draft =
{ status : String { status : String
, in_reply_to : Maybe Mastodon.Status , in_reply_to : Maybe Mastodon.Status
@ -79,7 +74,7 @@ type alias Model =
, userTimeline : List Mastodon.Status , userTimeline : List Mastodon.Status
, localTimeline : List Mastodon.Status , localTimeline : List Mastodon.Status
, publicTimeline : List Mastodon.Status , publicTimeline : List Mastodon.Status
, notifications : List Mastodon.Notification , notifications : List Mastodon.NotificationAggregate
, draft : Draft , draft : Draft
, account : Maybe Mastodon.Account , account : Maybe Mastodon.Account
, errors : List String , errors : List String
@ -499,7 +494,7 @@ update msg model =
Notifications result -> Notifications result ->
case result of case result of
Ok notifications -> Ok notifications ->
{ model | notifications = notifications } ! [] { model | notifications = Mastodon.aggregateNotifications notifications } ! []
Err error -> Err error ->
{ model | notifications = [], errors = (errorText error) :: model.errors } ! [] { model | notifications = [], errors = (errorText error) :: model.errors } ! []

View File

@ -54,6 +54,16 @@ accountLink account =
[ text <| "@" ++ account.username ] [ text <| "@" ++ account.username ]
accountAvatarLink : Mastodon.Account -> Html Msg
accountAvatarLink account =
a
[ href account.url
, ViewHelper.onClickWithPreventAndStop (OnLoadUserAccount account.id)
, title <| "@" ++ account.username
]
[ img [ src account.avatar ] [] ]
attachmentPreview : Maybe Bool -> Mastodon.Attachment -> Html Msg attachmentPreview : Maybe Bool -> Mastodon.Attachment -> Html Msg
attachmentPreview sensitive ({ url, preview_url } as attachment) = attachmentPreview sensitive ({ url, preview_url } as attachment) =
let let
@ -146,10 +156,10 @@ statusView ({ account, content, media_attachments, reblog, mentions } as status)
case reblog of case reblog of
Just (Mastodon.Reblog reblog) -> Just (Mastodon.Reblog reblog) ->
div [ class "reblog" ] div [ class "reblog" ]
[ p [] [ p [ class "status-info" ]
[ icon "fire" [ icon "fire"
, a (accountLinkAttributes ++ [ class "reblogger" ]) , a (accountLinkAttributes ++ [ class "reblogger" ])
[ text <| " " ++ account.username ] [ text <| " @" ++ account.username ]
, text " boosted" , text " boosted"
] ]
, statusView reblog , statusView reblog
@ -297,22 +307,28 @@ timelineView statuses label iconName =
] ]
notificationHeading : Mastodon.Account -> String -> String -> Html Msg notificationHeading : List Mastodon.Account -> String -> String -> Html Msg
notificationHeading account str iconType = notificationHeading accounts str iconType =
p [] <| div [ class "status-info" ]
List.intersperse (text " ") [ div [ class "avatars" ] <| List.map accountAvatarLink accounts
[ icon iconType, accountLink account, text str ] , p [] <|
List.intersperse (text " ")
[ icon iconType
, span [] <| List.intersperse (text ", ") (List.map accountLink accounts)
, text str
]
]
notificationStatusView : Mastodon.Status -> Mastodon.Notification -> Html Msg notificationStatusView : Mastodon.Status -> Mastodon.NotificationAggregate -> Html Msg
notificationStatusView status { type_, account } = notificationStatusView status { type_, accounts } =
div [ class "notification" ] div [ class <| "notification " ++ type_ ]
[ case type_ of [ case type_ of
"reblog" -> "reblog" ->
notificationHeading account "boosted your toot" "fire" notificationHeading accounts "boosted your toot" "fire"
"favourite" -> "favourite" ->
notificationHeading account "favourited your toot" "star" notificationHeading accounts "favourited your toot" "star"
_ -> _ ->
text "" text ""
@ -321,13 +337,13 @@ notificationStatusView status { type_, account } =
] ]
notificationFollowView : Mastodon.Notification -> Html Msg notificationFollowView : Mastodon.NotificationAggregate -> Html Msg
notificationFollowView { account } = notificationFollowView { accounts } =
div [ class "notification follow" ] div [ class "notification follow" ]
[ notificationHeading account "started following you" "user" ] [ notificationHeading accounts "started following you" "user" ]
notificationEntryView : Mastodon.Notification -> Html Msg notificationEntryView : Mastodon.NotificationAggregate -> Html Msg
notificationEntryView notification = notificationEntryView notification =
li [ class "list-group-item" ] li [ class "list-group-item" ]
[ case notification.status of [ case notification.status of
@ -339,7 +355,7 @@ notificationEntryView notification =
] ]
notificationListView : List Mastodon.Notification -> Html Msg notificationListView : List Mastodon.NotificationAggregate -> Html Msg
notificationListView notifications = notificationListView notifications =
div [ class "col-md-3" ] div [ class "col-md-3" ]
[ div [ class "panel panel-default" ] [ div [ class "panel panel-default" ]