2017-04-20 03:46:18 -04:00
|
|
|
module Model exposing (..)
|
|
|
|
|
2017-04-23 04:18:47 -04:00
|
|
|
import Dom
|
2017-04-20 03:46:18 -04:00
|
|
|
import Json.Encode as Encode
|
|
|
|
import Navigation
|
2017-04-27 10:34:27 -04:00
|
|
|
import Mastodon.Decoder
|
|
|
|
import Mastodon.Encoder
|
|
|
|
import Mastodon.Helper
|
|
|
|
import Mastodon.Http
|
|
|
|
import Mastodon.Model
|
|
|
|
import Mastodon.WebSocket
|
2017-04-20 03:46:18 -04:00
|
|
|
import Ports
|
2017-04-23 04:18:47 -04:00
|
|
|
import Task
|
2017-04-20 03:46:18 -04:00
|
|
|
|
|
|
|
|
|
|
|
type alias Flags =
|
2017-04-27 10:34:27 -04:00
|
|
|
{ client : Maybe Mastodon.Model.Client
|
|
|
|
, registration : Maybe Mastodon.Model.AppRegistration
|
2017-04-20 03:46:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-20 14:30:19 -04:00
|
|
|
type DraftMsg
|
2017-04-23 04:18:47 -04:00
|
|
|
= ClearDraft
|
|
|
|
| ClearReplyTo
|
2017-04-20 14:30:19 -04:00
|
|
|
| UpdateSensitive Bool
|
|
|
|
| UpdateSpoiler String
|
|
|
|
| UpdateStatus String
|
2017-04-21 08:03:39 -04:00
|
|
|
| UpdateVisibility String
|
2017-04-27 10:34:27 -04:00
|
|
|
| UpdateReplyTo Mastodon.Model.Status
|
2017-04-23 04:18:47 -04:00
|
|
|
| ToggleSpoiler Bool
|
2017-04-20 14:30:19 -04:00
|
|
|
|
|
|
|
|
2017-04-24 15:21:43 -04:00
|
|
|
type ViewerMsg
|
|
|
|
= CloseViewer
|
2017-04-27 10:34:27 -04:00
|
|
|
| OpenViewer (List Mastodon.Model.Attachment) Mastodon.Model.Attachment
|
2017-04-24 15:21:43 -04:00
|
|
|
|
|
|
|
|
2017-04-25 14:37:44 -04:00
|
|
|
type MastodonMsg
|
2017-04-27 10:34:27 -04:00
|
|
|
= AccessToken (Result Mastodon.Model.Error Mastodon.Model.AccessTokenResult)
|
|
|
|
| AppRegistered (Result Mastodon.Model.Error Mastodon.Model.AppRegistration)
|
2017-04-27 12:39:14 -04:00
|
|
|
| ContextLoaded Mastodon.Model.Status (Result Mastodon.Model.Error Mastodon.Model.Context)
|
2017-04-27 10:34:27 -04:00
|
|
|
| FavoriteAdded (Result Mastodon.Model.Error Mastodon.Model.Status)
|
|
|
|
| FavoriteRemoved (Result Mastodon.Model.Error Mastodon.Model.Status)
|
|
|
|
| LocalTimeline (Result Mastodon.Model.Error (List Mastodon.Model.Status))
|
|
|
|
| Notifications (Result Mastodon.Model.Error (List Mastodon.Model.Notification))
|
|
|
|
| GlobalTimeline (Result Mastodon.Model.Error (List Mastodon.Model.Status))
|
|
|
|
| Reblogged (Result Mastodon.Model.Error Mastodon.Model.Status)
|
|
|
|
| StatusPosted (Result Mastodon.Model.Error Mastodon.Model.Status)
|
|
|
|
| Unreblogged (Result Mastodon.Model.Error Mastodon.Model.Status)
|
|
|
|
| UserAccount (Result Mastodon.Model.Error Mastodon.Model.Account)
|
|
|
|
| UserTimeline (Result Mastodon.Model.Error (List Mastodon.Model.Status))
|
2017-04-25 14:37:44 -04:00
|
|
|
|
|
|
|
|
2017-04-27 02:11:24 -04:00
|
|
|
type WebSocketMsg
|
|
|
|
= NewWebsocketUserMessage String
|
|
|
|
| NewWebsocketGlobalMessage String
|
|
|
|
| NewWebsocketLocalMessage String
|
|
|
|
|
|
|
|
|
|
|
|
type Msg
|
2017-04-25 14:37:44 -04:00
|
|
|
= AddFavorite Int
|
2017-04-27 12:39:14 -04:00
|
|
|
| ClearOpenedAccount
|
|
|
|
| CloseThread
|
2017-04-20 14:30:19 -04:00
|
|
|
| DraftEvent DraftMsg
|
2017-04-27 12:39:14 -04:00
|
|
|
| LoadUserAccount Int
|
2017-04-25 14:37:44 -04:00
|
|
|
| MastodonEvent MastodonMsg
|
2017-04-23 04:18:47 -04:00
|
|
|
| NoOp
|
2017-04-27 12:39:14 -04:00
|
|
|
| OpenThread Mastodon.Model.Status
|
2017-04-23 04:18:47 -04:00
|
|
|
| Reblog Int
|
2017-04-20 03:46:18 -04:00
|
|
|
| Register
|
2017-04-23 04:18:47 -04:00
|
|
|
| RemoveFavorite Int
|
2017-04-20 03:46:18 -04:00
|
|
|
| ServerChange String
|
2017-04-20 14:30:19 -04:00
|
|
|
| SubmitDraft
|
2017-04-20 03:46:18 -04:00
|
|
|
| UrlChange Navigation.Location
|
2017-04-22 10:39:19 -04:00
|
|
|
| UseGlobalTimeline Bool
|
2017-04-23 04:18:47 -04:00
|
|
|
| Unreblog Int
|
2017-04-24 15:21:43 -04:00
|
|
|
| ViewerEvent ViewerMsg
|
2017-04-27 02:11:24 -04:00
|
|
|
| WebSocketEvent WebSocketMsg
|
2017-04-20 03:46:18 -04:00
|
|
|
|
|
|
|
|
2017-04-23 04:18:47 -04:00
|
|
|
type alias Draft =
|
|
|
|
{ status : String
|
2017-04-27 10:34:27 -04:00
|
|
|
, in_reply_to : Maybe Mastodon.Model.Status
|
2017-04-23 04:18:47 -04:00
|
|
|
, spoiler_text : Maybe String
|
|
|
|
, sensitive : Bool
|
|
|
|
, visibility : String
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-27 12:39:14 -04:00
|
|
|
type alias Thread =
|
|
|
|
{ status : Mastodon.Model.Status
|
|
|
|
, context : Mastodon.Model.Context
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-24 15:21:43 -04:00
|
|
|
type alias Viewer =
|
2017-04-27 10:34:27 -04:00
|
|
|
{ attachments : List Mastodon.Model.Attachment
|
|
|
|
, attachment : Mastodon.Model.Attachment
|
2017-04-24 15:21:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-27 12:39:14 -04:00
|
|
|
type CurrentView
|
|
|
|
= -- Basically, what we should be displaying in the fourth column
|
|
|
|
AccountView Mastodon.Model.Account
|
|
|
|
| ThreadView Thread
|
|
|
|
| LocalTimelineView
|
|
|
|
| GlobalTimelineView
|
|
|
|
|
|
|
|
|
2017-04-20 03:46:18 -04:00
|
|
|
type alias Model =
|
|
|
|
{ server : String
|
2017-04-27 10:34:27 -04:00
|
|
|
, registration : Maybe Mastodon.Model.AppRegistration
|
|
|
|
, client : Maybe Mastodon.Model.Client
|
|
|
|
, userTimeline : List Mastodon.Model.Status
|
|
|
|
, localTimeline : List Mastodon.Model.Status
|
|
|
|
, globalTimeline : List Mastodon.Model.Status
|
|
|
|
, notifications : List Mastodon.Model.NotificationAggregate
|
2017-04-23 04:18:47 -04:00
|
|
|
, draft : Draft
|
2017-04-20 03:46:18 -04:00
|
|
|
, errors : List String
|
|
|
|
, location : Navigation.Location
|
2017-04-22 10:39:19 -04:00
|
|
|
, useGlobalTimeline : Bool
|
2017-04-24 15:21:43 -04:00
|
|
|
, viewer : Maybe Viewer
|
2017-04-27 12:39:14 -04:00
|
|
|
, currentView : CurrentView
|
2017-04-20 03:46:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
extractAuthCode : Navigation.Location -> Maybe String
|
|
|
|
extractAuthCode { search } =
|
|
|
|
case (String.split "?code=" search) of
|
|
|
|
[ _, authCode ] ->
|
|
|
|
Just authCode
|
|
|
|
|
|
|
|
_ ->
|
|
|
|
Nothing
|
|
|
|
|
|
|
|
|
2017-04-23 04:18:47 -04:00
|
|
|
defaultDraft : Draft
|
2017-04-20 14:30:19 -04:00
|
|
|
defaultDraft =
|
|
|
|
{ status = ""
|
2017-04-23 04:18:47 -04:00
|
|
|
, in_reply_to = Nothing
|
2017-04-20 14:30:19 -04:00
|
|
|
, spoiler_text = Nothing
|
|
|
|
, sensitive = False
|
|
|
|
, visibility = "public"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-20 03:46:18 -04:00
|
|
|
init : Flags -> Navigation.Location -> ( Model, Cmd Msg )
|
|
|
|
init flags location =
|
|
|
|
let
|
|
|
|
authCode =
|
|
|
|
extractAuthCode location
|
|
|
|
in
|
|
|
|
{ server = ""
|
|
|
|
, registration = flags.registration
|
|
|
|
, client = flags.client
|
|
|
|
, userTimeline = []
|
|
|
|
, localTimeline = []
|
2017-04-25 17:33:37 -04:00
|
|
|
, globalTimeline = []
|
2017-04-22 10:39:19 -04:00
|
|
|
, notifications = []
|
2017-04-20 14:30:19 -04:00
|
|
|
, draft = defaultDraft
|
2017-04-20 03:46:18 -04:00
|
|
|
, errors = []
|
|
|
|
, location = location
|
2017-04-22 10:39:19 -04:00
|
|
|
, useGlobalTimeline = False
|
2017-04-24 15:21:43 -04:00
|
|
|
, viewer = Nothing
|
2017-04-27 12:39:14 -04:00
|
|
|
, currentView = LocalTimelineView
|
2017-04-20 03:46:18 -04:00
|
|
|
}
|
|
|
|
! [ initCommands flags.registration flags.client authCode ]
|
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
initCommands : Maybe Mastodon.Model.AppRegistration -> Maybe Mastodon.Model.Client -> Maybe String -> Cmd Msg
|
2017-04-20 03:46:18 -04:00
|
|
|
initCommands registration client authCode =
|
|
|
|
Cmd.batch <|
|
|
|
|
case authCode of
|
|
|
|
Just authCode ->
|
|
|
|
case registration of
|
|
|
|
Just registration ->
|
2017-04-27 10:34:27 -04:00
|
|
|
[ Mastodon.Http.getAccessToken registration authCode
|
|
|
|
|> Mastodon.Http.send (MastodonEvent << AccessToken)
|
2017-04-25 14:37:44 -04:00
|
|
|
]
|
2017-04-20 03:46:18 -04:00
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
[]
|
|
|
|
|
|
|
|
Nothing ->
|
2017-04-20 14:30:19 -04:00
|
|
|
[ loadTimelines client ]
|
2017-04-20 03:46:18 -04:00
|
|
|
|
|
|
|
|
|
|
|
registerApp : Model -> Cmd Msg
|
|
|
|
registerApp { server, location } =
|
|
|
|
let
|
|
|
|
appUrl =
|
|
|
|
location.origin ++ location.pathname
|
2017-04-25 04:13:00 -04:00
|
|
|
|
|
|
|
cleanServer =
|
|
|
|
if String.endsWith "/" server then
|
|
|
|
String.dropRight 1 server
|
|
|
|
else
|
|
|
|
server
|
2017-04-20 03:46:18 -04:00
|
|
|
in
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.Http.register
|
2017-04-25 04:13:00 -04:00
|
|
|
cleanServer
|
2017-04-20 03:46:18 -04:00
|
|
|
"tooty"
|
|
|
|
appUrl
|
|
|
|
"read write follow"
|
2017-04-24 06:02:23 -04:00
|
|
|
"https://github.com/n1k0/tooty"
|
2017-04-27 10:34:27 -04:00
|
|
|
|> Mastodon.Http.send (MastodonEvent << AppRegistered)
|
2017-04-20 03:46:18 -04:00
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
saveClient : Mastodon.Model.Client -> Cmd Msg
|
2017-04-20 03:46:18 -04:00
|
|
|
saveClient client =
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.Encoder.clientEncoder client
|
2017-04-20 03:46:18 -04:00
|
|
|
|> Encode.encode 0
|
|
|
|
|> Ports.saveClient
|
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
saveRegistration : Mastodon.Model.AppRegistration -> Cmd Msg
|
2017-04-20 03:46:18 -04:00
|
|
|
saveRegistration registration =
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.Encoder.registrationEncoder registration
|
2017-04-20 03:46:18 -04:00
|
|
|
|> Encode.encode 0
|
|
|
|
|> Ports.saveRegistration
|
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
loadNotifications : Maybe Mastodon.Model.Client -> Cmd Msg
|
2017-04-23 04:18:47 -04:00
|
|
|
loadNotifications client =
|
|
|
|
case client of
|
|
|
|
Just client ->
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.Http.fetchNotifications client
|
|
|
|
|> Mastodon.Http.send (MastodonEvent << Notifications)
|
2017-04-23 04:18:47 -04:00
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
Cmd.none
|
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
loadTimelines : Maybe Mastodon.Model.Client -> Cmd Msg
|
2017-04-20 03:46:18 -04:00
|
|
|
loadTimelines client =
|
2017-04-20 14:30:19 -04:00
|
|
|
case client of
|
|
|
|
Just client ->
|
|
|
|
Cmd.batch
|
2017-04-27 10:34:27 -04:00
|
|
|
[ Mastodon.Http.fetchUserTimeline client
|
|
|
|
|> Mastodon.Http.send (MastodonEvent << UserTimeline)
|
|
|
|
, Mastodon.Http.fetchLocalTimeline client
|
|
|
|
|> Mastodon.Http.send (MastodonEvent << LocalTimeline)
|
|
|
|
, Mastodon.Http.fetchGlobalTimeline client
|
|
|
|
|> Mastodon.Http.send (MastodonEvent << GlobalTimeline)
|
2017-04-23 04:18:47 -04:00
|
|
|
, loadNotifications <| Just client
|
2017-04-20 14:30:19 -04:00
|
|
|
]
|
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
Cmd.none
|
|
|
|
|
|
|
|
|
2017-04-27 12:39:14 -04:00
|
|
|
preferredTimeline : Model -> CurrentView
|
|
|
|
preferredTimeline model =
|
|
|
|
if model.useGlobalTimeline then
|
|
|
|
GlobalTimelineView
|
|
|
|
else
|
|
|
|
LocalTimelineView
|
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
postStatus : Mastodon.Model.Client -> Mastodon.Model.StatusRequestBody -> Cmd Msg
|
2017-04-20 14:30:19 -04:00
|
|
|
postStatus client draft =
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.Http.postStatus client draft
|
|
|
|
|> Mastodon.Http.send (MastodonEvent << StatusPosted)
|
2017-04-20 03:46:18 -04:00
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
errorText : Mastodon.Model.Error -> String
|
2017-04-20 03:46:18 -04:00
|
|
|
errorText error =
|
|
|
|
case error of
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.Model.MastodonError statusCode statusMsg errorMsg ->
|
2017-04-20 03:46:18 -04:00
|
|
|
"HTTP " ++ (toString statusCode) ++ " " ++ statusMsg ++ ": " ++ errorMsg
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.Model.ServerError statusCode statusMsg errorMsg ->
|
2017-04-20 03:46:18 -04:00
|
|
|
"HTTP " ++ (toString statusCode) ++ " " ++ statusMsg ++ ": " ++ errorMsg
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.Model.TimeoutError ->
|
2017-04-20 03:46:18 -04:00
|
|
|
"Request timed out."
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.Model.NetworkError ->
|
2017-04-20 03:46:18 -04:00
|
|
|
"Unreachable host."
|
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
toStatusRequestBody : Draft -> Mastodon.Model.StatusRequestBody
|
2017-04-23 04:18:47 -04:00
|
|
|
toStatusRequestBody draft =
|
|
|
|
{ status = draft.status
|
|
|
|
, in_reply_to_id =
|
|
|
|
case draft.in_reply_to of
|
|
|
|
Just status ->
|
|
|
|
Just status.id
|
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
Nothing
|
|
|
|
, spoiler_text = draft.spoiler_text
|
|
|
|
, sensitive = draft.sensitive
|
|
|
|
, visibility = draft.visibility
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
updateTimelinesWithBoolFlag : Int -> Bool -> (Mastodon.Model.Status -> Mastodon.Model.Status) -> Model -> Model
|
2017-04-23 04:18:47 -04:00
|
|
|
updateTimelinesWithBoolFlag statusId flag statusUpdater model =
|
|
|
|
let
|
|
|
|
update flag status =
|
2017-04-27 10:34:27 -04:00
|
|
|
if (Mastodon.Helper.extractReblog status).id == statusId then
|
2017-04-23 04:18:47 -04:00
|
|
|
statusUpdater status
|
|
|
|
else
|
|
|
|
status
|
|
|
|
in
|
|
|
|
{ model
|
|
|
|
| userTimeline = List.map (update flag) model.userTimeline
|
|
|
|
, localTimeline = List.map (update flag) model.localTimeline
|
2017-04-25 17:33:37 -04:00
|
|
|
, globalTimeline = List.map (update flag) model.globalTimeline
|
2017-04-23 04:18:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
processFavourite : Int -> Bool -> Model -> Model
|
|
|
|
processFavourite statusId flag model =
|
|
|
|
updateTimelinesWithBoolFlag statusId flag (\s -> { s | favourited = Just flag }) model
|
|
|
|
|
|
|
|
|
|
|
|
processReblog : Int -> Bool -> Model -> Model
|
|
|
|
processReblog statusId flag model =
|
|
|
|
updateTimelinesWithBoolFlag statusId flag (\s -> { s | reblogged = Just flag }) model
|
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
deleteStatusFromTimeline : Int -> List Mastodon.Model.Status -> List Mastodon.Model.Status
|
2017-04-27 02:11:24 -04:00
|
|
|
deleteStatusFromTimeline statusId timeline =
|
|
|
|
timeline
|
2017-04-27 10:34:27 -04:00
|
|
|
|> List.filter
|
|
|
|
(\s ->
|
|
|
|
s.id
|
|
|
|
/= statusId
|
|
|
|
&& (Mastodon.Helper.extractReblog s).id
|
|
|
|
/= statusId
|
|
|
|
)
|
2017-04-27 02:11:24 -04:00
|
|
|
|
|
|
|
|
2017-04-23 04:18:47 -04:00
|
|
|
updateDraft : DraftMsg -> Draft -> ( Draft, Cmd Msg )
|
2017-04-20 14:30:19 -04:00
|
|
|
updateDraft draftMsg draft =
|
|
|
|
case draftMsg of
|
2017-04-23 04:18:47 -04:00
|
|
|
ClearDraft ->
|
|
|
|
defaultDraft ! []
|
|
|
|
|
2017-04-20 14:30:19 -04:00
|
|
|
ToggleSpoiler enabled ->
|
|
|
|
{ draft
|
|
|
|
| spoiler_text =
|
|
|
|
if enabled then
|
|
|
|
Just ""
|
|
|
|
else
|
|
|
|
Nothing
|
|
|
|
}
|
2017-04-23 04:18:47 -04:00
|
|
|
! []
|
2017-04-20 14:30:19 -04:00
|
|
|
|
|
|
|
UpdateSensitive sensitive ->
|
2017-04-23 04:18:47 -04:00
|
|
|
{ draft | sensitive = sensitive } ! []
|
2017-04-20 14:30:19 -04:00
|
|
|
|
|
|
|
UpdateSpoiler spoiler_text ->
|
2017-04-23 04:18:47 -04:00
|
|
|
{ draft | spoiler_text = Just spoiler_text } ! []
|
2017-04-20 14:30:19 -04:00
|
|
|
|
|
|
|
UpdateStatus status ->
|
2017-04-23 04:18:47 -04:00
|
|
|
{ draft | status = status } ! []
|
2017-04-20 14:30:19 -04:00
|
|
|
|
2017-04-21 08:03:39 -04:00
|
|
|
UpdateVisibility visibility ->
|
2017-04-23 04:18:47 -04:00
|
|
|
{ draft | visibility = visibility } ! []
|
|
|
|
|
|
|
|
UpdateReplyTo status ->
|
|
|
|
let
|
|
|
|
mention =
|
|
|
|
"@" ++ status.account.acct
|
|
|
|
in
|
|
|
|
{ draft
|
|
|
|
| in_reply_to = Just status
|
|
|
|
, status =
|
|
|
|
if String.startsWith mention draft.status then
|
|
|
|
draft.status
|
|
|
|
else
|
|
|
|
mention ++ " " ++ draft.status
|
2017-04-25 12:45:11 -04:00
|
|
|
, sensitive = Maybe.withDefault False status.sensitive
|
|
|
|
, spoiler_text =
|
|
|
|
if status.spoiler_text == "" then
|
|
|
|
Nothing
|
|
|
|
else
|
|
|
|
Just status.spoiler_text
|
|
|
|
, visibility = status.visibility
|
2017-04-23 04:18:47 -04:00
|
|
|
}
|
|
|
|
! [ Dom.focus "status" |> Task.attempt (always NoOp) ]
|
|
|
|
|
|
|
|
ClearReplyTo ->
|
|
|
|
{ draft | in_reply_to = Nothing } ! []
|
2017-04-21 08:03:39 -04:00
|
|
|
|
2017-04-20 14:30:19 -04:00
|
|
|
|
2017-04-24 15:21:43 -04:00
|
|
|
updateViewer : ViewerMsg -> Maybe Viewer -> ( Maybe Viewer, Cmd Msg )
|
|
|
|
updateViewer viewerMsg viewer =
|
|
|
|
case viewerMsg of
|
|
|
|
CloseViewer ->
|
|
|
|
Nothing ! []
|
|
|
|
|
|
|
|
OpenViewer attachments attachment ->
|
|
|
|
(Just <| Viewer attachments attachment) ! []
|
|
|
|
|
|
|
|
|
2017-04-25 14:37:44 -04:00
|
|
|
processMastodonEvent : MastodonMsg -> Model -> ( Model, Cmd Msg )
|
|
|
|
processMastodonEvent msg model =
|
2017-04-20 03:46:18 -04:00
|
|
|
case msg of
|
2017-04-25 14:37:44 -04:00
|
|
|
AccessToken result ->
|
|
|
|
case result of
|
|
|
|
Ok { server, accessToken } ->
|
|
|
|
let
|
|
|
|
client =
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.Model.Client server accessToken
|
2017-04-25 14:37:44 -04:00
|
|
|
in
|
|
|
|
{ model | client = Just client }
|
|
|
|
! [ loadTimelines <| Just client
|
|
|
|
, Navigation.modifyUrl model.location.pathname
|
|
|
|
, saveClient client
|
|
|
|
]
|
2017-04-20 03:46:18 -04:00
|
|
|
|
2017-04-25 14:37:44 -04:00
|
|
|
Err error ->
|
|
|
|
{ model | errors = (errorText error) :: model.errors } ! []
|
2017-04-20 03:46:18 -04:00
|
|
|
|
|
|
|
AppRegistered result ->
|
|
|
|
case result of
|
|
|
|
Ok registration ->
|
|
|
|
{ model | registration = Just registration }
|
|
|
|
! [ saveRegistration registration
|
2017-04-27 10:34:27 -04:00
|
|
|
, Navigation.load <| Mastodon.Http.getAuthorizationUrl registration
|
2017-04-20 03:46:18 -04:00
|
|
|
]
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | errors = (errorText error) :: model.errors } ! []
|
|
|
|
|
2017-04-27 12:39:14 -04:00
|
|
|
ContextLoaded status result ->
|
|
|
|
case result of
|
|
|
|
Ok context ->
|
|
|
|
let
|
|
|
|
thread =
|
|
|
|
Thread status context
|
|
|
|
in
|
|
|
|
{ model | currentView = ThreadView thread } ! []
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model
|
|
|
|
| currentView = preferredTimeline model
|
|
|
|
, errors = (errorText error) :: model.errors
|
|
|
|
}
|
|
|
|
! []
|
|
|
|
|
2017-04-25 14:37:44 -04:00
|
|
|
FavoriteAdded result ->
|
2017-04-20 03:46:18 -04:00
|
|
|
case result of
|
2017-04-25 14:37:44 -04:00
|
|
|
Ok status ->
|
|
|
|
processFavourite status.id True model ! [ loadNotifications model.client ]
|
2017-04-20 03:46:18 -04:00
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | errors = (errorText error) :: model.errors } ! []
|
|
|
|
|
2017-04-25 14:37:44 -04:00
|
|
|
FavoriteRemoved result ->
|
|
|
|
case result of
|
|
|
|
Ok status ->
|
|
|
|
processFavourite status.id False model ! [ loadNotifications model.client ]
|
2017-04-23 04:18:47 -04:00
|
|
|
|
2017-04-25 14:37:44 -04:00
|
|
|
Err error ->
|
|
|
|
{ model | errors = (errorText error) :: model.errors } ! []
|
|
|
|
|
|
|
|
LocalTimeline result ->
|
|
|
|
case result of
|
|
|
|
Ok localTimeline ->
|
|
|
|
{ model | localTimeline = localTimeline } ! []
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | localTimeline = [], errors = (errorText error) :: model.errors } ! []
|
|
|
|
|
|
|
|
Notifications result ->
|
|
|
|
case result of
|
|
|
|
Ok notifications ->
|
2017-04-27 10:34:27 -04:00
|
|
|
{ model | notifications = Mastodon.Helper.aggregateNotifications notifications } ! []
|
2017-04-25 14:37:44 -04:00
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | notifications = [], errors = (errorText error) :: model.errors } ! []
|
|
|
|
|
2017-04-25 17:33:37 -04:00
|
|
|
GlobalTimeline result ->
|
2017-04-25 14:37:44 -04:00
|
|
|
case result of
|
2017-04-25 17:33:37 -04:00
|
|
|
Ok globalTimeline ->
|
|
|
|
{ model | globalTimeline = globalTimeline } ! []
|
2017-04-25 14:37:44 -04:00
|
|
|
|
|
|
|
Err error ->
|
2017-04-25 17:33:37 -04:00
|
|
|
{ model | globalTimeline = [], errors = (errorText error) :: model.errors } ! []
|
2017-04-23 04:18:47 -04:00
|
|
|
|
|
|
|
Reblogged result ->
|
|
|
|
case result of
|
|
|
|
Ok status ->
|
|
|
|
model ! [ loadNotifications model.client ]
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | errors = (errorText error) :: model.errors } ! []
|
|
|
|
|
2017-04-25 14:37:44 -04:00
|
|
|
StatusPosted _ ->
|
2017-04-25 17:33:37 -04:00
|
|
|
{ model | draft = defaultDraft } ! []
|
2017-04-23 04:18:47 -04:00
|
|
|
|
|
|
|
Unreblogged result ->
|
|
|
|
case result of
|
|
|
|
Ok status ->
|
|
|
|
model ! [ loadNotifications model.client ]
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | errors = (errorText error) :: model.errors } ! []
|
|
|
|
|
2017-04-25 14:37:44 -04:00
|
|
|
UserAccount result ->
|
|
|
|
case result of
|
|
|
|
Ok account ->
|
2017-04-27 12:39:14 -04:00
|
|
|
{ model | currentView = AccountView account } ! []
|
2017-04-25 14:37:44 -04:00
|
|
|
|
|
|
|
Err error ->
|
2017-04-27 12:39:14 -04:00
|
|
|
{ model
|
|
|
|
| currentView = preferredTimeline model
|
|
|
|
, errors = (errorText error) :: model.errors
|
|
|
|
}
|
|
|
|
! []
|
2017-04-25 14:37:44 -04:00
|
|
|
|
|
|
|
UserTimeline result ->
|
|
|
|
case result of
|
|
|
|
Ok userTimeline ->
|
|
|
|
{ model | userTimeline = userTimeline } ! []
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | userTimeline = [], errors = (errorText error) :: model.errors } ! []
|
|
|
|
|
|
|
|
|
2017-04-27 02:11:24 -04:00
|
|
|
processWebSocketMsg : WebSocketMsg -> Model -> ( Model, Cmd Msg )
|
|
|
|
processWebSocketMsg msg model =
|
|
|
|
case msg of
|
|
|
|
NewWebsocketUserMessage message ->
|
2017-04-27 10:34:27 -04:00
|
|
|
case (Mastodon.Decoder.decodeWebSocketMessage message) of
|
|
|
|
Mastodon.WebSocket.ErrorEvent error ->
|
2017-04-27 02:11:24 -04:00
|
|
|
{ model | errors = error :: model.errors } ! []
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.WebSocket.StatusUpdateEvent result ->
|
2017-04-27 02:11:24 -04:00
|
|
|
case result of
|
|
|
|
Ok status ->
|
|
|
|
{ model | userTimeline = status :: model.userTimeline } ! []
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | errors = error :: model.errors } ! []
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.WebSocket.StatusDeleteEvent result ->
|
2017-04-27 02:11:24 -04:00
|
|
|
case result of
|
|
|
|
Ok id ->
|
|
|
|
{ model | userTimeline = deleteStatusFromTimeline id model.userTimeline } ! []
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | errors = error :: model.errors } ! []
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.WebSocket.NotificationEvent result ->
|
2017-04-27 02:11:24 -04:00
|
|
|
case result of
|
|
|
|
Ok notification ->
|
|
|
|
let
|
|
|
|
notifications =
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.Helper.addNotificationToAggregates
|
|
|
|
notification
|
|
|
|
model.notifications
|
2017-04-27 02:11:24 -04:00
|
|
|
in
|
|
|
|
{ model | notifications = notifications } ! []
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | errors = error :: model.errors } ! []
|
|
|
|
|
|
|
|
NewWebsocketLocalMessage message ->
|
2017-04-27 10:34:27 -04:00
|
|
|
case (Mastodon.Decoder.decodeWebSocketMessage message) of
|
|
|
|
Mastodon.WebSocket.ErrorEvent error ->
|
2017-04-27 02:11:24 -04:00
|
|
|
{ model | errors = error :: model.errors } ! []
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.WebSocket.StatusUpdateEvent result ->
|
2017-04-27 02:11:24 -04:00
|
|
|
case result of
|
|
|
|
Ok status ->
|
|
|
|
{ model | localTimeline = status :: model.localTimeline } ! []
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | errors = error :: model.errors } ! []
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.WebSocket.StatusDeleteEvent result ->
|
2017-04-27 02:11:24 -04:00
|
|
|
case result of
|
|
|
|
Ok id ->
|
|
|
|
{ model | localTimeline = deleteStatusFromTimeline id model.localTimeline } ! []
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | errors = error :: model.errors } ! []
|
|
|
|
|
|
|
|
_ ->
|
|
|
|
model ! []
|
|
|
|
|
|
|
|
NewWebsocketGlobalMessage message ->
|
2017-04-27 10:34:27 -04:00
|
|
|
case (Mastodon.Decoder.decodeWebSocketMessage message) of
|
|
|
|
Mastodon.WebSocket.ErrorEvent error ->
|
2017-04-27 02:11:24 -04:00
|
|
|
{ model | errors = error :: model.errors } ! []
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.WebSocket.StatusUpdateEvent result ->
|
2017-04-27 02:11:24 -04:00
|
|
|
case result of
|
|
|
|
Ok status ->
|
|
|
|
{ model | globalTimeline = status :: model.globalTimeline } ! []
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | errors = error :: model.errors } ! []
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.WebSocket.StatusDeleteEvent result ->
|
2017-04-27 02:11:24 -04:00
|
|
|
case result of
|
|
|
|
Ok id ->
|
|
|
|
{ model | globalTimeline = deleteStatusFromTimeline id model.globalTimeline } ! []
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
{ model | errors = error :: model.errors } ! []
|
|
|
|
|
|
|
|
_ ->
|
|
|
|
model ! []
|
|
|
|
|
|
|
|
|
2017-04-25 14:37:44 -04:00
|
|
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
|
|
|
update msg model =
|
|
|
|
case msg of
|
|
|
|
NoOp ->
|
|
|
|
model ! []
|
|
|
|
|
|
|
|
MastodonEvent msg ->
|
|
|
|
let
|
|
|
|
( newModel, commands ) =
|
|
|
|
processMastodonEvent msg model
|
|
|
|
in
|
|
|
|
newModel ! [ commands ]
|
|
|
|
|
2017-04-27 02:11:24 -04:00
|
|
|
WebSocketEvent msg ->
|
|
|
|
let
|
|
|
|
( newModel, commands ) =
|
|
|
|
processWebSocketMsg msg model
|
|
|
|
in
|
|
|
|
newModel ! [ commands ]
|
|
|
|
|
2017-04-25 14:37:44 -04:00
|
|
|
ServerChange server ->
|
|
|
|
{ model | server = server } ! []
|
|
|
|
|
|
|
|
UrlChange location ->
|
|
|
|
model ! []
|
|
|
|
|
|
|
|
Register ->
|
|
|
|
model ! [ registerApp model ]
|
|
|
|
|
2017-04-27 12:39:14 -04:00
|
|
|
OpenThread status ->
|
|
|
|
case model.client of
|
|
|
|
Just client ->
|
|
|
|
model
|
|
|
|
! [ Mastodon.Http.context client status.id
|
|
|
|
|> Mastodon.Http.send (MastodonEvent << (ContextLoaded status))
|
|
|
|
]
|
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
model ! []
|
|
|
|
|
|
|
|
CloseThread ->
|
|
|
|
{ model | currentView = preferredTimeline model } ! []
|
|
|
|
|
2017-04-25 14:37:44 -04:00
|
|
|
Reblog id ->
|
|
|
|
-- Note: The case of reblogging is specific as it seems the server
|
|
|
|
-- response takes a lot of time to be received by the client, so we
|
|
|
|
-- perform optimistic updates here.
|
|
|
|
case model.client of
|
|
|
|
Just client ->
|
|
|
|
processReblog id True model
|
2017-04-27 10:34:27 -04:00
|
|
|
! [ Mastodon.Http.reblog client id
|
|
|
|
|> Mastodon.Http.send (MastodonEvent << Reblogged)
|
2017-04-25 14:37:44 -04:00
|
|
|
]
|
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
model ! []
|
|
|
|
|
|
|
|
Unreblog id ->
|
|
|
|
case model.client of
|
|
|
|
Just client ->
|
|
|
|
processReblog id False model
|
2017-04-27 10:34:27 -04:00
|
|
|
! [ Mastodon.Http.unfavourite client id
|
|
|
|
|> Mastodon.Http.send (MastodonEvent << Unreblogged)
|
2017-04-25 14:37:44 -04:00
|
|
|
]
|
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
model ! []
|
|
|
|
|
2017-04-23 04:18:47 -04:00
|
|
|
AddFavorite id ->
|
|
|
|
model
|
|
|
|
! case model.client of
|
|
|
|
Just client ->
|
2017-04-27 10:34:27 -04:00
|
|
|
[ Mastodon.Http.favourite client id
|
|
|
|
|> Mastodon.Http.send (MastodonEvent << FavoriteAdded)
|
2017-04-25 14:37:44 -04:00
|
|
|
]
|
2017-04-23 04:18:47 -04:00
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
[]
|
|
|
|
|
|
|
|
RemoveFavorite id ->
|
|
|
|
model
|
|
|
|
! case model.client of
|
|
|
|
Just client ->
|
2017-04-27 10:34:27 -04:00
|
|
|
[ Mastodon.Http.unfavourite client id
|
|
|
|
|> Mastodon.Http.send (MastodonEvent << FavoriteRemoved)
|
2017-04-25 14:37:44 -04:00
|
|
|
]
|
2017-04-23 04:18:47 -04:00
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
[]
|
|
|
|
|
2017-04-20 14:30:19 -04:00
|
|
|
DraftEvent draftMsg ->
|
2017-04-23 04:18:47 -04:00
|
|
|
let
|
|
|
|
( draft, commands ) =
|
|
|
|
updateDraft draftMsg model.draft
|
|
|
|
in
|
|
|
|
{ model | draft = draft } ! [ commands ]
|
2017-04-20 14:30:19 -04:00
|
|
|
|
2017-04-24 15:21:43 -04:00
|
|
|
ViewerEvent viewerMsg ->
|
|
|
|
let
|
|
|
|
( viewer, commands ) =
|
|
|
|
updateViewer viewerMsg model.viewer
|
|
|
|
in
|
|
|
|
{ model | viewer = viewer } ! [ commands ]
|
|
|
|
|
2017-04-20 14:30:19 -04:00
|
|
|
SubmitDraft ->
|
|
|
|
model
|
|
|
|
! case model.client of
|
|
|
|
Just client ->
|
2017-04-23 04:18:47 -04:00
|
|
|
[ postStatus client <| toStatusRequestBody model.draft ]
|
2017-04-20 14:30:19 -04:00
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
[]
|
|
|
|
|
2017-04-27 12:39:14 -04:00
|
|
|
LoadUserAccount accountId ->
|
2017-04-22 04:16:14 -04:00
|
|
|
{-
|
|
|
|
@TODO
|
|
|
|
When requesting a user profile, we should load a new "page"
|
|
|
|
so that the URL in the browser matches the user displayed
|
|
|
|
-}
|
|
|
|
model
|
|
|
|
! case model.client of
|
|
|
|
Just client ->
|
2017-04-27 10:34:27 -04:00
|
|
|
[ Mastodon.Http.fetchAccount client accountId
|
|
|
|
|> Mastodon.Http.send (MastodonEvent << UserAccount)
|
2017-04-25 14:37:44 -04:00
|
|
|
]
|
2017-04-22 04:16:14 -04:00
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
[]
|
|
|
|
|
2017-04-22 10:39:19 -04:00
|
|
|
UseGlobalTimeline flag ->
|
|
|
|
{ model | useGlobalTimeline = flag } ! []
|
|
|
|
|
2017-04-22 11:03:35 -04:00
|
|
|
ClearOpenedAccount ->
|
2017-04-27 12:39:14 -04:00
|
|
|
{ model | currentView = preferredTimeline model } ! []
|
2017-04-22 11:03:35 -04:00
|
|
|
|
2017-04-25 10:27:15 -04:00
|
|
|
|
|
|
|
subscriptions : Model -> Sub Msg
|
|
|
|
subscriptions model =
|
2017-04-27 02:11:24 -04:00
|
|
|
case model.client of
|
|
|
|
Just client ->
|
|
|
|
let
|
|
|
|
subs =
|
2017-04-27 10:34:27 -04:00
|
|
|
[ Mastodon.WebSocket.subscribeToWebSockets
|
2017-04-27 02:11:24 -04:00
|
|
|
client
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.WebSocket.UserStream
|
2017-04-27 02:11:24 -04:00
|
|
|
NewWebsocketUserMessage
|
|
|
|
]
|
|
|
|
++ (if model.useGlobalTimeline then
|
2017-04-27 10:34:27 -04:00
|
|
|
[ Mastodon.WebSocket.subscribeToWebSockets
|
2017-04-27 02:11:24 -04:00
|
|
|
client
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.WebSocket.GlobalPublicStream
|
2017-04-27 02:11:24 -04:00
|
|
|
NewWebsocketGlobalMessage
|
|
|
|
]
|
|
|
|
else
|
2017-04-27 10:34:27 -04:00
|
|
|
[ Mastodon.WebSocket.subscribeToWebSockets
|
2017-04-27 02:11:24 -04:00
|
|
|
client
|
2017-04-27 10:34:27 -04:00
|
|
|
Mastodon.WebSocket.LocalPublicStream
|
2017-04-27 02:11:24 -04:00
|
|
|
NewWebsocketLocalMessage
|
|
|
|
]
|
|
|
|
)
|
|
|
|
in
|
|
|
|
Sub.batch <| List.map (Sub.map WebSocketEvent) subs
|
2017-04-25 10:27:15 -04:00
|
|
|
|
2017-04-27 02:11:24 -04:00
|
|
|
Nothing ->
|
|
|
|
Sub.batch []
|