Skip to content

Commit

Permalink
notification grouping + extend poll support
Browse files Browse the repository at this point in the history
  • Loading branch information
easrng committed Sep 6, 2024
1 parent 1ed7076 commit d0124dc
Show file tree
Hide file tree
Showing 34 changed files with 585 additions and 277 deletions.
3 changes: 3 additions & 0 deletions src/intl/en-US.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ export default {
oneDay: '1 day',
threeDays: '3 days',
sevenDays: '7 days',
fourteenDays: '14 days',
thirtyDays: '30 days',
oneYear: '1 year',
never: 'Never',
addEmoji: 'Insert emoji',
addMedia: 'Add media (images, video, audio)',
Expand Down
2 changes: 1 addition & 1 deletion src/routes/_actions/addStatusOrNotification.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { database } from '../_database/database.js'
import { concat } from '../_utils/arrays.js'
import { isEqual, uniqById } from '../_utils/lodash-lite.js'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask.js'
import { timelineItemToSummary } from '../_utils/timelineItemToSummary.js'
import { timelineItemToSummary } from '../_utils/timelineItemToSummary.ts'

function getExistingItemIdsSet (instanceName, timelineName) {
const timelineItemSummaries = store.getForTimeline(instanceName, timelineName, 'timelineItemSummaries') || []
Expand Down
4 changes: 2 additions & 2 deletions src/routes/_actions/createMakeProps.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export function createMakeProps (instanceName, timelineType, timelineValue) {

// The results from IndexedDB or the worker thread can return in random order,
// so we ensure consistent ordering based on the order this function is called in.
return itemId => {
const getStatusOrNotificationPromise = getStatusOrNotification(itemId) // start the promise ASAP
return itemSummary => {
const getStatusOrNotificationPromise = getStatusOrNotification(itemSummary.id) // start the promise ASAP
return new Promise((resolve, reject) => {
promiseChain = promiseChain
.then(() => getStatusOrNotificationPromise)
Expand Down
16 changes: 12 additions & 4 deletions src/routes/_actions/timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { database } from '../_database/database.js'
import { getStatus, getStatusContext } from '../_api/statuses.js'
import { emit } from '../_utils/eventBus.ts'
import { TIMELINE_BATCH_SIZE } from '../_static/timelines.js'
import { timelineItemToSummary } from '../_utils/timelineItemToSummary.js'
import { timelineItemToSummary } from '../_utils/timelineItemToSummary.ts'
import { addStatusesOrNotifications } from './addStatusOrNotification.js'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask.js'
import { sortItemSummariesForThread } from '../_utils/sortItemSummariesForThread.js'
import { sortItemSummariesForThread, sortItemSummariesForNotificationBatch } from '../_utils/sortItemSummaries.ts'
import { rehydrateStatusOrNotification } from './rehydrateStatusOrNotification.js'
import li from 'li'

Expand Down Expand Up @@ -106,11 +106,15 @@ async function addPagedTimelineItems (instanceName, timelineName, items) {
}

export async function addPagedTimelineItemSummaries (instanceName, timelineName, newSummaries) {
const [type, statusId] = timelineName.split('/')
const oldSummaries = store.getForTimeline(instanceName, timelineName, 'timelineItemSummaries')

if (type === 'notifications') {
newSummaries = sortItemSummariesForNotificationBatch(newSummaries)
}

let mergedSummaries = uniqById(concat(oldSummaries || [], newSummaries))

const [type, statusId] = timelineName.split('/')
if (type === 'status') {
mergedSummaries = sortItemSummariesForThread(mergedSummaries, statusId)
}
Expand Down Expand Up @@ -167,12 +171,16 @@ async function addTimelineItems (instanceName, timelineName, items, stale) {
}

export async function addTimelineItemSummaries (instanceName, timelineName, newSummaries, newStale) {
const [type, statusId] = timelineName.split('/')
const oldSummaries = store.getForTimeline(instanceName, timelineName, 'timelineItemSummaries')
const oldStale = store.getForTimeline(instanceName, timelineName, 'timelineItemSummariesAreStale')

if (type === 'notifications') {
newSummaries = sortItemSummariesForNotificationBatch(newSummaries)
}

let mergedSummaries = uniqById(mergeArrays(oldSummaries || [], newSummaries, compareTimelineItemSummaries))

const [type, statusId] = timelineName.split('/')
if (type === 'status') {
mergedSummaries = sortItemSummariesForThread(mergedSummaries, statusId)
}
Expand Down
2 changes: 1 addition & 1 deletion src/routes/_components/HiddenFromSSR.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="hidden-from-ssr" style={style}>
<div class="hidden-from-ssr" {style}>
<slot></slot>
</div>
<script>
Expand Down
4 changes: 2 additions & 2 deletions src/routes/_components/compose/ComposeBox.html
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ <h2 class="sr-only">{'intl.composeStatus'}</h2>
import { slide } from '../../_transitions/slide.js'
import { postStatus, insertHandleForReply, setReplySpoiler, setReplyVisibility } from '../../_actions/compose.js'
import { classname } from '../../_utils/classname.js'
import { POLL_EXPIRY_DEFAULT } from '../../_static/polls.js'
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask.js'
import IconButton from '../IconButton.html'

Expand Down Expand Up @@ -319,6 +318,7 @@ <h2 class="sr-only">{'intl.composeStatus'}</h2>
editId,
localOnly
} = this.get()
const { statusPollExpiryOptions } = this.store.get()
const mediaIds = media.map(_ => _.data.id)
const mediaDescriptions = media.map(_ => _.description)
const mediaFocalPoints = media.map(_ => [_.focusX, _.focusY])
Expand All @@ -338,7 +338,7 @@ <h2 class="sr-only">{'intl.composeStatus'}</h2>

// convert internal poll format to the format Mastodon's REST API uses
const pollToPost = hasPoll && {
expires_in: (poll.expiry || POLL_EXPIRY_DEFAULT).toString(),
expires_in: (poll.expiry || statusPollExpiryOptions[0].value).toString(),
multiple: !!poll.multiple,
options: poll.options
}
Expand Down
18 changes: 11 additions & 7 deletions src/routes/_components/compose/ComposePoll.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{#each poll.options as option, i}
<input id="poll-option-{realm}-{i}"
type="text"
maxlength="50"
maxlength={$maxStatusPollOptionLength}
on:change="onChange(i)"
placeholder="{createLabel(i)}"

Expand All @@ -11,6 +11,7 @@
label="{createRemoveLabel(i)}"
href="#fa-times"
muted={true}
disabled={!canRemoveOption}
on:click="onDeleteClick(i)"
/>
{/each}
Expand All @@ -24,7 +25,7 @@
{'intl.multipleChoice'}
</label>
<Select className="poll-expiry-select"
options={pollExpiryOptions}
options={$statusPollExpiryOptions}
defaultValue={pollExpiryDefaultValue}
on:change="onExpiryChange(event)"
label="{'intl.pollDuration'}"
Expand All @@ -35,7 +36,7 @@
label="Add choice"
href="#fa-plus"
muted={true}
disabled={poll.options.length === 4}
disabled={!canAddOption}
on:click="onAddClick()"
/>
{#each poll.options as option, i}
Expand Down Expand Up @@ -79,7 +80,6 @@
import Select from '../Select.html'
import { store } from '../../_store/store.js'
import { scheduleIdleTask } from '../../_utils/scheduleIdleTask.js'
import { POLL_EXPIRY_DEFAULT, POLL_EXPIRY_OPTIONS } from '../../_static/polls.js'
import { formatIntl } from '../../_utils/formatIntl.js'

function flushPollOptionsToDom (poll, realm) {
Expand All @@ -92,15 +92,19 @@
export default {
oncreate () {
const { realm } = this.get()
const { statusPollExpiryOptions } = this.store.get()
const poll = this.store.getComposeData(realm, 'poll')
flushPollOptionsToDom(poll, realm)
document.getElementById(`poll-option-multiple-${realm}`).checked = !!poll.multiple
this.set({ pollExpiryDefaultValue: poll.expiry || POLL_EXPIRY_DEFAULT })
this.set({ pollExpiryDefaultValue: poll.expiry || statusPollExpiryOptions[0] })
},
data: () => ({
pollExpiryOptions: POLL_EXPIRY_OPTIONS,
pollExpiryDefaultValue: POLL_EXPIRY_DEFAULT
pollExpiryDefaultValue: undefined
}),
computed: {
canAddOption: ({ poll, $maxStatusPollOptions }) => poll.options.length <= $maxStatusPollOptions,
canRemoveOption: ({ poll }) => poll.options.length > 2
},
store: () => store,
helpers: {
createLabel (i) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
width: 100%;
max-width: 100%;
flex: 1;
overflow: hidden;
}
</style>
<script>
Expand Down
17 changes: 10 additions & 7 deletions src/routes/_components/list/List.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<div class="the-list" on:initialized>
{#each safeItems as item, i (item)}
{#each peekItems as item, i (item[1].id)}
<ListLazyItem
{component}
index={i}
{length}
{makeProps}
key={item}
prev={item[0]}
data={item[1]}
next={item[2]}
on:initialized="itemInitialized()"
/>
{/each}
Expand All @@ -21,6 +23,7 @@
import { getScrollContainer } from '../../_utils/scrollContainer.js'
import { observe } from 'svelte-extras'
import { mark, stop } from '../../_utils/marks.js'
import { peek } from '../../_utils/peek.js'

function getScrollTopOffset () {
return document.getElementById('main-nav').getBoundingClientRect().height
Expand All @@ -32,9 +35,9 @@
this.store.setCurrentRealm(realm)

if (process.env.NODE_ENV !== 'production') {
this.observe('safeItems', safeItems => {
if (new Set(safeItems).size !== safeItems.length) {
console.error('list of items is not unique:', safeItems)
this.observe('items', items => {
if (items && new Set(items).size !== items.length) {
console.error('list of items is not unique:', items)
}
})
}
Expand Down Expand Up @@ -75,8 +78,8 @@
initializedCount: 0
}),
computed: {
safeItems: ({ items }) => items || [],
length: ({ safeItems }) => safeItems.length
peekItems: ({ items }) => items ? peek(items) : [],
length: ({ peekItems }) => peekItems.length
},
components: {
ListLazyItem
Expand Down
6 changes: 4 additions & 2 deletions src/routes/_components/list/ListItem.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
}
</style>
<div class="list-item {shown && 'shown'}"
id={`list-item-${key}`} >
id="list-item-{data.id}" >
<svelte:component this={component}
virtualProps={props}
virtualIndex={index}
virtualLength={length}
virtualKey={key}
virtualSummaryPrev={prev}
virtualSummary={data}
virtualSummaryNext={next}
/>
</div>
<script>
Expand Down
8 changes: 5 additions & 3 deletions src/routes/_components/list/ListLazyItem.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
<ListItem
{component}
{props}
{key}
{prev}
{data}
{next}
{index}
{length}
on:initialized
Expand All @@ -14,9 +16,9 @@

export default {
async oncreate () {
const { makeProps, key } = this.get()
const { makeProps, data } = this.get()
if (makeProps) {
const props = await makeProps(key)
const props = await makeProps(data)
mark('ListLazyItem set props')
this.set({ props })
this.fire('initialized')
Expand Down
2 changes: 1 addition & 1 deletion src/routes/_components/settings/SettingsLayout.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<FocusRestoration realm={page}>
<SettingsNav {page} {label} />

<div class="settings" style={style}>
<div class="settings" {style}>
<FreeTextLayout>
<slot></slot>
</FreeTextLayout>
Expand Down
2 changes: 1 addition & 1 deletion src/routes/_components/settings/SettingsNav.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<nav class="settings-nav" style={style}>
<nav class="settings-nav" {style}>
<ul>
{#each navItems as navItem}
<li>
Expand Down
6 changes: 6 additions & 0 deletions src/routes/_components/status/Notification.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{#if status}
<Status {index} {length} {timelineType} {timelineValue} {focusSelector}
{status} {notification} {enableShortcuts} on:recalculateHeight
{prevSummary} {summary} {nextSummary}
/>
{:else}
<article id={elementId}
Expand All @@ -9,6 +10,8 @@
aria-posinset={index + 1}
aria-setsize={length}
aria-label={ariaLabel}
on:load|capture="recalculateHeight()"
on:error|capture="recalculateHeight()"
>
<StatusHeader {notification} {notificationId} {status} {statusId} {timelineType}
{account} {accountId} {uuid} isStatusInNotification="true" />
Expand Down Expand Up @@ -99,6 +102,9 @@
async mentionAuthor () {
const { account } = this.get()
await composeNewStatusMentioning(account)
},
recalculateHeight () {
this.fire('recalculateHeight')
}
}
}
Expand Down
Loading

0 comments on commit d0124dc

Please sign in to comment.