Skip to content

Commit

Permalink
feat(badge-behavior): implements new badge behavior
Browse files Browse the repository at this point in the history
* add a list of notices ids in tab state
  • Loading branch information
lutangar committed Nov 7, 2019
1 parent fc9cc1c commit 6a51e75
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 49 deletions.
13 changes: 11 additions & 2 deletions src/app/background/reducers/tabs.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ import {
TAB_REMOVED,
AppAction,
ReceivedNavigatedToUrlAction,
ReceivedTabRemovedAction
ReceivedTabRemovedAction,
NoticesFoundAction
} from 'app/actions';
import { StatefulNotice } from '../../lmem/notice';

export interface TabsState {
[tabId: string]: Tab;
}

export const toNoticesIds = (notices: StatefulNotice[]) =>
notices.map(({ id }) => id);

export const initialState: TabsState = {};

const addOrUpdateTab = (tab: Tab) => (state: TabsState): TabsState =>
Expand Down Expand Up @@ -47,7 +52,11 @@ export default function(state = initialState, action: AppAction) {
: R.identity
)(state)
: state;

case 'NOTICES_FOUND':
return addOrUpdateTab({
...(action as NoticesFoundAction).meta.tab,
notices: toNoticesIds(action.payload.notices)
})(state);
default:
return state;
}
Expand Down
49 changes: 17 additions & 32 deletions src/app/background/sagas/badge.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { SagaIterator } from 'redux-saga';
import { takeLatest, call, select } from 'redux-saga/effects';
import { StatefulNotice } from 'app/lmem/notice';
import { BadgeTheme, updateBadge } from 'app/lmem/badge';
import {
FeedbackOnNoticeAction,
Expand All @@ -10,16 +9,8 @@ import {
AppAction
} from 'app/actions';
import { ReceivedAction } from 'webext/createMessageHandler';
import { getNoticesToDisplay } from '../selectors/prefs';

const noticeFromId = (id: number) =>
({
id,
message: '',
contributor: { name: '' },
intention: 'alternative',
state: { dismissed: false, disliked: false }
} as StatefulNotice);
import { getNumberOfNoticesOnTab } from '../selectors/tabs';
import { getNumberOfUnreadNoticesOnTab } from '../selectors';

type BadgeImpactingAction = (
| MarkNoticeReadAction
Expand All @@ -33,30 +24,24 @@ export const updateBadgeSaga = (badgeTheme: BadgeTheme) =>
action.type === 'LMEM/CONTEXT_NOT_TRIGGERED' ||
action.type === 'NO_NOTICES_DISPLAYED'
) {
yield call(updateBadge, [], badgeTheme, action.meta.tab.id);
yield call(updateBadge, 0, 0, badgeTheme, action.meta.tab.id);
return;
}

const notices =
action.type === 'NOTICES_FOUND'
? (action as NoticesFoundAction).payload.notices
: [
noticeFromId(
action.type === 'MARK_NOTICE_READ'
? (action as MarkNoticeReadAction).payload
: (action as FeedbackOnNoticeAction).payload.id
)
];

/* FIXME (JAR): I don't like this because we don't really have real notices in `notices`
but we may have { id: number } objects.
It works because we only filter based on id, and then count them,
but this is fragile and Im' not hayppy with it.
I think we should maintain a list of actives notices for each tab. */

const noticesToDisplay = yield select(getNoticesToDisplay(notices));

yield call(updateBadge, noticesToDisplay, badgeTheme, action.meta.tab.id);
const noticesNumber = yield select(
getNumberOfNoticesOnTab(action.meta.tab.id)
);
const unreadNoticesNumber = yield select(
getNumberOfUnreadNoticesOnTab(action.meta.tab.id)
);

yield call(
updateBadge,
noticesNumber,
unreadNoticesNumber,
badgeTheme,
action.meta.tab.id
);
} catch (e) {
badgeUpdateFailed(e);
}
Expand Down
12 changes: 11 additions & 1 deletion src/app/background/selectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { createSelector } from 'reselect';
import { InstallationDetails } from 'app/lmem/installation';
import isBulleVersionNumber from 'app/lmem/isBulleVersionNumber';
import { getInstallationDetails } from './installationDetails';
import { areTosAccepted } from './prefs';
import { areTosAccepted, getRead } from './prefs';
import { getNbSubscriptions } from './subscriptions.selectors';
import { getNoticesIdsOnTab } from './tabs';

export const findTriggeredContexts = (state: BackgroundState) => (
url: string
Expand Down Expand Up @@ -55,3 +56,12 @@ export const isRehydrated = createSelector(
[getPersistState],
persistState => (persistState ? persistState.rehydrated : false)
);

export const getNumberOfUnreadNoticesOnTab = (tabId: number) =>
createSelector(
[getNoticesIdsOnTab(tabId), getRead],
(noticesIds, readNoticesIds) =>
noticesIds
? noticesIds.filter(noticeId => !readNoticesIds.includes(noticeId))
: 0
);
18 changes: 18 additions & 0 deletions src/app/background/selectors/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,21 @@ export const getOptionsTabs = createSelector(
[getTabsList],
R.filter(isOptionsTab)
);

export const getTabById = (tabId: number) =>
createSelector(
[getTabs],
tabs => tabs[tabId]
);

export const getNoticesIdsOnTab = (tabId: number) =>
createSelector(
getTabById(tabId),
tab => tab.notices
);

export const getNumberOfNoticesOnTab = (tabId: number) =>
createSelector(
getNoticesIdsOnTab(tabId),
noticesIds => (noticesIds ? noticesIds.length : 0)
);
22 changes: 8 additions & 14 deletions src/app/lmem/badge.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { StatefulNotice, isUnread } from './notice';
import icons from '../../../manifest/icons';
import greyIcons from '../../../manifest/icons-grey';

Expand All @@ -17,38 +16,33 @@ export const resetBadge = (tabId?: number) => {
/**
* Update text and background color of the badge based on the number of notices.
*
* @param {StatefulNotice[]} notices
* @param {number} noticesNumber
* @param {number} unreadNoticesNumber
* @param {BadgeTheme} badgeTheme
* @param {number} tabId Limits the change to when a particular tab is selected.
*
* @return {void}
*/
export const updateBadge = (
notices: StatefulNotice[],
noticesNumber: number,
unreadNoticesNumber: number,
badgeTheme: BadgeTheme,
tabId?: number
): void => {
if (notices.length > 0) {
chrome.browserAction.setIcon({ path: icons });

const unreadNotices = notices.filter(isUnread);
chrome.browserAction.setIcon({ path: icons });
if (noticesNumber > 0) {
const { backgroundColor } = badgeTheme;

chrome.browserAction.setBadgeText({
text:
unreadNotices.length > 0
? unreadNotices.length.toString()
: notices.length.toString(),
text: noticesNumber.toString(),
tabId
});
chrome.browserAction.setBadgeBackgroundColor({
color:
unreadNotices.length > 0
unreadNoticesNumber > 0
? backgroundColor.hasUnreadNotices
: backgroundColor.hasAllNoticesRead,
tabId
});
} else {
resetBadge(tabId);
}
};
1 change: 1 addition & 0 deletions src/app/lmem/tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export default interface Tab {
url: string;
ready?: boolean;
options?: boolean;
notices?: number[];
}

export const isOptionsTab = (tab: Tab) => Boolean(tab && tab.options === true);
Expand Down

0 comments on commit 6a51e75

Please sign in to comment.