diff --git a/changelog.d/preview_posting.fix b/changelog.d/preview_posting.fix
deleted file mode 100644
index 1a35dbeba..000000000
--- a/changelog.d/preview_posting.fix
+++ /dev/null
@@ -1 +0,0 @@
-Fix posting not working when using preview
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 4fb6f4746..1cea48670 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -720,10 +720,6 @@ const PostStatusForm = {
})
.finally(() => {
this.previewLoading = false
- // If we post right after doing a preview request
- // backend treats non-preview request as preview one
- // and "eats" the post
- this.updateIdempotencyKey()
})
},
debouncePreviewStatus: debounce(function () {
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 43b0f4806..a53812da1 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -152,7 +152,8 @@ const Status = {
},
showReasonMutedThread() {
return (
- (this.mainStatus.thread_muted || this.mainSatus.reblog?.thread_muted) &&
+ (this.mainStatus.thread_muted ||
+ this.smainSatus.reblog?.thread_muted) &&
!this.inConversation
)
},
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
index ed9519e06..3c7e33060 100644
--- a/src/components/timeline/timeline.js
+++ b/src/components/timeline/timeline.js
@@ -31,7 +31,6 @@ const Timeline = {
embedded: Boolean,
inProfile: Boolean,
skipPinned: Boolean,
- hideEmpty: Boolean,
},
data() {
return {
@@ -107,9 +106,7 @@ const Timeline = {
const statusesPerSide = Math.ceil(Math.max(3, window.innerHeight / 80))
const min = Math.max(0, this.virtualScrollIndex - statusesPerSide)
const max = Math.min(amount, this.virtualScrollIndex + statusesPerSide)
- return new Set(
- this.filteredVisibleStatuses.slice(min, max).map(({ id }) => id),
- )
+ return new Set(this.timeline.order.slice(min, max))
},
virtualScrollingEnabled() {
return useMergedConfigStore().mergedConfig.virtualScrolling
diff --git a/src/components/timeline/timeline.scss b/src/components/timeline/timeline.scss
index 984129bf4..2dd66328d 100644
--- a/src/components/timeline/timeline.scss
+++ b/src/components/timeline/timeline.scss
@@ -4,14 +4,6 @@
backdrop-filter: none;
}
- .timeline-placeholder {
- background: var(--background);
- display: flex;
- place-items: center;
- place-content: center;
- padding: 5em;
- }
-
.alert-badge {
font-size: 0.75em;
line-height: 1;
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index d3c3eced2..1435bba48 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -40,7 +40,7 @@
-
-
-
-
-
- {{ $t('timeline.no_statuses') }}
-
-
+ {{ $t('timeline.no_statuses') }}
+
+
{{ $t('timeline.no_more_statuses') }}
+
-
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index 43d91b8e5..9a987cd09 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -30,7 +30,6 @@
:timeline-ref="{ name: 'userPinned', argument: userId }"
embedded
in-profile
- hide-empty
/>
{
const numStatusesBeforeFetch = timeline.statusIds.size
- if (older && bottomedOut.value) return
+ if (bottomedOut.value) return
return fetchTimeline(args)
- .then(({ data, pagination, timestamp }) => {
- // No statuses for timeline, ever.
- if (timeline.order.length === 0 && data.length === 0) {
- bottomedOut.value = true
- }
- if (!older && data.length >= 20 && numStatusesBeforeFetch > 0) {
+ .then(({ data: statuses, pagination, timestamp }) => {
+ if (!older && statuses.length >= 20 && numStatusesBeforeFetch > 0) {
useTimelinesStore().requireReload(timeline.name)
}
- if (older && data.length === 0) {
+ if (older && statuses.length === 0) {
bottomedOut.value = true
}
- const processed = useStatusesStore().addNewStatuses({
- statuses: data,
- timestamp,
- })
-
- const statuses = processed.map(({ id }) => id)
-
- const repeats = processed
- .filter(({ retweeted_status }) => Boolean(retweeted_status))
- .map(({ id, retweeted_status: { id: repeatedId } }) => [
- id,
- repeatedId,
- ])
+ const processed = useStatusesStore()
+ .addNewStatuses({ statuses, timestamp })
+ .map(({ id }) => id)
useTimelinesStore().addStatusesToTimeline(timeline.name, argument, {
- statuses,
- repeats,
+ statuses: processed,
showImmediately,
older,
pagination,
diff --git a/src/stores/timelines.js b/src/stores/timelines.js
index ed4ecfaec..26223e69d 100644
--- a/src/stores/timelines.js
+++ b/src/stores/timelines.js
@@ -21,11 +21,6 @@ const emptyTl = (name, argument = null) => {
// Statuses shown to user
visibleStatusIds: new Set(),
- // Tracked reprööts, used to avoid displaying same reprööt more than once
- repeatedToRepeat: new Map(),
- repeatToRepeated: new Map(),
- ignoredIds: new Set(),
-
// Number of statuses not shown yet
newStatusCount: 0,
@@ -193,7 +188,6 @@ export const useTimelinesStore = defineStore('timelines', {
timeline.order = []
timeline.statusIds = new Set()
timeline.visibleStatusIds = new Set()
- timeline.ignoredIds = new Set()
timeline.newStatusCount = 0
timeline.maxId = ''
timeline.minId = ''
@@ -258,7 +252,6 @@ export const useTimelinesStore = defineStore('timelines', {
argument,
{
statuses,
- repeats = [],
showImmediately = false,
noIdUpdate = false,
pagination = {},
@@ -268,8 +261,6 @@ export const useTimelinesStore = defineStore('timelines', {
if (statuses.length === 0) return
const timeline = this[timelineName]
- this.populateRepeats(timeline, repeats)
-
// This makes sure that user timeline won't get data meant for other
// user. I.e. opening different user profiles makes request which could
// return data late after user already viewing different user profile
@@ -296,18 +287,13 @@ export const useTimelinesStore = defineStore('timelines', {
timeline.statusIds.add(statusId)
if (isNew) {
- const seenBefore = this.checkSeenBefore(timeline, statusId)
- if (!seenBefore) {
- if (showImmediately) {
- // Add it directly to the visibleStatuses, don't change
- // newStatusCount
- timeline.visibleStatusIds.add(statusId)
- } else {
- // Just change newStatuscount
- timeline.newStatusCount += 1
- }
+ if (showImmediately) {
+ // Add it directly to the visibleStatuses, don't change
+ // newStatusCount
+ timeline.visibleStatusIds.add(statusId)
} else {
- timeline.ignoredIds.add(statusId)
+ // Just change newStatuscount
+ timeline.newStatusCount += 1
}
}
})
@@ -315,43 +301,9 @@ export const useTimelinesStore = defineStore('timelines', {
onStreamMessage(timeline, argument, event) {
this.addStatusesToTimeline(timeline, argument, {
statuses: event.data.map(({ id }) => id),
- repeats: event.data
- .filter(({ retweeted_status }) => Boolean(retweeted_status))
- .map(({ id, retweeted_status: { id: repeatedId } }) => [
- id,
- repeatedId,
- ]),
})
},
- // Reprööt handling
- populateRepeats(timeline, repeats) {
- // Starting from oldest
- ;[...repeats].reverse().forEach(([repeatId, repeatedId]) => {
- timeline.repeatToRepeated.set(repeatId, repeatedId)
- const knownRepeats =
- timeline.repeatedToRepeat.get(repeatedId) ?? new Set()
- knownRepeats.add(repeatId)
- timeline.repeatedToRepeat.set(repeatedId, knownRepeats)
- })
- },
- checkSeenBefore(timeline, statusId) {
- // Check if this is a reprööt
- const repeatedStatusId = timeline.repeatToRepeated.get(statusId)
- // Non-reprööts are never seen before
- if (!repeatedStatusId) return false
- // We've seen this status already directly
- if (timeline.statusIds.has(repeatedStatusId)) return true
-
- // Check for reprööts
- const knownRepeats = timeline.repeatedToRepeat.get(repeatedStatusId)
-
- // If it's the only reprööt then we've never seen post before
- if (knownRepeats.size === 1) return false
- // If we're working on oldest known reprööt then we've never seen it before
- return first(knownRepeats) !== statusId
- },
-
// Poll & Push
onStreamConnect(timeline) {
console.debug('[Timelines] Stream connected', timeline)
@@ -439,11 +391,7 @@ export const useTimelinesStore = defineStore('timelines', {
timeline.newStatusCount = 0
timeline.order = timeline.order.slice(0, 50)
timeline.statusIds = new Set([...timeline.order])
-
- // Reprööts CAN be present in order but some must be ignored
- timeline.visibleStatusIds = new Set([
- ...timeline.order.filter((id) => !timeline.ignoredIds.has(id)),
- ])
+ timeline.visibleStatusIds = new Set([...timeline.order])
this.updateTimelineExtremes(timeline)
},
syncOrder(timeline) {
diff --git a/test/unit/specs/stores/timelines.spec.js b/test/unit/specs/stores/timelines.spec.js
index 2b4704052..cfc84ea3d 100644
--- a/test/unit/specs/stores/timelines.spec.js
+++ b/test/unit/specs/stores/timelines.spec.js
@@ -122,7 +122,6 @@ describe('Timelines store', () => {
store.activate('list', '1')
store.addStatusesToTimeline('list', '1', {
statuses,
- repeats: [],
pagination: { minId: '1', maxId: '3' },
})
@@ -141,12 +140,10 @@ describe('Timelines store', () => {
store.activate('list', '1')
store.addStatusesToTimeline('list', '1', {
statuses,
- repeats: [],
pagination: { minId: '1', maxId: '3' },
})
store.addStatusesToTimeline('list', '1', {
statuses,
- repeats: [],
pagination: { minId: '1', maxId: '3' },
})
@@ -165,7 +162,6 @@ describe('Timelines store', () => {
store.activate('list', '1')
store.addStatusesToTimeline('list', '1', {
statuses,
- repeats: [],
showImmediately: true,
pagination: { minId: '1', maxId: '3' },
})
@@ -185,7 +181,6 @@ describe('Timelines store', () => {
store.activate('list', '1')
store.addStatusesToTimeline('list', '1', {
statuses,
- repeats: [],
noIdUpdate: true,
pagination: { minId: '1', maxId: '3' },
})
@@ -205,7 +200,6 @@ describe('Timelines store', () => {
store.activate('list', '1')
store.addStatusesToTimeline('list', '2', {
statuses,
- repeats: [],
noIdUpdate: true,
pagination: { minId: '1', maxId: '3' },
})
@@ -226,12 +220,10 @@ describe('Timelines store', () => {
store.activate('list', '1')
store.addStatusesToTimeline('list', '1', {
statuses: statuses1,
- repeats: [],
pagination: { minId: '3', maxId: '1' },
})
store.addStatusesToTimeline('list', '1', {
statuses: statuses2,
- repeats: [],
pagination: { minId: '6', maxId: '4' },
})
@@ -252,12 +244,10 @@ describe('Timelines store', () => {
store.activate('list', '1')
store.addStatusesToTimeline('list', '1', {
statuses: statuses1,
- repeats: [],
pagination: { minId: '6', maxId: '4' },
})
store.addStatusesToTimeline('list', '1', {
statuses: statuses2,
- repeats: [],
pagination: { minId: '3', maxId: '1' },
older: true,
})
@@ -270,157 +260,6 @@ describe('Timelines store', () => {
expect(store.list).to.have.property('maxId', '6')
expect(store.list).to.have.property('minId', '1')
})
-
- describe('repeat de-duplication', () => {
- it('handles repeat de-duplication (older)', () => {
- const store = useTimelinesStore()
- const statuses1 = ['s7s3', 's6s3', 's5', 's4s0', 's3', 's2']
- const statuses2 = ['s1s0', 's0']
-
- store.activate('list', '1')
- store.addStatusesToTimeline('list', '1', {
- statuses: statuses1,
- repeats: [
- ['s7s3', 's2'],
- ['s6s3', 's2'],
- ['s4s0', 's0'],
- ],
- pagination: { minId: 's7s3', maxId: 's2' },
- showImmediately: true,
- })
- expect(store.list.order).to.eql(statuses1)
- expect(store.list.statusIds).to.eql(new Set(statuses1))
- expect(store.list.visibleStatusIds).to.eql(
- new Set(['s5', 's4s0', 's3', 's2']),
- )
- expect(store.list).to.have.property('maxId', 's7s3')
- expect(store.list).to.have.property('minId', 's2')
-
- store.addStatusesToTimeline('list', '1', {
- statuses: statuses2,
- repeats: [['s1s0', 's0']],
- pagination: { minId: 's1', maxId: 's0' },
- showImmediately: true,
- older: true,
- })
-
- const newOrder = [...statuses1, ...statuses2]
- expect(store.list.order).to.eql(newOrder)
- expect(store.list.statusIds).to.eql(new Set(newOrder))
- expect(store.list.visibleStatusIds).to.eql(
- new Set(['s5', 's4s0', 's3', 's2', 's0']),
- )
- expect(store.list).to.have.property('maxId', 's7s3')
- expect(store.list).to.have.property('minId', 's0')
- })
-
- it('handles repeat de-duplication(reverse)', () => {
- const store = useTimelinesStore()
- const statuses1 = ['s6s2', 's5s2', 's4', 's3s0', 's2', 's1']
- const statuses2 = ['sAs0', 's9s1', 's8', 's7s2']
-
- store.activate('list', '1')
- store.addStatusesToTimeline('list', '1', {
- statuses: statuses1,
- repeats: [
- ['s6s2', 's2'],
- ['s5s2', 's2'],
- ['s3s0', 's0'],
- ],
- pagination: { minId: 's6s2', maxId: 's1' },
- showImmediately: true,
- })
- expect(store.list.order).to.eql(statuses1)
- expect(store.list.statusIds).to.eql(new Set(statuses1))
- expect(store.list.visibleStatusIds).to.eql(
- new Set(['s4', 's3s0', 's2', 's1']),
- )
- expect(store.list).to.have.property('maxId', 's6s2')
- expect(store.list).to.have.property('minId', 's1')
-
- store.addStatusesToTimeline('list', '1', {
- statuses: statuses2,
- repeats: [
- ['sAs0', 's0'],
- ['s9s1', 's1'],
- ['s7s2', 's2'],
- ],
- pagination: { minId: 'sAs0', maxId: 's7s2' },
- showImmediately: true,
- })
-
- const newOrder = [...statuses2, ...statuses1]
- expect(store.list.order).to.eql(newOrder)
- expect(store.list.statusIds).to.eql(new Set(newOrder))
- expect(store.list.visibleStatusIds).to.eql(
- new Set([
- 's4',
- 's3s0',
- 's2',
- 's1',
- // Newer
- 's8',
- ]),
- )
- expect(store.list).to.have.property('maxId', 'sAs0')
- expect(store.list).to.have.property('minId', 's1')
- })
-
- it('showNewStatuses follows de-duplication rules', () => {
- const store = useTimelinesStore()
- const statuses1 = ['s6s2', 's5s2', 's4', 's3s0', 's2', 's1']
- const statuses2 = ['sAs0', 's9s1', 's8', 's7s2']
-
- store.activate('list', '1')
- store.addStatusesToTimeline('list', '1', {
- statuses: statuses1,
- repeats: [
- ['s6s2', 's2'],
- ['s5s2', 's2'],
- ['s3s0', 's0'],
- ],
- pagination: { minId: 's6s2', maxId: 's1' },
- showImmediately: true,
- })
- expect(store.list.order).to.eql(statuses1)
- expect(store.list.statusIds).to.eql(new Set(statuses1))
- expect(store.list.visibleStatusIds).to.eql(
- new Set(['s4', 's3s0', 's2', 's1']),
- )
- expect(store.list).to.have.property('maxId', 's6s2')
- expect(store.list).to.have.property('minId', 's1')
-
- store.addStatusesToTimeline('list', '1', {
- statuses: statuses2,
- repeats: [
- ['sAs0', 's0'],
- ['s9s1', 's1'],
- ['s7s2', 's2'],
- ],
- pagination: { minId: 'sAs0', maxId: 's7s2' },
- })
-
- const newOrder = [...statuses2, ...statuses1]
- expect(store.list.order).to.eql(newOrder)
- expect(store.list.statusIds).to.eql(new Set(newOrder))
- expect(store.list.newStatusCount).to.eql(1)
- expect(store.list.visibleStatusIds).to.eql(
- new Set(['s4', 's3s0', 's2', 's1']),
- )
-
- store.showNewStatuses('list')
- expect(store.list.visibleStatusIds).to.eql(
- new Set([
- 's4',
- 's3s0',
- 's2',
- 's1',
- // Newer
- 's8',
- ]),
- )
- })
- })
})
describe('showNewStatuses', () => {
@@ -431,7 +270,6 @@ describe('Timelines store', () => {
store.activate('public')
store.addStatusesToTimeline('public', undefined, {
statuses,
- repeats: [],
pagination: { minId: '1', maxId: '3' },
})
@@ -442,27 +280,6 @@ describe('Timelines store', () => {
expect(store.public.visibleStatusIds).to.eql(new Set(statuses))
expect(store.public.newStatusCount).to.equal(0)
})
-
- it('limits shown items to 50 for better performance', () => {
- const store = useTimelinesStore()
- const statuses = new Array(100).fill().map((_, index) => 's' + index)
-
- store.activate('public')
- store.addStatusesToTimeline('public', undefined, {
- statuses,
- repeats: [],
- pagination: { minId: '1', maxId: '3' },
- })
-
- expect(store.public.statusIds).to.eql(new Set(statuses))
- expect(store.public.visibleStatusIds).to.eql(new Set())
- expect(store.public.newStatusCount).to.equal(100)
- store.showNewStatuses('public')
- expect(store.public.visibleStatusIds).to.eql(
- new Set(statuses.slice(0, 50)),
- )
- expect(store.public.newStatusCount).to.equal(0)
- })
})
describe('wipeStatuses', () => {
@@ -473,11 +290,9 @@ describe('Timelines store', () => {
store.activate('public')
store.addStatusesToTimeline('public', undefined, {
statuses: ['1', '2', '3', '0'],
- repeats: [],
})
store.addStatusesToTimeline('friends', undefined, {
statuses: ['5', '0', '9', '1'],
- repeats: [],
})
store.wipeStatuses(['0'])
expect(store.friends.statusIds).to.not.have.members('0')