forked from cybrespace/pinafore
add ability to fetch and store notifications
This commit is contained in:
parent
43170b9f6f
commit
c8cb4354e3
|
@ -2,55 +2,51 @@ import { store } from '../_store/store'
|
||||||
import { database } from '../_utils/database/database'
|
import { database } from '../_utils/database/database'
|
||||||
import { getTimeline } from '../_utils/mastodon/timelines'
|
import { getTimeline } from '../_utils/mastodon/timelines'
|
||||||
import { toast } from '../_utils/toast'
|
import { toast } from '../_utils/toast'
|
||||||
import { StatusStream } from '../_utils/mastodon/StatusStream'
|
|
||||||
import { getInstanceInfo } from '../_utils/mastodon/instance'
|
|
||||||
import { mark, stop } from '../_utils/marks'
|
import { mark, stop } from '../_utils/marks'
|
||||||
import { mergeArrays } from '../_utils/arrays'
|
import { mergeArrays } from '../_utils/arrays'
|
||||||
|
|
||||||
const FETCH_LIMIT = 20
|
const FETCH_LIMIT = 20
|
||||||
|
|
||||||
let statusStream
|
async function fetchTimelineItems(instanceName, accessToken, timelineName, lastTimelineItemId, online) {
|
||||||
|
mark('fetchTimelineItems')
|
||||||
async function fetchStatuses(instanceName, accessToken, timelineName, lastStatusId, online) {
|
let items
|
||||||
mark('fetchStatuses')
|
|
||||||
let statuses
|
|
||||||
if (!online) {
|
if (!online) {
|
||||||
statuses = await database.getTimeline(instanceName, timelineName, lastStatusId, FETCH_LIMIT)
|
items = await database.getTimeline(instanceName, timelineName, lastTimelineItemId, FETCH_LIMIT)
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
statuses = await getTimeline(instanceName, accessToken, timelineName, lastStatusId, FETCH_LIMIT)
|
items = await getTimeline(instanceName, accessToken, timelineName, lastTimelineItemId, FETCH_LIMIT)
|
||||||
/* no await */ database.insertStatuses(instanceName, timelineName, statuses)
|
/* no await */ database.insertTimelineItems(instanceName, timelineName, items)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
toast.say('Internet request failed. Showing offline content.')
|
toast.say('Internet request failed. Showing offline content.')
|
||||||
statuses = await database.getTimeline(instanceName, timelineName, lastStatusId, FETCH_LIMIT)
|
items = await database.getTimeline(instanceName, timelineName, lastTimelineItemId, FETCH_LIMIT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stop('fetchStatuses')
|
stop('fetchTimelineItems')
|
||||||
return statuses
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addStatuses(instanceName, timelineName, newStatuses) {
|
async function addTimelineItems(instanceName, timelineName, newItems) {
|
||||||
console.log('addStatuses, length:', newStatuses.length)
|
console.log('addTimelineItems, length:', newItems.length)
|
||||||
mark('addStatuses')
|
mark('addTimelineItems')
|
||||||
let newStatusIds = newStatuses.map(status => status.id)
|
let newIds = newItems.map(item => item.id)
|
||||||
let oldStatusIds = store.getForTimeline(instanceName, timelineName, 'statusIds') || []
|
let oldIds = store.getForTimeline(instanceName, timelineName, 'timelineItemIds') || []
|
||||||
let merged = mergeArrays(oldStatusIds, newStatusIds)
|
let merged = mergeArrays(oldIds, newIds)
|
||||||
store.setForTimeline(instanceName, timelineName, { statusIds: merged })
|
store.setForTimeline(instanceName, timelineName, { timelineItemIds: merged })
|
||||||
stop('addStatuses')
|
stop('addTimelineItems')
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchStatusesAndPossiblyFallBack() {
|
async function fetchTimelineItemsAndPossiblyFallBack() {
|
||||||
mark('fetchStatusesAndPossiblyFallBack')
|
mark('fetchTimelineItemsAndPossiblyFallBack')
|
||||||
let timelineName = store.get('currentTimeline')
|
let timelineName = store.get('currentTimeline')
|
||||||
let instanceName = store.get('currentInstance')
|
let instanceName = store.get('currentInstance')
|
||||||
let accessToken = store.get('accessToken')
|
let accessToken = store.get('accessToken')
|
||||||
let lastStatusId = store.get('lastStatusId')
|
let lastTimelineItemId = store.get('lastTimelineItemId')
|
||||||
let online = store.get('online')
|
let online = store.get('online')
|
||||||
|
|
||||||
let newStatuses = await fetchStatuses(instanceName, accessToken, timelineName, lastStatusId, online)
|
let newItems = await fetchTimelineItems(instanceName, accessToken, timelineName, lastTimelineItemId, online)
|
||||||
addStatuses(instanceName, timelineName, newStatuses)
|
addTimelineItems(instanceName, timelineName, newItems)
|
||||||
stop('fetchStatusesAndPossiblyFallBack')
|
stop('fetchTimelineItemsAndPossiblyFallBack')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initializeTimeline() {
|
export function initializeTimeline() {
|
||||||
|
@ -66,30 +62,20 @@ export function initializeTimeline() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setupTimeline() {
|
export async function setupTimeline() {
|
||||||
mark('addStatuses')
|
mark('setupTimeline')
|
||||||
let timelineName = store.get('currentTimeline')
|
let timelineName = store.get('currentTimeline')
|
||||||
let instanceName = store.get('currentInstance')
|
let instanceName = store.get('currentInstance')
|
||||||
let accessToken = store.get('accessToken')
|
let accessToken = store.get('accessToken')
|
||||||
if (!store.get('statusIds').length) {
|
if (!store.get('timelineItemIds').length) {
|
||||||
await fetchStatusesAndPossiblyFallBack()
|
await fetchTimelineItemsAndPossiblyFallBack()
|
||||||
}
|
}
|
||||||
/* no await */ getInstanceInfo(instanceName).then(instanceInfo => database.setInstanceInfo(instanceName, instanceInfo))
|
stop('setupTimeline')
|
||||||
let instanceInfo = await database.getInstanceInfo(instanceName)
|
|
||||||
if (statusStream) {
|
|
||||||
statusStream.close()
|
|
||||||
}
|
|
||||||
/*statusStream = new StatusStream(instanceInfo.urls.streaming_api, accessToken, timelineName, {
|
|
||||||
onMessage(message) {
|
|
||||||
console.log('message', message)
|
|
||||||
}
|
|
||||||
})*/
|
|
||||||
stop('addStatuses')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchStatusesOnScrollToBottom() {
|
export async function fetchTimelineItemsOnScrollToBottom() {
|
||||||
let timelineName = store.get('currentTimeline')
|
let timelineName = store.get('currentTimeline')
|
||||||
let instanceName = store.get('currentInstance')
|
let instanceName = store.get('currentInstance')
|
||||||
store.setForTimeline(instanceName, timelineName, { runningUpdate: true })
|
store.setForTimeline(instanceName, timelineName, { runningUpdate: true })
|
||||||
await fetchStatusesAndPossiblyFallBack()
|
await fetchTimelineItemsAndPossiblyFallBack()
|
||||||
store.setForTimeline(instanceName, timelineName, { runningUpdate: false })
|
store.setForTimeline(instanceName, timelineName, { runningUpdate: false })
|
||||||
}
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<article class="notification-article"
|
||||||
|
tabindex="0"
|
||||||
|
aria-posinset="{{index}}" aria-setsize="{{length}}"
|
||||||
|
on:recalculateHeight
|
||||||
|
>
|
||||||
|
Notification
|
||||||
|
</article>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<Notification
|
||||||
|
notification="{{virtualProps.notification}}"
|
||||||
|
timelineType="{{virtualProps.timelineType}}"
|
||||||
|
timelineValue="{{virtualProps.timelineValue}}"
|
||||||
|
index="{{virtualIndex}}"
|
||||||
|
length="{{virtualLength}}"
|
||||||
|
on:recalculateHeight />
|
||||||
|
<script>
|
||||||
|
import Notification from '../notification/Notification.html'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Notification
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -4,10 +4,21 @@
|
||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if virtual}}
|
{{#if timelineType === 'notifications'}}
|
||||||
|
<VirtualList component="{{NotificationVirtualListItem}}"
|
||||||
|
:makeProps
|
||||||
|
items="{{$timelineItemIds}}"
|
||||||
|
on:scrollToBottom="onScrollToBottom()"
|
||||||
|
shown="{{$initialized}}"
|
||||||
|
footerComponent="{{LoadingFooter}}"
|
||||||
|
showFooter="{{$initialized && $runningUpdate}}"
|
||||||
|
realm="{{$currentInstance + '/' + timeline}}"
|
||||||
|
on:initializedVisibleItems="initialize()"
|
||||||
|
/>
|
||||||
|
{{elseif virtual}}
|
||||||
<VirtualList component="{{StatusVirtualListItem}}"
|
<VirtualList component="{{StatusVirtualListItem}}"
|
||||||
:makeProps
|
:makeProps
|
||||||
items="{{$statusIds}}"
|
items="{{$timelineItemIds}}"
|
||||||
on:scrollToBottom="onScrollToBottom()"
|
on:scrollToBottom="onScrollToBottom()"
|
||||||
shown="{{$initialized}}"
|
shown="{{$initialized}}"
|
||||||
footerComponent="{{LoadingFooter}}"
|
footerComponent="{{LoadingFooter}}"
|
||||||
|
@ -20,7 +31,7 @@
|
||||||
whole thing rather than use a virtual list -->
|
whole thing rather than use a virtual list -->
|
||||||
<PseudoVirtualList component="{{StatusVirtualListItem}}"
|
<PseudoVirtualList component="{{StatusVirtualListItem}}"
|
||||||
:makeProps
|
:makeProps
|
||||||
items="{{$statusIds}}"
|
items="{{$timelineItemIds}}"
|
||||||
shown="{{$initialized}}"
|
shown="{{$initialized}}"
|
||||||
on:initializedVisibleItems="initialize()"
|
on:initializedVisibleItems="initialize()"
|
||||||
scrollToItem="{{timelineValue}}"
|
scrollToItem="{{timelineValue}}"
|
||||||
|
@ -48,13 +59,14 @@
|
||||||
<script>
|
<script>
|
||||||
import { store } from '../../_store/store'
|
import { store } from '../../_store/store'
|
||||||
import StatusVirtualListItem from './StatusVirtualListItem.html'
|
import StatusVirtualListItem from './StatusVirtualListItem.html'
|
||||||
|
import NotificationVirtualListItem from './NotificationVirtualListItem.html'
|
||||||
import Status from '../status/Status.html'
|
import Status from '../status/Status.html'
|
||||||
import PseudoVirtualList from '../pseudoVirtualList/PseudoVirtualList.html'
|
import PseudoVirtualList from '../pseudoVirtualList/PseudoVirtualList.html'
|
||||||
import LoadingFooter from './LoadingFooter.html'
|
import LoadingFooter from './LoadingFooter.html'
|
||||||
import VirtualList from '../virtualList/VirtualList.html'
|
import VirtualList from '../virtualList/VirtualList.html'
|
||||||
import { timelines } from '../../_static/timelines'
|
import { timelines } from '../../_static/timelines'
|
||||||
import { database } from '../../_utils/database/database'
|
import { database } from '../../_utils/database/database'
|
||||||
import { initializeTimeline, fetchStatusesOnScrollToBottom, setupTimeline } from '../../_actions/timeline'
|
import { initializeTimeline, fetchTimelineItemsOnScrollToBottom, setupTimeline } from '../../_actions/timeline'
|
||||||
import LoadingSpinner from '../LoadingSpinner.html'
|
import LoadingSpinner from '../LoadingSpinner.html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -64,15 +76,20 @@
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
StatusVirtualListItem,
|
StatusVirtualListItem,
|
||||||
|
NotificationVirtualListItem,
|
||||||
LoadingFooter,
|
LoadingFooter,
|
||||||
Status
|
Status
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
makeProps: ($currentInstance, timelineType, timelineValue) => async (statusId) => ({
|
makeProps: ($currentInstance, timelineType, timelineValue) => async (itemId) => {
|
||||||
timelineType: timelineType,
|
let res = { timelineType, timelineValue }
|
||||||
timelineValue: timelineValue,
|
if (timelineType === 'notifications') {
|
||||||
status: await database.getStatus($currentInstance, statusId)
|
res.notification = await database.getNotification($currentInstance, itemId)
|
||||||
}),
|
} else {
|
||||||
|
res.status = await database.getStatus($currentInstance, itemId)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
label: (timeline, $currentInstance, timelineType, timelineValue) => {
|
label: (timeline, $currentInstance, timelineType, timelineValue) => {
|
||||||
if (timelines[timeline]) {
|
if (timelines[timeline]) {
|
||||||
return `${timelines[timeline].label} timeline for ${$currentInstance}`
|
return `${timelines[timeline].label} timeline for ${$currentInstance}`
|
||||||
|
@ -101,11 +118,12 @@
|
||||||
components: {
|
components: {
|
||||||
VirtualList,
|
VirtualList,
|
||||||
PseudoVirtualList,
|
PseudoVirtualList,
|
||||||
|
NotificationVirtualListItem,
|
||||||
LoadingSpinner
|
LoadingSpinner
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initialize() {
|
initialize() {
|
||||||
if (this.store.get('initialized') || !this.store.get('statusIds') || !this.store.get('statusIds').length) {
|
if (this.store.get('initialized') || !this.store.get('timelineItemIds') || !this.store.get('timelineItemIds').length) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.log('timeline initialize()')
|
console.log('timeline initialize()')
|
||||||
|
@ -117,7 +135,7 @@
|
||||||
this.get('timelineType') === 'status') { // for status contexts, we've already fetched the whole thread
|
this.get('timelineType') === 'status') { // for status contexts, we've already fetched the whole thread
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fetchStatusesOnScrollToBottom()
|
fetchTimelineItemsOnScrollToBottom()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ export function timelineComputations(store) {
|
||||||
return ((timelines && timelines[currentInstance]) || {})[currentTimeline] || {}
|
return ((timelines && timelines[currentInstance]) || {})[currentTimeline] || {}
|
||||||
})
|
})
|
||||||
|
|
||||||
store.compute('statusIds', ['currentTimelineData'], (currentTimelineData) => currentTimelineData.statusIds || [])
|
store.compute('timelineItemIds', ['currentTimelineData'], (currentTimelineData) => currentTimelineData.timelineItemIds || [])
|
||||||
store.compute('runningUpdate', ['currentTimelineData'], (currentTimelineData) => currentTimelineData.runningUpdate)
|
store.compute('runningUpdate', ['currentTimelineData'], (currentTimelineData) => currentTimelineData.runningUpdate)
|
||||||
store.compute('initialized', ['currentTimelineData'], (currentTimelineData) => currentTimelineData.initialized)
|
store.compute('initialized', ['currentTimelineData'], (currentTimelineData) => currentTimelineData.initialized)
|
||||||
store.compute('lastStatusId', ['statusIds'], (statusIds) => statusIds.length && statusIds[statusIds.length - 1])
|
store.compute('lastTimelineItemId', ['timelineItemIds'], (timelineItemIds) => timelineItemIds.length && timelineItemIds[timelineItemIds.length - 1])
|
||||||
}
|
}
|
|
@ -16,13 +16,18 @@ export const metaCache = {
|
||||||
maxSize: 20,
|
maxSize: 20,
|
||||||
caches: {}
|
caches: {}
|
||||||
}
|
}
|
||||||
|
export const notificationsCache = {
|
||||||
|
maxSize: 50,
|
||||||
|
caches: {}
|
||||||
|
}
|
||||||
|
|
||||||
if (process.browser && process.env.NODE_ENV !== 'production') {
|
if (process.browser && process.env.NODE_ENV !== 'production') {
|
||||||
window.cacheStats = {
|
window.cacheStats = {
|
||||||
statuses: statusesCache,
|
statuses: statusesCache,
|
||||||
accounts: accountsCache,
|
accounts: accountsCache,
|
||||||
relationships: relationshipsCache,
|
relationships: relationshipsCache,
|
||||||
meta: metaCache
|
meta: metaCache,
|
||||||
|
notifications: notificationsCache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
export const STATUSES_STORE = 'statuses'
|
export const STATUSES_STORE = 'statuses'
|
||||||
export const TIMELINE_STORE = 'timelines'
|
export const STATUS_TIMELINES_STORE = 'status_timelines'
|
||||||
export const META_STORE = 'meta'
|
export const META_STORE = 'meta'
|
||||||
export const ACCOUNTS_STORE = 'accounts'
|
export const ACCOUNTS_STORE = 'accounts'
|
||||||
export const RELATIONSHIPS_STORE = 'relationships'
|
export const RELATIONSHIPS_STORE = 'relationships'
|
||||||
|
export const NOTIFICATIONS_STORE = 'notifications'
|
||||||
|
export const NOTIFICATION_TIMELINES_STORE = 'notification_timelines'
|
|
@ -9,10 +9,11 @@ import {
|
||||||
|
|
||||||
import {
|
import {
|
||||||
META_STORE,
|
META_STORE,
|
||||||
TIMELINE_STORE,
|
STATUS_TIMELINES_STORE,
|
||||||
STATUSES_STORE,
|
STATUSES_STORE,
|
||||||
ACCOUNTS_STORE,
|
ACCOUNTS_STORE,
|
||||||
RELATIONSHIPS_STORE
|
RELATIONSHIPS_STORE,
|
||||||
|
NOTIFICATIONS_STORE, NOTIFICATION_TIMELINES_STORE
|
||||||
} from './constants'
|
} from './constants'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -20,6 +21,7 @@ import {
|
||||||
relationshipsCache,
|
relationshipsCache,
|
||||||
accountsCache,
|
accountsCache,
|
||||||
metaCache,
|
metaCache,
|
||||||
|
notificationsCache,
|
||||||
clearCache,
|
clearCache,
|
||||||
getInCache,
|
getInCache,
|
||||||
hasInCache,
|
hasInCache,
|
||||||
|
@ -51,13 +53,29 @@ async function setGenericEntityWithId(store, cache, instanceName, entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// timelines/statuses
|
// timelines/statuses/notifications
|
||||||
//
|
//
|
||||||
|
|
||||||
|
function getTimelineVariables(timeline) {
|
||||||
|
if (timeline === 'notifications') {
|
||||||
|
return {
|
||||||
|
stores: [NOTIFICATION_TIMELINES_STORE, NOTIFICATIONS_STORE, ACCOUNTS_STORE],
|
||||||
|
remoteId: 'notificationId',
|
||||||
|
itemsCache: notificationsCache
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
stores: [STATUS_TIMELINES_STORE, STATUSES_STORE, ACCOUNTS_STORE],
|
||||||
|
remoteId: 'statusId',
|
||||||
|
itemsCache: statusesCache
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function getTimeline(instanceName, timeline, maxId = null, limit = 20) {
|
export async function getTimeline(instanceName, timeline, maxId = null, limit = 20) {
|
||||||
const db = await getDatabase(instanceName, timeline)
|
let { stores, remoteId } = getTimelineVariables(timeline)
|
||||||
return await dbPromise(db, [TIMELINE_STORE, STATUSES_STORE], 'readonly', (stores, callback) => {
|
const db = await getDatabase(instanceName)
|
||||||
let [ timelineStore, statusesStore ] = stores
|
return await dbPromise(db, stores, 'readonly', (stores, callback) => {
|
||||||
|
let [ timelineStore, itemsStore ] = stores
|
||||||
|
|
||||||
let negBigInt = maxId && toReversePaddedBigInt(maxId)
|
let negBigInt = maxId && toReversePaddedBigInt(maxId)
|
||||||
let start = negBigInt ? (timeline + '\u0000' + negBigInt) : (timeline + '\u0000')
|
let start = negBigInt ? (timeline + '\u0000' + negBigInt) : (timeline + '\u0000')
|
||||||
|
@ -68,7 +86,7 @@ export async function getTimeline(instanceName, timeline, maxId = null, limit =
|
||||||
let timelineResults = e.target.result
|
let timelineResults = e.target.result
|
||||||
let res = new Array(timelineResults.length)
|
let res = new Array(timelineResults.length)
|
||||||
timelineResults.forEach((timelineResult, i) => {
|
timelineResults.forEach((timelineResult, i) => {
|
||||||
statusesStore.get(timelineResult.statusId).onsuccess = e => {
|
itemsStore.get(timelineResult[remoteId]).onsuccess = e => {
|
||||||
res[i] = e.target.result
|
res[i] = e.target.result
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -77,27 +95,28 @@ export async function getTimeline(instanceName, timeline, maxId = null, limit =
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function insertStatuses(instanceName, timeline, statuses) {
|
export async function insertTimelineItems(instanceName, timeline, timelineItems) {
|
||||||
for (let status of statuses) {
|
let { stores, remoteId, itemsCache } = getTimelineVariables(timeline)
|
||||||
setInCache(statusesCache, instanceName, status.id, status)
|
for (let timelineItem of timelineItems) {
|
||||||
setInCache(accountsCache, instanceName, status.account.id, status.account)
|
setInCache(itemsCache, instanceName, timelineItem.id, timelineItem)
|
||||||
if (status.reblog) {
|
setInCache(accountsCache, instanceName, timelineItem.account.id, timelineItem.account)
|
||||||
setInCache(accountsCache, instanceName, status.reblog.account.id, status.reblog.account)
|
if (timelineItem.reblog) {
|
||||||
|
setInCache(accountsCache, instanceName, timelineItem.reblog.account.id, timelineItem.reblog.account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const db = await getDatabase(instanceName, timeline)
|
const db = await getDatabase(instanceName)
|
||||||
await dbPromise(db, [TIMELINE_STORE, STATUSES_STORE, ACCOUNTS_STORE], 'readwrite', (stores) => {
|
await dbPromise(db, stores, 'readwrite', (stores) => {
|
||||||
let [ timelineStore, statusesStore, accountsStore ] = stores
|
let [ timelineStore, itemsStore, accountsStore ] = stores
|
||||||
for (let status of statuses) {
|
for (let item of timelineItems) {
|
||||||
statusesStore.put(status)
|
itemsStore.put(item)
|
||||||
// reverse chronological order, prefixed by timeline
|
// reverse chronological order, prefixed by timeline
|
||||||
timelineStore.put({
|
timelineStore.put({
|
||||||
id: (timeline + '\u0000' + toReversePaddedBigInt(status.id)),
|
id: (timeline + '\u0000' + toReversePaddedBigInt(item.id)),
|
||||||
statusId: status.id
|
[remoteId]: item.id
|
||||||
})
|
})
|
||||||
accountsStore.put(status.account)
|
accountsStore.put(item.account)
|
||||||
if (status.reblog) {
|
if (item.reblog) {
|
||||||
accountsStore.put(status.reblog.account)
|
accountsStore.put(item.reblog.account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -107,6 +126,10 @@ export async function getStatus(instanceName, statusId) {
|
||||||
return await getGenericEntityWithId(STATUSES_STORE, statusesCache, instanceName, statusId)
|
return await getGenericEntityWithId(STATUSES_STORE, statusesCache, instanceName, statusId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getNotification(instanceName, notificationId) {
|
||||||
|
return await getGenericEntityWithId(NOTIFICATIONS_STORE, notificationsCache, instanceName, notificationId)
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// meta
|
// meta
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
const openReqs = {}
|
const openReqs = {}
|
||||||
const databaseCache = {}
|
const databaseCache = {}
|
||||||
|
|
||||||
const DB_VERSION = 2
|
const DB_VERSION = 1
|
||||||
|
|
||||||
import {
|
import {
|
||||||
META_STORE,
|
META_STORE,
|
||||||
TIMELINE_STORE,
|
STATUS_TIMELINES_STORE,
|
||||||
STATUSES_STORE,
|
STATUSES_STORE,
|
||||||
ACCOUNTS_STORE,
|
ACCOUNTS_STORE,
|
||||||
RELATIONSHIPS_STORE
|
RELATIONSHIPS_STORE,
|
||||||
|
NOTIFICATIONS_STORE,
|
||||||
|
NOTIFICATION_TIMELINES_STORE
|
||||||
} from './constants'
|
} from './constants'
|
||||||
|
|
||||||
export function getDatabase(instanceName) {
|
export function getDatabase(instanceName) {
|
||||||
|
@ -28,16 +30,15 @@ export function getDatabase(instanceName) {
|
||||||
}
|
}
|
||||||
req.onupgradeneeded = (e) => {
|
req.onupgradeneeded = (e) => {
|
||||||
let db = req.result;
|
let db = req.result;
|
||||||
if (e.oldVersion < 1) {
|
db.createObjectStore(META_STORE, {keyPath: 'key'})
|
||||||
db.createObjectStore(META_STORE, {keyPath: 'key'})
|
db.createObjectStore(STATUSES_STORE, {keyPath: 'id'})
|
||||||
db.createObjectStore(STATUSES_STORE, {keyPath: 'id'})
|
db.createObjectStore(ACCOUNTS_STORE, {keyPath: 'id'})
|
||||||
db.createObjectStore(ACCOUNTS_STORE, {keyPath: 'id'})
|
db.createObjectStore(RELATIONSHIPS_STORE, {keyPath: 'id'})
|
||||||
let timelineStore = db.createObjectStore(TIMELINE_STORE, {keyPath: 'id'})
|
db.createObjectStore(NOTIFICATIONS_STORE, {keyPath: 'id'})
|
||||||
timelineStore.createIndex('statusId', 'statusId')
|
db.createObjectStore(STATUS_TIMELINES_STORE, {keyPath: 'id'})
|
||||||
}
|
.createIndex('statusId', 'statusId')
|
||||||
if (e.oldVersion < 2) {
|
db.createObjectStore(NOTIFICATION_TIMELINES_STORE, {keyPath: 'id'})
|
||||||
db.createObjectStore(RELATIONSHIPS_STORE, {keyPath: 'id'})
|
.createIndex('notificationId', 'notificationId')
|
||||||
}
|
|
||||||
}
|
}
|
||||||
req.onsuccess = () => resolve(req.result)
|
req.onsuccess = () => resolve(req.result)
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,6 +8,8 @@ function getTimelineUrlPath(timeline) {
|
||||||
return 'timelines/public'
|
return 'timelines/public'
|
||||||
case 'home':
|
case 'home':
|
||||||
return 'timelines/home'
|
return 'timelines/home'
|
||||||
|
case 'notifications':
|
||||||
|
return 'notifications'
|
||||||
}
|
}
|
||||||
if (timeline.startsWith('tag/')) {
|
if (timeline.startsWith('tag/')) {
|
||||||
return 'timelines/tag'
|
return 'timelines/tag'
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
<title>Pinafore – Notifications</title>
|
<title>Pinafore – Notifications</title>
|
||||||
</:Head>
|
</:Head>
|
||||||
|
|
||||||
<Layout page='notifications' virtual="true" virtualRealm="federated">
|
<Layout page='notifications' virtual="true" virtualRealm="notifications">
|
||||||
|
{{#if $isUserLoggedIn}}
|
||||||
|
<LazyTimeline timeline='notifications' />
|
||||||
|
{{else}}
|
||||||
<HiddenFromSSR>
|
<HiddenFromSSR>
|
||||||
<FreeTextLayout>
|
<FreeTextLayout>
|
||||||
<h1>Notifications</h1>
|
<h1>Notifications</h1>
|
||||||
|
@ -10,18 +13,23 @@
|
||||||
<p>Your notifications will appear here when logged in.</p>
|
<p>Your notifications will appear here when logged in.</p>
|
||||||
</FreeTextLayout>
|
</FreeTextLayout>
|
||||||
</HiddenFromSSR>
|
</HiddenFromSSR>
|
||||||
|
{{/if}}
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Layout from './_components/Layout.html';
|
import Layout from './_components/Layout.html'
|
||||||
|
import LazyTimeline from './_components/timeline/LazyTimeline.html'
|
||||||
import FreeTextLayout from './_components/FreeTextLayout.html'
|
import FreeTextLayout from './_components/FreeTextLayout.html'
|
||||||
|
import { store } from './_store/store.js'
|
||||||
import HiddenFromSSR from './_components/HiddenFromSSR'
|
import HiddenFromSSR from './_components/HiddenFromSSR'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
store: () => store,
|
||||||
components: {
|
components: {
|
||||||
Layout,
|
Layout,
|
||||||
|
LazyTimeline,
|
||||||
FreeTextLayout,
|
FreeTextLayout,
|
||||||
HiddenFromSSR
|
HiddenFromSSR
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
Loading…
Reference in New Issue