Compare commits

...

2 Commits

Author SHA1 Message Date
1d3b0febde Refactor some code. 2018-12-23 21:29:48 -08:00
70d6eba427 Add basic notification priority filtering. 2018-12-23 21:17:03 -08:00
4 changed files with 66 additions and 47 deletions

View File

@ -284,7 +284,7 @@ updateSyncResponse model r notify =
notification sr = findFirstBy notification sr = findFirstBy
(\(s, e) -> e.originServerTs) (\(s, e) -> e.originServerTs)
(\(s, e) -> e.sender /= model.loginUsername) (\(s, e) -> e.sender /= model.loginUsername)
<| notificationEvents sr <| joinedRoomNotificationEvents sr
notificationCmd sr = if notify notificationCmd sr = if notify
then Maybe.withDefault Cmd.none then Maybe.withDefault Cmd.none
<| Maybe.map (\(s, e) -> sendNotificationPort <| Maybe.map (\(s, e) -> sendNotificationPort

View File

@ -1,6 +1,7 @@
module Scylla.AccountData exposing (..) module Scylla.AccountData exposing (..)
import Scylla.Sync exposing (AccountData, JoinedRoom, roomAccountData) import Scylla.Sync exposing (SyncResponse, AccountData, JoinedRoom, roomAccountData)
import Json.Decode as Decode import Json.Decode as Decode
import Dict
type NotificationSetting = Normal | MentionsOnly | None type NotificationSetting = Normal | MentionsOnly | None
@ -20,3 +21,10 @@ roomNotificationSetting jr = Maybe.withDefault Normal
<| Maybe.andThen Result.toMaybe <| Maybe.andThen Result.toMaybe
<| Maybe.map (Decode.decodeValue notificationSettingDecoder) <| Maybe.map (Decode.decodeValue notificationSettingDecoder)
<| roomAccountData jr "com.danilafe.scylla.notifications" <| roomAccountData jr "com.danilafe.scylla.notifications"
roomIdNotificationSetting : SyncResponse -> String -> NotificationSetting
roomIdNotificationSetting sr s = Maybe.withDefault Normal
<| Maybe.map roomNotificationSetting
<| Maybe.andThen (Dict.get s)
<| Maybe.andThen .join sr.rooms

View File

@ -1,5 +1,8 @@
port module Scylla.Notification exposing (..) port module Scylla.Notification exposing (..)
import Json.Decode import Scylla.Sync exposing (SyncResponse, RoomEvent, joinedRoomsTimelineEvents)
import Scylla.AccountData exposing (..)
import Json.Decode as Decode exposing (string, field)
import Dict
type alias Notification = type alias Notification =
{ name : String { name : String
@ -9,3 +12,25 @@ type alias Notification =
port sendNotificationPort : Notification -> Cmd msg port sendNotificationPort : Notification -> Cmd msg
port onNotificationClickPort : (String -> msg) -> Sub msg port onNotificationClickPort : (String -> msg) -> Sub msg
producesNotification : NotificationSetting -> RoomEvent -> Bool
producesNotification ns re = case ns of
Normal -> True
_ -> False
notificationText : RoomEvent -> String
notificationText re = case (Decode.decodeValue (field "msgtype" string) re.content) of
Ok "m.text" -> Result.withDefault "" <| (Decode.decodeValue (field "body" string) re.content)
_ -> ""
joinedRoomNotificationEvents : SyncResponse -> List (String, RoomEvent)
joinedRoomNotificationEvents s =
let
applyPair k = List.map (\v -> (k, v))
in
List.sortBy (\(k, v) -> v.originServerTs)
<| Dict.foldl (\k v a -> a ++ applyPair k v) []
<| Dict.map (\k v -> List.filter (producesNotification (roomIdNotificationSetting s k)) v)
<| joinedRoomsTimelineEvents s

View File

@ -1,6 +1,5 @@
module Scylla.Sync exposing (..) module Scylla.Sync exposing (..)
import Scylla.Api exposing (..) import Scylla.Api exposing (..)
import Scylla.Notification exposing (..)
import Scylla.Login exposing (Username) import Scylla.Login exposing (Username)
import Scylla.Route exposing (RoomId) import Scylla.Route exposing (RoomId)
import Dict exposing (Dict) import Dict exposing (Dict)
@ -273,7 +272,7 @@ historyResponseDecoder =
|> required "end" string |> required "end" string
|> required "chunk" (list roomEventDecoder) |> required "chunk" (list roomEventDecoder)
-- Business Logic -- Business Logic: Helper Functions
uniqueByRecursive : (a -> comparable) -> List a -> Set comparable -> List a uniqueByRecursive : (a -> comparable) -> List a -> Set comparable -> List a
uniqueByRecursive f l s = case l of uniqueByRecursive f l s = case l of
x::tail -> if Set.member (f x) s x::tail -> if Set.member (f x) s
@ -433,8 +432,9 @@ senderName s =
in in
String.slice 1 colonIndex s String.slice 1 colonIndex s
roomStateEvents : JoinedRoom -> List StateEvent -- Business Logic: Events
roomStateEvents jr = allRoomStateEvents : JoinedRoom -> List StateEvent
allRoomStateEvents jr =
let let
stateEvents = Maybe.withDefault [] <| Maybe.andThen .events jr.state stateEvents = Maybe.withDefault [] <| Maybe.andThen .events jr.state
timelineEvents = Maybe.withDefault [] <| Maybe.andThen .events jr.timeline timelineEvents = Maybe.withDefault [] <| Maybe.andThen .events jr.timeline
@ -452,6 +452,29 @@ roomStateEvents jr =
in in
allStateEvents allStateEvents
allRoomDictTimelineEvents : Dict String { a | timeline : Maybe Timeline } -> List RoomEvent
allRoomDictTimelineEvents dict = List.concatMap (Maybe.withDefault [] << .events)
<| List.filterMap .timeline
<| Dict.values dict
allTimelineEvents : SyncResponse -> List RoomEvent
allTimelineEvents s =
let
eventsFor f = Maybe.withDefault []
<| Maybe.map allRoomDictTimelineEvents
<| Maybe.andThen f s.rooms
joinedEvents = eventsFor .join
leftEvents = eventsFor .leave
in
uniqueBy .eventId <| leftEvents ++ joinedEvents
joinedRoomsTimelineEvents : SyncResponse -> Dict String (List RoomEvent)
joinedRoomsTimelineEvents s =
Maybe.withDefault Dict.empty
<| Maybe.map (Dict.map (\k v -> Maybe.withDefault [] <| Maybe.andThen .events v.timeline))
<| Maybe.andThen .join s.rooms
-- Business Logic: Room Info
roomAccountData : JoinedRoom -> String -> Maybe Decode.Value roomAccountData : JoinedRoom -> String -> Maybe Decode.Value
roomAccountData jr et = roomAccountData jr et =
Maybe.map .content Maybe.map .content
@ -462,32 +485,10 @@ roomName : JoinedRoom -> Maybe String
roomName jr = roomName jr =
let let
name c = Result.toMaybe <| Decode.decodeValue (field "name" string) c name c = Result.toMaybe <| Decode.decodeValue (field "name" string) c
nameEvent = findLastEvent (((==) "m.room.name") << .type_) <| roomStateEvents jr nameEvent = findLastEvent (((==) "m.room.name") << .type_) <| allRoomStateEvents jr
in in
Maybe.andThen (name << .content) nameEvent Maybe.andThen (name << .content) nameEvent
-- Business Logic: Event Extraction
notificationText : RoomEvent -> String
notificationText re = case (Decode.decodeValue (field "msgtype" string) re.content) of
Ok "m.text" -> Result.withDefault "" <| (Decode.decodeValue (field "body" string) re.content)
_ -> ""
notificationEvents : SyncResponse -> List (String, RoomEvent)
notificationEvents s =
let
applyPair k = List.map (\v -> (k, v))
in
List.sortBy (\(k, v) -> v.originServerTs)
<| Dict.foldl (\k v a -> a ++ applyPair k v) []
<| joinedRoomsEvents s
joinedRoomsEvents : SyncResponse -> Dict String (List RoomEvent)
joinedRoomsEvents s =
Maybe.withDefault Dict.empty
<| Maybe.map (Dict.map (\k v -> Maybe.withDefault [] <| Maybe.andThen .events v.timeline))
<| Maybe.andThen .join s.rooms
-- Business Logic: User Extraction
roomTypingUsers : JoinedRoom -> List Username roomTypingUsers : JoinedRoom -> List Username
roomTypingUsers jr = Maybe.withDefault [] roomTypingUsers jr = Maybe.withDefault []
<| Maybe.andThen (Result.toMaybe << Decode.decodeValue (Decode.field "user_ids" (list string))) <| Maybe.andThen (Result.toMaybe << Decode.decodeValue (Decode.field "user_ids" (list string)))
@ -495,21 +496,6 @@ roomTypingUsers jr = Maybe.withDefault []
<| Maybe.andThen (findLast (((==) "m.typing") << .type_)) <| Maybe.andThen (findLast (((==) "m.typing") << .type_))
<| Maybe.andThen .events jr.ephemeral <| Maybe.andThen .events jr.ephemeral
allRoomDictEvents : Dict String { a | timeline : Maybe Timeline } -> List RoomEvent -- Business Logic: Users
allRoomDictEvents dict = List.concatMap (Maybe.withDefault [] << .events)
<| List.filterMap .timeline
<| Dict.values dict
allEvents : SyncResponse -> List RoomEvent
allEvents s =
let
eventsFor f = Maybe.withDefault []
<| Maybe.map allRoomDictEvents
<| Maybe.andThen f s.rooms
joinedEvents = eventsFor .join
leftEvents = eventsFor .leave
in
uniqueBy .eventId <| leftEvents ++ joinedEvents
allUsers : SyncResponse -> List Username allUsers : SyncResponse -> List Username
allUsers s = uniqueBy (\u -> u) <| List.map .sender <| allEvents s allUsers s = uniqueBy (\u -> u) <| List.map .sender <| allTimelineEvents s