kopia lustrzana https://github.com/nextcloud/social
commit
4d056fe998
|
@ -60,7 +60,7 @@ class Application extends App implements IBootstrap {
|
|||
$context->registerSearchProvider(UnifiedSearchProvider::class);
|
||||
$context->registerWellKnownHandler(WebfingerHandler::class);
|
||||
$context->registerEventListener(BeforeTemplateRenderedEvent::class, ProfileSectionListener::class);
|
||||
// $context->registerDashboardWidget(SocialWidget::class);
|
||||
$context->registerDashboardWidget(SocialWidget::class);
|
||||
}
|
||||
|
||||
public function boot(IBootContext $context): void {
|
||||
|
|
|
@ -169,13 +169,13 @@ export default {
|
|||
},
|
||||
defaultVisibility: {
|
||||
type: String,
|
||||
default: localStorage.getItem('social.lastPostType') || 'followers',
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
statusContent: '',
|
||||
visibility: this.defaultVisibility,
|
||||
visibility: this.defaultVisibility || localStorage.getItem('social.lastPostType') || 'followers',
|
||||
loading: false,
|
||||
/** @type {Object<string, LocalAttachment>} */
|
||||
attachments: {},
|
||||
|
@ -301,14 +301,14 @@ export default {
|
|||
* @param {import('../../types/Mastodon.js').Account} account
|
||||
*/
|
||||
prefillMessageWithMention(account) {
|
||||
if (!this.statusIsEmpty) {
|
||||
if (!this.statusIsEmpty || this.$refs.composerInput === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
this.$refs.composerInput.innerHTML = `
|
||||
<span class="mention" contenteditable="false">
|
||||
<a href="${account.url}" target="_blank">
|
||||
<img src="${!account.acct.includes('@') ? generateUrl(`/avatar/${account.username}/32`) : generateUrl(`apps/social/api/v1/global/actor/avatar?id=${account.acct}`)}"/>
|
||||
<img src="${account.avatar}"/>
|
||||
@${account.acct}
|
||||
</a>
|
||||
</span> `
|
||||
|
@ -413,6 +413,7 @@ export default {
|
|||
this.loading = false
|
||||
this.replyTo = null
|
||||
this.$refs.composerInput.innerText = ''
|
||||
this.updateStatusContent()
|
||||
this.attachments = {}
|
||||
this.$store.dispatch('refreshTimeline')
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
:disable-tooltip="true"
|
||||
:size="128" />
|
||||
<NcAvatar v-else
|
||||
:url="avatarUrl"
|
||||
:url="accountInfo.avatar"
|
||||
:disable-tooltip="true"
|
||||
:size="128" />
|
||||
<h2>{{ displayName }}</h2>
|
||||
|
@ -57,6 +57,9 @@
|
|||
{{ t('social', 'Website') }}: <a :href="website.value">{{ website.value }}<OpenInNew :size="15" /></a>
|
||||
</p>
|
||||
|
||||
<!-- Hack to render note safely -->
|
||||
<MessageContent v-if="accountInfo.note" class="user-profile__note" :item="{content: accountInfo.note, tag: [], mentions: []}" />
|
||||
|
||||
<FollowButton class="user-profile__info" :account="accountInfo.acct" :uid="uid" />
|
||||
<NcButton v-if="serverData.public"
|
||||
class="user-profile__info primary"
|
||||
|
@ -158,6 +161,10 @@ export default {
|
|||
|
||||
}
|
||||
|
||||
&__note {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
&__sections {
|
||||
display: flex;
|
||||
|
||||
|
|
|
@ -43,11 +43,14 @@ export default {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang='scss'>
|
||||
.post-avatar {
|
||||
position: relative;
|
||||
padding: 5px 10px 10px 5px;
|
||||
height: 52px;
|
||||
width: 52px;
|
||||
|
||||
.avatardiv {
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div :class="['timeline-entry', hasHeader ? 'with-header' : '']">
|
||||
<li :class="['timeline-entry', hasHeader ? 'with-header' : '']">
|
||||
<div v-if="isNotification" class="notification">
|
||||
<Bell :size="22" />
|
||||
<span class="notification-action">
|
||||
|
@ -30,15 +30,16 @@
|
|||
:type="type" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Bell from 'vue-material-design-icons/Bell.vue'
|
||||
import { translate } from '@nextcloud/l10n'
|
||||
import TimelinePost from './TimelinePost.vue'
|
||||
import TimelineAvatar from './TimelineAvatar.vue'
|
||||
import UserEntry from './UserEntry.vue'
|
||||
import Bell from 'vue-material-design-icons/Bell.vue'
|
||||
import { translate } from '@nextcloud/l10n'
|
||||
import { notificationSummary } from '../services/notifications.js'
|
||||
|
||||
export default {
|
||||
name: 'TimelineEntry',
|
||||
|
@ -102,30 +103,7 @@ export default {
|
|||
* @return {string}
|
||||
*/
|
||||
actionSummary() {
|
||||
switch (this.notification.type) {
|
||||
case 'mention':
|
||||
return t('social', '{account} mentioned you', { account: this.notification.account.acct })
|
||||
case 'status':
|
||||
return t('social', '{account} posted a status', { account: this.notification.account.acct })
|
||||
case 'reblog':
|
||||
return t('social', '{account} boosted your post', { account: this.notification.account.acct })
|
||||
case 'follow':
|
||||
return t('social', '{account} started to follow you', { account: this.notification.account.acct })
|
||||
case 'follow_request':
|
||||
return t('social', '{account} requested to follow you', { account: this.notification.account.acct })
|
||||
case 'favourite':
|
||||
return t('social', '{account} liked your post', { account: this.notification.account.acct })
|
||||
case 'poll':
|
||||
return t('social', '{account} ended the poll', { account: this.notification.account.acct })
|
||||
case 'update':
|
||||
return t('social', '{account} edited a status', { account: this.notification.account.acct })
|
||||
case 'admin.sign_up':
|
||||
return t('social', '{account} signed up', { account: this.notification.account.acct })
|
||||
case 'admin.report':
|
||||
return t('social', '{account} filed a report', { account: this.notification.account.acct })
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
return notificationSummary(this.notification)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
<template>
|
||||
<div class="social__timeline">
|
||||
<transition-group name="list" tag="div">
|
||||
<transition-group name="list" tag="ul">
|
||||
<TimelineEntry v-for="entry in timeline"
|
||||
:key="entry.id"
|
||||
:item="entry"
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
</span>
|
||||
</template>
|
||||
</NcButton>
|
||||
<NcButton v-if="item.visibility === 'public' || item.visibility === 'followers'"
|
||||
<NcButton v-if="item.visibility === 'public' || item.visibility === 'unlisted'"
|
||||
:title="t('social', 'Boost')"
|
||||
type="tertiary-no-background"
|
||||
@click="boost">
|
||||
|
@ -208,10 +208,10 @@ export default {
|
|||
getSinglePostTimeline(e) {
|
||||
// Display internal or external post
|
||||
if (!this.isLocal) {
|
||||
// TODO - fix
|
||||
if (this.type === 'Note') {
|
||||
window.open(this.item.id)
|
||||
} else if (this.type === 'Announce') {
|
||||
// TODO
|
||||
window.open(this.item.object)
|
||||
} else {
|
||||
logger.warn("Don't know what to do with posts of type " + this.type, { post: this.item })
|
||||
|
@ -269,7 +269,6 @@ export default {
|
|||
padding: 4px 8px;
|
||||
font-size: 15px;
|
||||
line-height: 1.6em;
|
||||
position: relative;
|
||||
border-radius: 8px;
|
||||
|
||||
::v-deep a.widget-default {
|
||||
|
@ -304,7 +303,7 @@ export default {
|
|||
}
|
||||
|
||||
.post-visibility {
|
||||
opacity: 0.5;
|
||||
color: var(--color-text-lighter);
|
||||
background-position: right;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,11 @@ Vue.prototype.OC = window.OC
|
|||
document.addEventListener('DOMContentLoaded', function() {
|
||||
OCA.Dashboard.register('social_notifications', (el, { widget }) => {
|
||||
const View = Vue.extend(Dashboard)
|
||||
/* eslint-disable-next-line no-new */
|
||||
new View({
|
||||
propsData: { title: widget.title },
|
||||
}).$mount(el)
|
||||
el,
|
||||
name: 'SocialDashboard',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -57,7 +57,10 @@ Vue.use(VueMasonry)
|
|||
|
||||
/* eslint-disable-next-line no-new */
|
||||
new Vue({
|
||||
el: '#content',
|
||||
// eslint-disable-next-line vue/match-component-file-name
|
||||
name: 'SocialRoot',
|
||||
router,
|
||||
render: h => h(App),
|
||||
store,
|
||||
}).$mount('#content')
|
||||
})
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import { translate } from '@nextcloud/l10n'
|
||||
|
||||
/**
|
||||
* @param {import("../types/Mastodon").Notification} notification
|
||||
* @return {string}
|
||||
*/
|
||||
export function notificationSummary(notification) {
|
||||
switch (notification.type) {
|
||||
case 'mention':
|
||||
return translate('social', '{account} mentioned you', { account: notification.account.acct })
|
||||
case 'status':
|
||||
return translate('social', '{account} posted a status', { account: notification.account.acct })
|
||||
case 'reblog':
|
||||
return translate('social', '{account} boosted your post', { account: notification.account.acct })
|
||||
case 'follow':
|
||||
return translate('social', '{account} started to follow you', { account: notification.account.acct })
|
||||
case 'follow_request':
|
||||
return translate('social', '{account} requested to follow you', { account: notification.account.acct })
|
||||
case 'favourite':
|
||||
return translate('social', '{account} liked your post', { account: notification.account.acct })
|
||||
case 'poll':
|
||||
return translate('social', '{account} ended the poll', { account: notification.account.acct })
|
||||
case 'update':
|
||||
return translate('social', '{account} edited a status', { account: notification.account.acct })
|
||||
case 'admin.sign_up':
|
||||
return translate('social', '{account} signed up', { account: notification.account.acct })
|
||||
case 'admin.report':
|
||||
return translate('social', '{account} filed a report', { account: notification.account.acct })
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
|
@ -47,6 +47,7 @@ import { generateUrl } from '@nextcloud/router'
|
|||
import { showError } from '@nextcloud/dialogs'
|
||||
import NcDashboardWidget from '@nextcloud/vue/dist/Components/NcDashboardWidget.js'
|
||||
import NcEmptyContent from '@nextcloud/vue/dist/Components/NcEmptyContent.js'
|
||||
import { notificationSummary } from '../services/notifications.js'
|
||||
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
|
@ -121,25 +122,19 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
fetchNotifications() {
|
||||
const req = {
|
||||
params: {
|
||||
limit: 10,
|
||||
},
|
||||
}
|
||||
const url = generateUrl('/apps/social/api/v1/stream/notifications')
|
||||
// TODO check why 'since' param is in fact 'until'
|
||||
/* if (this.lastDate) {
|
||||
req.params.since = this.lastTimestamp,
|
||||
} */
|
||||
axios.get(url, req).then((response) => {
|
||||
if (response.data?.result) {
|
||||
this.processNotifications(response.data.result)
|
||||
async fetchNotifications() {
|
||||
const url = generateUrl('apps/social/api/v1/notifications')
|
||||
|
||||
try {
|
||||
|
||||
const response = await axios.get(url)
|
||||
if (response.data) {
|
||||
this.processNotifications(response.data)
|
||||
this.state = 'ok'
|
||||
} else {
|
||||
this.state = 'error'
|
||||
}
|
||||
}).catch((error) => {
|
||||
} catch (error) {
|
||||
clearInterval(this.loop)
|
||||
if (error.response?.status && error.response.status >= 400) {
|
||||
showError(t('social', 'Failed to get Social notifications'))
|
||||
|
@ -148,8 +143,9 @@ export default {
|
|||
// there was an error in notif processing
|
||||
console.error(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
/** @param {import('../types/Mastodon.js').Notification[]} newNotifications */
|
||||
processNotifications(newNotifications) {
|
||||
if (this.lastTimestamp !== 0) {
|
||||
// just add those which are more recent than our most recent one
|
||||
|
@ -166,55 +162,46 @@ export default {
|
|||
this.notifications = this.filter(newNotifications)
|
||||
}
|
||||
},
|
||||
/** @param {import('../types/Mastodon.js').Notification[]} notifications */
|
||||
filter(notifications) {
|
||||
return notifications
|
||||
// TODO check if we need to filter
|
||||
/* return notifications.filter((n) => {
|
||||
return (n.type === 'something' || n.subtype === 'somethingElse')
|
||||
}) */
|
||||
},
|
||||
/** @param {import('../types/Mastodon.js').Notification} n */
|
||||
getMainText(n) {
|
||||
if (n.subtype === 'Follow') {
|
||||
return t('social', '{account} is following you', { account: this.getActorName(n) })
|
||||
}
|
||||
if (n.subtype === 'Like') {
|
||||
return t('social', '{account} liked your post', { account: this.getActorName(n) })
|
||||
}
|
||||
return notificationSummary(n)
|
||||
},
|
||||
/** @param {import('../types/Mastodon.js').Notification} n */
|
||||
getAvatarUrl(n) {
|
||||
return undefined
|
||||
// TODO get external and internal avatars
|
||||
/* return this.getActorAccountName(n)
|
||||
? generateUrl('???')
|
||||
: undefined */
|
||||
return n.account.avatar
|
||||
},
|
||||
/** @param {import('../types/Mastodon.js').Notification} n */
|
||||
getActorName(n) {
|
||||
return n.actor_info && n.actor_info.type === 'Person' && n.actor_info.preferredUsername
|
||||
? n.actor_info.preferredUsername
|
||||
: ''
|
||||
return n.account.display_name
|
||||
},
|
||||
/** @param {import('../types/Mastodon.js').Notification} n */
|
||||
getActorAccountName(n) {
|
||||
return n.actor_info && n.actor_info.type === 'Person' && n.actor_info.account
|
||||
? n.actor_info.account
|
||||
: ''
|
||||
return n.account.acct
|
||||
},
|
||||
/** @param {import('../types/Mastodon.js').Notification} n */
|
||||
getNotificationTarget(n) {
|
||||
if (n.subtype === 'Follow') {
|
||||
if (n.type === 'follow') {
|
||||
return generateUrl('/apps/social/@' + this.getActorAccountName(n) + '/')
|
||||
}
|
||||
return this.showMoreUrl
|
||||
},
|
||||
/** @param {import('../types/Mastodon.js').Notification} n */
|
||||
getSubline(n) {
|
||||
if (n.subtype === 'Follow') {
|
||||
if (n.type === 'follow') {
|
||||
return this.getActorAccountName(n)
|
||||
}
|
||||
if (n.subtype === 'Like') {
|
||||
if (n.type === 'favourite') {
|
||||
return this.getActorAccountName(n)
|
||||
}
|
||||
return ''
|
||||
},
|
||||
/** @param {import('../types/Mastodon.js').Notification} n */
|
||||
getNotificationTypeImage(n) {
|
||||
if (n.subtype === 'Follow') {
|
||||
if (n.type === 'follow') {
|
||||
return generateUrl('/svg/social/add_user')
|
||||
}
|
||||
return ''
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2>Social</h2>
|
||||
<transition-group name="list" tag="div">
|
||||
<transition-group name="list" tag="ul">
|
||||
<TimelineEntry v-for="entry in timeline"
|
||||
:key="entry.id"
|
||||
:item="entry" />
|
||||
|
@ -42,16 +42,14 @@ export default {
|
|||
beforeMount() {
|
||||
const uid = this.userId
|
||||
|
||||
axios.get(generateUrl(`apps/social/api/v1/account/${uid}/info`)).then((response) => {
|
||||
this.accountInfo = response.data.result.account
|
||||
axios.get(generateUrl(`apps/social/api/v1/global/account/info?account=${uid}`)).then(({ data }) => {
|
||||
this.accountInfo = data
|
||||
logger.log(this.accountInfo)
|
||||
})
|
||||
|
||||
const since = Math.floor(Date.now() / 1000) + 1
|
||||
|
||||
axios.get(generateUrl(`apps/social/api/v1/account/${uid}/stream?limit=25&since=${since}`)).then(({ data }) => {
|
||||
axios.get(generateUrl(`apps/social/api/v1/accounts/${uid}/statuses`)).then(({ data }) => {
|
||||
this.timeline = data
|
||||
logger.log(this.timeline)
|
||||
this.timeline = data.result
|
||||
})
|
||||
},
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue