Aggregate notifications. (#37)
This commit is contained in:
parent
3a697f07bb
commit
6b75c90ef6
@ -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",
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 } ! []
|
||||||
|
50
src/View.elm
50
src/View.elm
@ -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" ]
|
||||||
|
Loading…
Reference in New Issue
Block a user