From d49d8bc145c99cf0358913f22d9469417f1bc117 Mon Sep 17 00:00:00 2001 From: Sean King Date: Wed, 12 Aug 2020 13:39:13 -0600 Subject: [PATCH 1/4] Remove dupilcate quickFilter in notification settings --- app/soapbox/features/notifications/components/column_settings.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/soapbox/features/notifications/components/column_settings.js b/app/soapbox/features/notifications/components/column_settings.js index f53ba70c8..a7aa1f87b 100644 --- a/app/soapbox/features/notifications/components/column_settings.js +++ b/app/soapbox/features/notifications/components/column_settings.js @@ -58,7 +58,6 @@ export default class ColumnSettings extends React.PureComponent {
-
From dc9f5c3a6a311aeddd44bf5e4c39dd74d695ffff Mon Sep 17 00:00:00 2001 From: Mary Kate Date: Thu, 13 Aug 2020 15:48:33 -0500 Subject: [PATCH 2/4] slight overflow imrpovements, fixes #303 --- app/styles/overflow_hacks.scss | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/app/styles/overflow_hacks.scss b/app/styles/overflow_hacks.scss index 204098fca..c00096b72 100644 --- a/app/styles/overflow_hacks.scss +++ b/app/styles/overflow_hacks.scss @@ -12,10 +12,30 @@ button.column-header__button.active { } .detailed-status__wrapper .detailed-status__action-bar { - border-radius: 0; + border-radius: 0 0 10px 10px; } .slist .item-list .column-link { background-color: transparent; border-top: 1px solid var(--brand-color--med); } + +.focusable { + &:focus { + border-radius: 0 0 10px 10px; + } +} + +.focusable:focus .status.status-direct { + border-radius: 0 0 10px 10px; +} + +.status.status-direct:not(.read) { + border-radius: 0 0 10px 10px; +} + +// this still looks like shit but at least it's better than it overflowing + +.empty-column-indicator { + border-radius: 0 0 10px 10px; +} From bd65a1b3f50c42218aa056dee0d2d39cb8de9046 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 14 Aug 2020 12:42:03 -0500 Subject: [PATCH 3/4] Filter out reposts in local timeline by default, fixes #307 --- app/soapbox/actions/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/soapbox/actions/settings.js b/app/soapbox/actions/settings.js index e9b3a0c85..677556dee 100644 --- a/app/soapbox/actions/settings.js +++ b/app/soapbox/actions/settings.js @@ -75,7 +75,7 @@ const defaultSettings = ImmutableMap({ community: ImmutableMap({ shows: ImmutableMap({ - reblog: true, + reblog: false, reply: true, }), other: ImmutableMap({ From fdbe981477039013aaf22cd8288447f4198e9d39 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 14 Aug 2020 15:28:09 -0500 Subject: [PATCH 4/4] Fix timeline queue header when filters are enabled --- app/soapbox/actions/streaming.js | 4 +- app/soapbox/actions/timelines.js | 17 ++++- .../ui/containers/status_list_container.js | 22 ++---- app/soapbox/utils/__tests__/timelines-test.js | 70 +++++++++++++++++++ app/soapbox/utils/timelines.js | 13 ++++ 5 files changed, 105 insertions(+), 21 deletions(-) create mode 100644 app/soapbox/utils/__tests__/timelines-test.js create mode 100644 app/soapbox/utils/timelines.js diff --git a/app/soapbox/actions/streaming.js b/app/soapbox/actions/streaming.js index 027491a1c..099cbab69 100644 --- a/app/soapbox/actions/streaming.js +++ b/app/soapbox/actions/streaming.js @@ -4,7 +4,7 @@ import { expandHomeTimeline, connectTimeline, disconnectTimeline, - updateTimelineQueue, + processTimelineUpdate, } from './timelines'; import { updateNotificationsQueue, expandNotifications } from './notifications'; import { updateConversations } from './conversations'; @@ -36,7 +36,7 @@ export function connectTimelineStream(timelineId, path, pollingRefresh = null, a onReceive(data) { switch(data.event) { case 'update': - dispatch(updateTimelineQueue(timelineId, JSON.parse(data.payload), accept)); + dispatch(processTimelineUpdate(timelineId, JSON.parse(data.payload), accept)); break; case 'delete': dispatch(deleteFromTimelines(data.payload)); diff --git a/app/soapbox/actions/timelines.js b/app/soapbox/actions/timelines.js index 7ae27b8af..323a545b4 100644 --- a/app/soapbox/actions/timelines.js +++ b/app/soapbox/actions/timelines.js @@ -1,6 +1,8 @@ import { importFetchedStatus, importFetchedStatuses } from './importer'; import api, { getLinks } from '../api'; -import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; +import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; +import { getSettings } from 'soapbox/actions/settings'; +import { shouldFilter } from 'soapbox/utils/timelines'; export const TIMELINE_UPDATE = 'TIMELINE_UPDATE'; export const TIMELINE_DELETE = 'TIMELINE_DELETE'; @@ -18,6 +20,19 @@ export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT'; export const MAX_QUEUED_ITEMS = 40; +export function processTimelineUpdate(timeline, status, accept) { + return (dispatch, getState) => { + const columnSettings = getSettings(getState()).get(timeline, ImmutableMap()); + const shouldSkipQueue = shouldFilter(fromJS(status), columnSettings); + + if (shouldSkipQueue) { + return dispatch(updateTimeline(timeline, status, accept)); + } else { + return dispatch(updateTimelineQueue(timeline, status, accept)); + } + }; +} + export function updateTimeline(timeline, status, accept) { return dispatch => { if (typeof accept === 'function' && !accept(status)) { diff --git a/app/soapbox/features/ui/containers/status_list_container.js b/app/soapbox/features/ui/containers/status_list_container.js index f54cd2eee..03afa4b88 100644 --- a/app/soapbox/features/ui/containers/status_list_container.js +++ b/app/soapbox/features/ui/containers/status_list_container.js @@ -6,6 +6,7 @@ import { debounce } from 'lodash'; import { dequeueTimeline } from 'soapbox/actions/timelines'; import { scrollTopTimeline } from '../../../actions/timelines'; import { getSettings } from 'soapbox/actions/settings'; +import { shouldFilter } from 'soapbox/utils/timelines'; const makeGetStatusIds = () => createSelector([ (state, { type }) => getSettings(state).get(type, ImmutableMap()), @@ -14,24 +15,9 @@ const makeGetStatusIds = () => createSelector([ (state) => state.get('me'), ], (columnSettings, statusIds, statuses, me) => { return statusIds.filter(id => { - if (id === null) return true; - - const statusForId = statuses.get(id); - let showStatus = true; - - if (columnSettings.getIn(['shows', 'reblog']) === false) { - showStatus = showStatus && statusForId.get('reblog') === null; - } - - if (columnSettings.getIn(['shows', 'reply']) === false) { - showStatus = showStatus && (statusForId.get('in_reply_to_id') === null); - } - - if (columnSettings.getIn(['shows', 'direct']) === false) { - showStatus = showStatus && (statusForId.get('visibility') !== 'direct'); - } - - return showStatus; + const status = statuses.get(id); + if (!status) return true; + return !shouldFilter(status, columnSettings); }); }); diff --git a/app/soapbox/utils/__tests__/timelines-test.js b/app/soapbox/utils/__tests__/timelines-test.js new file mode 100644 index 000000000..7b9124559 --- /dev/null +++ b/app/soapbox/utils/__tests__/timelines-test.js @@ -0,0 +1,70 @@ +import { shouldFilter } from '../timelines'; +import { fromJS } from 'immutable'; + +describe('shouldFilter', () => { + it('returns false under normal circumstances', () => { + const columnSettings = fromJS({}); + const status = fromJS({}); + expect(shouldFilter(status, columnSettings)).toBe(false); + }); + + it('reblog: returns true when `shows.reblog == false`', () => { + const columnSettings = fromJS({ shows: { reblog: false } }); + const status = fromJS({ reblog: {} }); + expect(shouldFilter(status, columnSettings)).toBe(true); + }); + + it('reblog: returns false when `shows.reblog == true`', () => { + const columnSettings = fromJS({ shows: { reblog: true } }); + const status = fromJS({ reblog: {} }); + expect(shouldFilter(status, columnSettings)).toBe(false); + }); + + it('reply: returns true when `shows.reply == false`', () => { + const columnSettings = fromJS({ shows: { reply: false } }); + const status = fromJS({ in_reply_to_id: '1234' }); + expect(shouldFilter(status, columnSettings)).toBe(true); + }); + + it('reply: returns false when `shows.reply == true`', () => { + const columnSettings = fromJS({ shows: { reply: true } }); + const status = fromJS({ in_reply_to_id: '1234' }); + expect(shouldFilter(status, columnSettings)).toBe(false); + }); + + it('direct: returns true when `shows.direct == false`', () => { + const columnSettings = fromJS({ shows: { direct: false } }); + const status = fromJS({ visibility: 'direct' }); + expect(shouldFilter(status, columnSettings)).toBe(true); + }); + + it('direct: returns false when `shows.direct == true`', () => { + const columnSettings = fromJS({ shows: { direct: true } }); + const status = fromJS({ visibility: 'direct' }); + expect(shouldFilter(status, columnSettings)).toBe(false); + }); + + it('direct: returns false for a public post when `shows.direct == false`', () => { + const columnSettings = fromJS({ shows: { direct: false } }); + const status = fromJS({ visibility: 'public' }); + expect(shouldFilter(status, columnSettings)).toBe(false); + }); + + it('multiple settings', () => { + const columnSettings = fromJS({ shows: { reblog: false, reply: false, direct: false } }); + const status = fromJS({ reblog: null, in_reply_to_id: null, visibility: 'direct' }); + expect(shouldFilter(status, columnSettings)).toBe(true); + }); + + it('multiple settings', () => { + const columnSettings = fromJS({ shows: { reblog: false, reply: true, direct: false } }); + const status = fromJS({ reblog: null, in_reply_to_id: '1234', visibility: 'public' }); + expect(shouldFilter(status, columnSettings)).toBe(false); + }); + + it('multiple settings', () => { + const columnSettings = fromJS({ shows: { reblog: true, reply: false, direct: true } }); + const status = fromJS({ reblog: {}, in_reply_to_id: '1234', visibility: 'direct' }); + expect(shouldFilter(status, columnSettings)).toBe(true); + }); +}); diff --git a/app/soapbox/utils/timelines.js b/app/soapbox/utils/timelines.js new file mode 100644 index 000000000..d15a4fa88 --- /dev/null +++ b/app/soapbox/utils/timelines.js @@ -0,0 +1,13 @@ +import { Map as ImmutableMap } from 'immutable'; + +export const shouldFilter = (status, columnSettings) => { + const shows = ImmutableMap({ + reblog: status.get('reblog') !== null, + reply: status.get('in_reply_to_id') !== null, + direct: status.get('visibility') === 'direct', + }); + + return shows.some((value, key) => { + return columnSettings.getIn(['shows', key]) === false && value; + }); +};