add ability to post statuses

This commit is contained in:
Nolan Lawson 2018-03-04 16:27:15 -08:00
parent 525066e6ea
commit 4220e61042
5 changed files with 108 additions and 4 deletions

View File

@ -1,4 +1,8 @@
import { database } from '../_database/database' import { database } from '../_database/database'
import { store } from '../_store/store'
import { toast } from '../_utils/toast'
import { postStatus as postStatusToServer } from '../_api/statuses'
import { addStatusOrNotification } from './addStatusOrNotification'
export async function getIdThatThisStatusReblogged (instanceName, statusId) { export async function getIdThatThisStatusReblogged (instanceName, statusId) {
let status = await database.getStatus(instanceName, statusId) let status = await database.getStatus(instanceName, statusId)
@ -19,3 +23,27 @@ export async function getIdsThatRebloggedThisStatus (instanceName, statusId) {
export async function getNotificationIdsForStatuses (instanceName, statusIds) { export async function getNotificationIdsForStatuses (instanceName, statusIds) {
return database.getNotificationIdsForStatuses(instanceName, statusIds) return database.getNotificationIdsForStatuses(instanceName, statusIds)
} }
export async function postStatus(realm, text, inReplyToId, mediaIds,
sensitive, spoilerText, visibility) {
let instanceName = store.get('currentInstance')
let accessToken = store.get('accessToken')
let online = store.get('online')
if (!online) {
toast.say('You cannot post while offline')
return
}
store.set({postingStatus: true})
try {
let status = await postStatusToServer(instanceName, accessToken, text,
inReplyToId, mediaIds, sensitive, spoilerText, visibility)
addStatusOrNotification(instanceName, 'home', status)
store.clearComposeData(realm)
} catch (e) {
toast.say('Unable to post status: ' + (e.message || ''))
} finally {
store.set({postingStatus: false})
}
}

25
routes/_api/statuses.js Normal file
View File

@ -0,0 +1,25 @@
import { auth, basename } from './utils'
import { postWithTimeout } from '../_utils/ajax'
export async function postStatus(instanceName, accessToken, text, inReplyToId, mediaIds,
sensitive, spoilerText, visibility) {
let url = `${basename(instanceName)}/api/v1/statuses`
let body = {
status: text,
in_reply_to_id: inReplyToId,
media_ids: mediaIds,
sensitive: sensitive,
spoiler_text: spoilerText,
visibility: visibility
}
for (let key of Object.keys(body)) {
let value = body[key]
if (!value || (Array.isArray(value) && !value.length)) {
delete body[key]
}
}
return postWithTimeout(url, body, auth(accessToken))
}

View File

@ -11,7 +11,7 @@
<ComposeToolbar :realm :postPrivacy :media :contentWarningShown /> <ComposeToolbar :realm :postPrivacy :media :contentWarningShown />
<ComposeLengthIndicator :length :overLimit /> <ComposeLengthIndicator :length :overLimit />
<ComposeMedia :realm :media /> <ComposeMedia :realm :media />
<ComposeButton :length :overLimit /> <ComposeButton :length :overLimit on:click="onClickPostButton()" />
</div> </div>
<style> <style>
.compose-box { .compose-box {
@ -58,6 +58,7 @@
import { CHAR_LIMIT, POST_PRIVACY_OPTIONS } from '../../_static/statuses' import { CHAR_LIMIT, POST_PRIVACY_OPTIONS } from '../../_static/statuses'
import { store } from '../../_store/store' import { store } from '../../_store/store'
import { slide } from 'svelte-transitions' import { slide } from 'svelte-transitions'
import { postStatus } from '../../_actions/statuses'
export default { export default {
components: { components: {
@ -89,6 +90,20 @@
}, },
transitions: { transitions: {
slide slide
},
methods: {
onClickPostButton() {
let text = this.get('text')
let media = this.get('media')
let postPrivacyKey = this.get('postPrivacyKey')
let contentWarning = this.get('contentWarning')
let sensitive = media.length && !!contentWarning
let realm = this.get('realm')
let mediaIds = media.map(_ => _.data.id)
/* no await */ postStatus(realm, text, null, mediaIds,
sensitive, contentWarning, postPrivacyKey)
}
} }
} }
</script> </script>

View File

@ -1,6 +1,15 @@
<button class="primary compose-box-button" <button class="primary compose-box-button"
:disabled > :disabled
Toot! on:click>
<span class="{{$postingStatus ? 'hidden' : ''}}">
Toot!
</span>
<div class="compose-box-button-spinner {{$postingStatus ? 'spin' : 'hidden'}}"
aria-hidden="true">
<svg>
<use xlink:href="#fa-spinner" />
</svg>
</div>
</button> </button>
<style> <style>
.compose-box-button { .compose-box-button {
@ -8,6 +17,24 @@
justify-self: right; justify-self: right;
text-transform: uppercase; text-transform: uppercase;
margin-top: 10px; margin-top: 10px;
position: relative;
}
.compose-box-button-spinner {
pointer-events: none;
position: absolute;
display: flex;
justify-content: center;
align-items: center;
z-index: 10;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.compose-box-button-spinner svg {
width: 24px;
height: 24px;
fill: var(--button-primary-text);
} }
</style> </style>
<script> <script>
@ -16,7 +43,7 @@
export default { export default {
store: () => store, store: () => store,
computed: { computed: {
disabled: (overLimit, length) => overLimit || length === 0 disabled: ($postingStatus, overLimit, length) => $postingStatus || overLimit || length === 0
} }
} }
</script> </script>

View File

@ -14,4 +14,13 @@ export function instanceMixins (Store) {
composeData[instanceName][realm] && composeData[instanceName][realm] &&
composeData[instanceName][realm][key] composeData[instanceName][realm][key]
} }
Store.prototype.clearComposeData = function (realm) {
let composeData = this.get('composeData')
let instanceName = this.get('currentInstance')
if (composeData && composeData[instanceName]) {
delete composeData[instanceName][realm]
}
this.set({composeData})
}
} }