diff --git a/public/style.css b/public/style.css index 2d2c412..f73ab35 100644 --- a/public/style.css +++ b/public/style.css @@ -47,11 +47,19 @@ body { max-height: calc(100vh - 60px); } -.status, .follow-profile { +.status, .follow-profile, .current-user { min-height: 50px; clear: both; } +.current-user { + min-height: 55px; +} + +.current-user .status-text { + font-size: 90%; +} + .follow-profile .status-text { opacity: .8; } @@ -268,6 +276,10 @@ body { /* Draft form */ +.form { + clear: both; +} + .in-reply-to .attachments { margin: 0; } diff --git a/src/Mastodon/ApiUrl.elm b/src/Mastodon/ApiUrl.elm index b495b22..e5879d2 100644 --- a/src/Mastodon/ApiUrl.elm +++ b/src/Mastodon/ApiUrl.elm @@ -3,6 +3,7 @@ module Mastodon.ApiUrl ( apps , oauthAuthorize , oauthToken + , userAccount , account , accountTimeline , homeTimeline @@ -47,6 +48,11 @@ account id = accounts ++ (toString id) +userAccount : Server -> String +userAccount server = + server ++ accounts ++ "verify_credentials" + + homeTimeline : String homeTimeline = "/api/v1/timelines/home" diff --git a/src/Mastodon/Http.elm b/src/Mastodon/Http.elm index c56f76d..cac7813 100644 --- a/src/Mastodon/Http.elm +++ b/src/Mastodon/Http.elm @@ -16,13 +16,13 @@ module Mastodon.Http , fetchGlobalTimeline , fetchUserTimeline , postStatus + , userAccount , send ) import Http import HttpBuilder import Json.Decode as Decode -import Task import Mastodon.ApiUrl as ApiUrl import Mastodon.Decoder exposing (..) import Mastodon.Encoder exposing (..) @@ -133,6 +133,13 @@ fetchNotifications client = fetch client (ApiUrl.notifications) <| Decode.list notificationDecoder +userAccount : Client -> Request Account +userAccount client = + HttpBuilder.get (ApiUrl.userAccount client.server) + |> HttpBuilder.withHeader "Authorization" ("Bearer " ++ client.token) + |> HttpBuilder.withExpect (Http.expectJson accountDecoder) + + postStatus : Client -> StatusRequestBody -> Request Status postStatus client statusRequestBody = HttpBuilder.post (ApiUrl.statuses client.server) diff --git a/src/Model.elm b/src/Model.elm index 18eaf1a..da9fac1 100644 --- a/src/Model.elm +++ b/src/Model.elm @@ -21,7 +21,6 @@ type alias Flags = type DraftMsg = ClearDraft - | ClearReplyTo | UpdateSensitive Bool | UpdateSpoiler String | UpdateStatus String @@ -39,6 +38,7 @@ type MastodonMsg = AccessToken (Result Mastodon.Model.Error Mastodon.Model.AccessTokenResult) | AppRegistered (Result Mastodon.Model.Error Mastodon.Model.AppRegistration) | ContextLoaded Mastodon.Model.Status (Result Mastodon.Model.Error Mastodon.Model.Context) + | CurrentUser (Result Mastodon.Model.Error Mastodon.Model.Account) | 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)) @@ -122,6 +122,7 @@ type alias Model = , location : Navigation.Location , useGlobalTimeline : Bool , viewer : Maybe Viewer + , currentUser : Maybe Mastodon.Model.Account , currentView : CurrentView } @@ -166,6 +167,7 @@ init flags location = , useGlobalTimeline = False , viewer = Nothing , currentView = LocalTimelineView + , currentUser = Nothing } ! [ initCommands flags.registration flags.client authCode ] @@ -185,7 +187,7 @@ initCommands registration client authCode = [] Nothing -> - [ loadTimelines client ] + [ loadUserAccount client, loadTimelines client ] registerApp : Model -> Cmd Msg @@ -234,6 +236,17 @@ loadNotifications client = Cmd.none +loadUserAccount : Maybe Mastodon.Model.Client -> Cmd Msg +loadUserAccount client = + case client of + Just client -> + Mastodon.Http.userAccount client + |> Mastodon.Http.send (MastodonEvent << CurrentUser) + + Nothing -> + Cmd.none + + loadTimelines : Maybe Mastodon.Model.Client -> Cmd Msg loadTimelines client = case client of @@ -260,6 +273,16 @@ preferredTimeline model = LocalTimelineView +accountMentioned : Mastodon.Model.Account -> Mastodon.Model.Mention -> Bool +accountMentioned { acct, username } mention = + acct == mention.acct && username == mention.username + + +sameAccount : Mastodon.Model.Account -> Mastodon.Model.Account -> Bool +sameAccount { acct, username } account = + acct == account.acct && username == account.username + + postStatus : Mastodon.Model.Client -> Mastodon.Model.StatusRequestBody -> Cmd Msg postStatus client draft = Mastodon.Http.postStatus client draft @@ -336,8 +359,8 @@ deleteStatusFromTimeline statusId timeline = ) -updateDraft : DraftMsg -> Draft -> ( Draft, Cmd Msg ) -updateDraft draftMsg draft = +updateDraft : DraftMsg -> Mastodon.Model.Account -> Draft -> ( Draft, Cmd Msg ) +updateDraft draftMsg currentUser draft = case draftMsg of ClearDraft -> defaultDraft ! [] @@ -368,16 +391,19 @@ updateDraft draftMsg draft = let mentions = status.mentions + |> List.filter (\m -> not (accountMentioned currentUser m)) |> List.map (\m -> "@" ++ m.acct) |> String.join " " - prefix = - "@" ++ status.account.acct ++ " " ++ mentions + newStatus = + if sameAccount status.account currentUser then + mentions + else + "@" ++ status.account.acct ++ " " ++ mentions in { draft | in_reply_to = Just status - , status = - prefix ++ " " ++ draft.status + , status = (String.trim newStatus) ++ " " , sensitive = Maybe.withDefault False status.sensitive , spoiler_text = if status.spoiler_text == "" then @@ -388,9 +414,6 @@ updateDraft draftMsg draft = } ! [ Dom.focus "status" |> Task.attempt (always NoOp) ] - ClearReplyTo -> - { draft | in_reply_to = Nothing } ! [] - updateViewer : ViewerMsg -> Maybe Viewer -> ( Maybe Viewer, Cmd Msg ) updateViewer viewerMsg viewer = @@ -448,6 +471,14 @@ processMastodonEvent msg model = } ! [] + CurrentUser result -> + case result of + Ok currentUser -> + { model | currentUser = Just currentUser } ! [] + + Err error -> + { model | errors = (errorText error) :: model.errors } ! [] + FavoriteAdded result -> case result of Ok status -> @@ -714,11 +745,16 @@ update msg model = [] DraftEvent draftMsg -> - let - ( draft, commands ) = - updateDraft draftMsg model.draft - in - { model | draft = draft } ! [ commands ] + case model.currentUser of + Just user -> + let + ( draft, commands ) = + updateDraft draftMsg user model.draft + in + { model | draft = draft } ! [ commands ] + + Nothing -> + model ! [] ViewerEvent viewerMsg -> let diff --git a/src/View.elm b/src/View.elm index dfdacb6..45bb027 100644 --- a/src/View.elm +++ b/src/View.elm @@ -419,7 +419,7 @@ draftReplyToView draft = [ text "In reply to this toot (" , a [ href "" - , onClickWithPreventAndStop <| DraftEvent ClearReplyTo + , onClickWithPreventAndStop <| DraftEvent ClearDraft ] [ icon "remove" ] , text ")" @@ -432,8 +432,22 @@ draftReplyToView draft = text "" +currentUserView : Maybe Mastodon.Model.Account -> Html Msg +currentUserView currentUser = + case currentUser of + Just currentUser -> + div [ class "current-user" ] + [ accountAvatarLink currentUser + , div [ class "username" ] [ accountLink currentUser ] + , p [ class "status-text" ] <| formatContent currentUser.note [] + ] + + Nothing -> + text "" + + draftView : Model -> Html Msg -draftView { draft } = +draftView { draft, currentUser } = let hasSpoiler = draft.spoiler_text /= Nothing @@ -452,7 +466,8 @@ draftView { draft } = "Post a message" ] , div [ class "panel-body" ] - [ draftReplyToView draft + [ currentUserView currentUser + , draftReplyToView draft , Html.form [ class "form", onSubmit SubmitDraft ] [ div [ class "form-group checkbox" ] [ label []