aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/@types/stores.types.ts1
-rw-r--r--src/components/layout/Sidebar.tsx68
-rw-r--r--src/components/services/tabs/TabBarSortableList.tsx (renamed from src/components/services/tabs/TabBarSortableList.js)44
-rw-r--r--src/components/services/tabs/TabItem.tsx (renamed from src/components/services/tabs/TabItem.js)134
-rw-r--r--src/components/services/tabs/Tabbar.tsx (renamed from src/components/services/tabs/Tabbar.js)61
5 files changed, 165 insertions, 143 deletions
diff --git a/src/@types/stores.types.ts b/src/@types/stores.types.ts
index 30898a8a7..bf2dc8bd2 100644
--- a/src/@types/stores.types.ts
+++ b/src/@types/stores.types.ts
@@ -125,6 +125,7 @@ interface AppStore extends TypedStore {
125 universalDarkMode: boolean; 125 universalDarkMode: boolean;
126 cacheSize: () => void; 126 cacheSize: () => void;
127 debugInfo: () => void; 127 debugInfo: () => void;
128 enableLongPressServiceHint: boolean;
128} 129}
129 130
130interface CommunityRecipesStore extends TypedStore { 131interface CommunityRecipesStore extends TypedStore {
diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx
index a81229dca..c37447357 100644
--- a/src/components/layout/Sidebar.tsx
+++ b/src/components/layout/Sidebar.tsx
@@ -3,28 +3,28 @@ import ReactTooltip from 'react-tooltip';
3import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl'; 3import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
4import { inject, observer } from 'mobx-react'; 4import { inject, observer } from 'mobx-react';
5import { 5import {
6 mdiBell,
7 mdiBellOff,
6 mdiCheckAll, 8 mdiCheckAll,
7 mdiViewGrid, 9 mdiChevronDown,
8 mdiPlusBox, 10 mdiChevronRight,
9 mdiCog, 11 mdiCog,
10 mdiBellOff,
11 mdiBell,
12 mdiLock, 12 mdiLock,
13 mdiMenu, 13 mdiMenu,
14 mdiChevronDown, 14 mdiPlusBox,
15 mdiChevronRight, 15 mdiViewGrid,
16 mdiViewSplitVertical, 16 mdiViewSplitVertical,
17} from '@mdi/js'; 17} from '@mdi/js';
18 18
19import Tabbar from '../services/tabs/Tabbar'; 19import Tabbar from '../services/tabs/Tabbar';
20import { 20import {
21 settingsShortcutKey, 21 addNewServiceShortcutKey,
22 lockFerdiumShortcutKey, 22 lockFerdiumShortcutKey,
23 muteFerdiumShortcutKey,
24 settingsShortcutKey,
25 splitModeToggleShortcutKey,
23 todosToggleShortcutKey, 26 todosToggleShortcutKey,
24 workspaceToggleShortcutKey, 27 workspaceToggleShortcutKey,
25 addNewServiceShortcutKey,
26 splitModeToggleShortcutKey,
27 muteFerdiumShortcutKey,
28} from '../../environment'; 28} from '../../environment';
29import { todosStore } from '../../features/todos'; 29import { todosStore } from '../../features/todos';
30import { todoActions } from '../../features/todos/actions'; 30import { todoActions } from '../../features/todos/actions';
@@ -86,21 +86,25 @@ interface IProps extends WrappedComponentProps {
86 actions?: Actions; 86 actions?: Actions;
87 stores?: RealStores; 87 stores?: RealStores;
88 88
89 deleteService: () => void;
90 updateService: () => void;
91 hibernateService: () => void;
92 wakeUpService: () => void;
93 toggleMuteApp: () => void; 89 toggleMuteApp: () => void;
94 toggleCollapseMenu: () => void; 90 toggleCollapseMenu: () => void;
95 toggleWorkspaceDrawer: () => void; 91 toggleWorkspaceDrawer: () => void;
96 openSettings: (arg: { path: string }) => void; 92 openSettings: (args: { path: string }) => void;
97 closeSettings: () => void; 93 closeSettings: () => void;
98 setActive: () => void; 94 setActive: (args: { serviceId: string }) => void;
99 reorder: () => void; 95 reorder: (args: { oldIndex: number; newIndex: number }) => void;
100 reload: () => void; 96 reload: (args: { serviceId: string }) => void;
101 toggleNotifications: () => void; 97 toggleNotifications: (args: { serviceId: string }) => void;
102 toggleAudio: () => void; 98 toggleAudio: (args: { serviceId: string }) => void;
103 toggleDarkMode: () => void; 99 toggleDarkMode: (args: { serviceId: string }) => void;
100 deleteService: (args: { serviceId: string }) => void;
101 hibernateService: (args: { serviceId: string }) => void;
102 wakeUpService: (args: { serviceId: string }) => void;
103 updateService: (args: {
104 serviceId: string;
105 serviceData: { isEnabled: boolean; isMediaPlaying: boolean };
106 redirect: boolean;
107 }) => void;
104} 108}
105 109
106interface IState { 110interface IState {
@@ -180,10 +184,28 @@ class Sidebar extends Component<IProps, IState> {
180 return ( 184 return (
181 <div className="sidebar"> 185 <div className="sidebar">
182 <Tabbar 186 <Tabbar
183 {...this.props} 187 useHorizontalStyle={stores!.settings.all.app.useHorizontalStyle}
188 showMessageBadgeWhenMutedSetting={
189 this.props.showMessageBadgeWhenMutedSetting
190 }
191 showServiceNameSetting={this.props.showServiceNameSetting}
192 showMessageBadgesEvenWhenMuted={
193 this.props.showMessageBadgesEvenWhenMuted
194 }
195 services={this.props.services}
196 setActive={this.props.setActive}
197 openSettings={this.props.openSettings}
184 enableToolTip={() => this.enableToolTip()} 198 enableToolTip={() => this.enableToolTip()}
185 disableToolTip={() => this.disableToolTip()} 199 disableToolTip={() => this.disableToolTip()}
186 useHorizontalStyle={stores!.settings.all.app.useHorizontalStyle} 200 reorder={this.props.reorder}
201 reload={this.props.reload}
202 toggleNotifications={this.props.toggleNotifications}
203 toggleAudio={this.props.toggleAudio}
204 toggleDarkMode={this.props.toggleDarkMode}
205 deleteService={this.props.deleteService}
206 updateService={this.props.updateService}
207 hibernateService={this.props.hibernateService}
208 wakeUpService={this.props.wakeUpService}
187 /> 209 />
188 <> 210 <>
189 {numberActiveButtons <= 1 || hideCollapseButton ? null : ( 211 {numberActiveButtons <= 1 || hideCollapseButton ? null : (
diff --git a/src/components/services/tabs/TabBarSortableList.js b/src/components/services/tabs/TabBarSortableList.tsx
index e01461e5c..e04f6268d 100644
--- a/src/components/services/tabs/TabBarSortableList.js
+++ b/src/components/services/tabs/TabBarSortableList.tsx
@@ -1,29 +1,31 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 2import { observer } from 'mobx-react';
3import PropTypes from 'prop-types';
4import { SortableContainer } from 'react-sortable-hoc'; 3import { SortableContainer } from 'react-sortable-hoc';
5 4
6import TabItem from './TabItem'; 5import TabItem from './TabItem';
6import Service from '../../../models/Service';
7 7
8class TabBarSortableList extends Component { 8interface IProps {
9 static propTypes = { 9 showMessageBadgeWhenMutedSetting: boolean;
10 services: MobxPropTypes.arrayOrObservableArray.isRequired, 10 showServiceNameSetting: boolean;
11 setActive: PropTypes.func.isRequired, 11 showMessageBadgesEvenWhenMuted: boolean;
12 openSettings: PropTypes.func.isRequired, 12 services: Service[];
13 reload: PropTypes.func.isRequired,
14 toggleNotifications: PropTypes.func.isRequired,
15 toggleAudio: PropTypes.func.isRequired,
16 toggleDarkMode: PropTypes.func.isRequired,
17 deleteService: PropTypes.func.isRequired,
18 disableService: PropTypes.func.isRequired,
19 enableService: PropTypes.func.isRequired,
20 hibernateService: PropTypes.func.isRequired,
21 wakeUpService: PropTypes.func.isRequired,
22 showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired,
23 showServiceNameSetting: PropTypes.bool.isRequired,
24 showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired,
25 };
26 13
14 setActive: (args: { serviceId: string }) => void;
15 openSettings: (args: { path: string }) => void;
16 reload: (args: { serviceId: string }) => void;
17 toggleNotifications: (args: { serviceId: string }) => void;
18 toggleAudio: (args: { serviceId: string }) => void;
19 toggleDarkMode: (args: { serviceId: string }) => void;
20 deleteService: (args: { serviceId: string }) => void;
21 disableService: (args: { serviceId: string }) => void;
22 enableService: (args: { serviceId: string }) => void;
23 hibernateService: (args: { serviceId: string }) => void;
24 wakeUpService: (args: { serviceId: string }) => void;
25}
26
27@observer
28class TabBarSortableList extends Component<IProps> {
27 render() { 29 render() {
28 const { 30 const {
29 services, 31 services,
@@ -74,4 +76,4 @@ class TabBarSortableList extends Component {
74 } 76 }
75} 77}
76 78
77export default SortableContainer(observer(TabBarSortableList)); 79export default SortableContainer(TabBarSortableList);
diff --git a/src/components/services/tabs/TabItem.js b/src/components/services/tabs/TabItem.tsx
index 0aab82a6f..fae788764 100644
--- a/src/components/services/tabs/TabItem.js
+++ b/src/components/services/tabs/TabItem.tsx
@@ -1,20 +1,20 @@
1import { Menu, dialog, app } from '@electron/remote'; 1import { app, dialog, Menu } from '@electron/remote';
2import { Component } from 'react'; 2import { Component } from 'react';
3import { defineMessages, injectIntl } from 'react-intl'; 3import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
4import PropTypes from 'prop-types';
5import { inject, observer } from 'mobx-react'; 4import { inject, observer } from 'mobx-react';
6import classnames from 'classnames'; 5import classnames from 'classnames';
7import { SortableElement } from 'react-sortable-hoc'; 6import { SortableElement } from 'react-sortable-hoc';
8import injectSheet from 'react-jss'; 7import injectSheet, { WithStylesProps } from 'react-jss';
9import ms from 'ms'; 8import ms from 'ms';
10 9
11import { observable, autorun, reaction, makeObservable } from 'mobx'; 10import { autorun, makeObservable, observable, reaction } from 'mobx';
12import { mdiExclamation, mdiVolumeSource } from '@mdi/js'; 11import { mdiExclamation, mdiVolumeSource } from '@mdi/js';
13import ServiceModel from '../../../models/Service'; 12import Service from '../../../models/Service';
14import { cmdOrCtrlShortcutKey, shiftKey, altKey } from '../../../environment'; 13import { altKey, cmdOrCtrlShortcutKey, shiftKey } from '../../../environment';
15import globalMessages from '../../../i18n/globalMessages'; 14import globalMessages from '../../../i18n/globalMessages';
16import SettingsStore from '../../../stores/SettingsStore';
17import Icon from '../../ui/icon'; 15import Icon from '../../ui/icon';
16import { Stores } from '../../../@types/stores.types';
17import MenuItemConstructorOptions = Electron.MenuItemConstructorOptions;
18 18
19const IS_SERVICE_DEBUGGING_ENABLED = ( 19const IS_SERVICE_DEBUGGING_ENABLED = (
20 localStorage.getItem('debug') || '' 20 localStorage.getItem('debug') || ''
@@ -114,30 +114,34 @@ const styles = {
114 }, 114 },
115}; 115};
116 116
117class TabItem extends Component { 117interface IProps extends WrappedComponentProps, WithStylesProps<typeof styles> {
118 static propTypes = { 118 showMessageBadgeWhenMutedSetting: boolean;
119 classes: PropTypes.object.isRequired, 119 showServiceNameSetting: boolean;
120 service: PropTypes.instanceOf(ServiceModel).isRequired, 120 showMessageBadgesEvenWhenMuted: boolean;
121 clickHandler: PropTypes.func.isRequired, 121 service: Service;
122 shortcutIndex: PropTypes.number.isRequired, 122 shortcutIndex: number;
123 reload: PropTypes.func.isRequired, 123 stores?: Stores;
124 toggleNotifications: PropTypes.func.isRequired, 124 reload: () => void;
125 toggleAudio: PropTypes.func.isRequired, 125
126 toggleDarkMode: PropTypes.func.isRequired, 126 clickHandler: () => void;
127 openSettings: PropTypes.func.isRequired, 127 toggleNotifications: () => void;
128 deleteService: PropTypes.func.isRequired, 128 toggleAudio: () => void;
129 disableService: PropTypes.func.isRequired, 129 toggleDarkMode: () => void;
130 enableService: PropTypes.func.isRequired, 130 openSettings: (args: { path: string }) => void;
131 hibernateService: PropTypes.func.isRequired, 131 deleteService: () => void;
132 wakeUpService: PropTypes.func.isRequired, 132 disableService: () => void;
133 showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired, 133 enableService: () => void;
134 showServiceNameSetting: PropTypes.bool.isRequired, 134 hibernateService: () => void;
135 showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired, 135 wakeUpService: () => void;
136 stores: PropTypes.shape({ 136}
137 settings: PropTypes.instanceOf(SettingsStore).isRequired, 137
138 }).isRequired, 138interface IState {
139 }; 139 showShortcutIndex: boolean;
140}
140 141
142@inject('stores')
143@observer
144class TabItem extends Component<IProps, IState> {
141 @observable isPolled = false; 145 @observable isPolled = false;
142 146
143 @observable isPollAnswered = false; 147 @observable isPollAnswered = false;
@@ -152,10 +156,10 @@ class TabItem extends Component {
152 }; 156 };
153 157
154 reaction( 158 reaction(
155 () => this.props.stores.settings.app.enableLongPressServiceHint, 159 () => this.props.stores!.settings.app.enableLongPressServiceHint,
156 () => { 160 () => {
157 this.checkForLongPress( 161 this.checkForLongPress(
158 this.props.stores.settings.app.enableLongPressServiceHint, 162 this.props.stores!.settings.app.enableLongPressServiceHint,
159 ); 163 );
160 }, 164 },
161 ); 165 );
@@ -202,7 +206,7 @@ class TabItem extends Component {
202 }); 206 });
203 } 207 }
204 208
205 this.checkForLongPress(stores.settings.app.enableLongPressServiceHint); 209 this.checkForLongPress(stores!.settings.app.enableLongPressServiceHint);
206 } 210 }
207 211
208 render() { 212 render() {
@@ -227,7 +231,7 @@ class TabItem extends Component {
227 } = this.props; 231 } = this.props;
228 const { intl } = this.props; 232 const { intl } = this.props;
229 233
230 const menuTemplate = [ 234 const menuTemplate: Array<MenuItemConstructorOptions> = [
231 { 235 {
232 label: service.name || service.recipe.name, 236 label: service.name || service.recipe.name,
233 enabled: false, 237 enabled: false,
@@ -299,6 +303,7 @@ class TabItem extends Component {
299 { 303 {
300 label: intl.formatMessage(messages.deleteService), 304 label: intl.formatMessage(messages.deleteService),
301 click: () => { 305 click: () => {
306 // @ts-ignore
302 const selection = dialog.showMessageBoxSync(app.mainWindow, { 307 const selection = dialog.showMessageBoxSync(app.mainWindow, {
303 type: 'question', 308 type: 'question',
304 message: intl.formatMessage(messages.deleteService), 309 message: intl.formatMessage(messages.deleteService),
@@ -318,37 +323,10 @@ class TabItem extends Component {
318 ]; 323 ];
319 const menu = Menu.buildFromTemplate(menuTemplate); 324 const menu = Menu.buildFromTemplate(menuTemplate);
320 325
321 let notificationBadge = null; 326 const showNotificationBadge =
322 if (
323 (showMessageBadgeWhenMutedSetting || service.isNotificationEnabled) && 327 (showMessageBadgeWhenMutedSetting || service.isNotificationEnabled) &&
324 showMessageBadgesEvenWhenMuted && 328 showMessageBadgesEvenWhenMuted &&
325 service.isBadgeEnabled 329 service.isBadgeEnabled;
326 ) {
327 notificationBadge = (
328 <>
329 {service.unreadDirectMessageCount > 0 && (
330 <span className="tab-item__message-count">
331 {service.unreadDirectMessageCount}
332 </span>
333 )}
334 {service.unreadIndirectMessageCount > 0 &&
335 service.unreadDirectMessageCount === 0 &&
336 service.isIndirectMessageBadgeEnabled && (
337 <span className="tab-item__message-count is-indirect">•</span>
338 )}
339 {service.isHibernating && (
340 <span className="tab-item__message-count hibernating">•</span>
341 )}
342 </>
343 );
344 }
345
346 let errorBadge = null;
347 if (service.isError) {
348 errorBadge = (
349 <Icon icon={mdiExclamation} className="tab-item__error-icon" />
350 );
351 }
352 330
353 const showMediaBadge = 331 const showMediaBadge =
354 service.isMediaBadgeEnabled && 332 service.isMediaBadgeEnabled &&
@@ -381,8 +359,26 @@ class TabItem extends Component {
381 {showServiceNameSetting && ( 359 {showServiceNameSetting && (
382 <span className="tab-item__label">{service.name}</span> 360 <span className="tab-item__label">{service.name}</span>
383 )} 361 )}
384 {notificationBadge} 362 {showNotificationBadge && (
385 {errorBadge} 363 <>
364 {service.unreadDirectMessageCount > 0 && (
365 <span className="tab-item__message-count">
366 {service.unreadDirectMessageCount}
367 </span>
368 )}
369 {service.unreadIndirectMessageCount > 0 &&
370 service.unreadDirectMessageCount === 0 &&
371 service.isIndirectMessageBadgeEnabled && (
372 <span className="tab-item__message-count is-indirect">•</span>
373 )}
374 {service.isHibernating && (
375 <span className="tab-item__message-count hibernating">•</span>
376 )}
377 </>
378 )}
379 {service.isError && (
380 <Icon icon={mdiExclamation} className="tab-item__error-icon" />
381 )}
386 {showMediaBadge && mediaBadge} 382 {showMediaBadge && mediaBadge}
387 {IS_SERVICE_DEBUGGING_ENABLED && ( 383 {IS_SERVICE_DEBUGGING_ENABLED && (
388 <> 384 <>
@@ -411,9 +407,5 @@ class TabItem extends Component {
411} 407}
412 408
413export default injectIntl( 409export default injectIntl(
414 SortableElement( 410 SortableElement(injectSheet(styles, { injectTheme: true })(TabItem)),
415 injectSheet(styles, { injectTheme: true })(
416 inject('stores')(observer(TabItem)),
417 ),
418 ),
419); 411);
diff --git a/src/components/services/tabs/Tabbar.js b/src/components/services/tabs/Tabbar.tsx
index 0eaf641e3..64541cc8f 100644
--- a/src/components/services/tabs/Tabbar.js
+++ b/src/components/services/tabs/Tabbar.tsx
@@ -1,31 +1,36 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import PropTypes from 'prop-types'; 2import { observer } from 'mobx-react';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4 3
5import TabBarSortableList from './TabBarSortableList'; 4import TabBarSortableList from './TabBarSortableList';
5import Service from '../../../models/Service';
6 6
7class TabBar extends Component { 7interface IProps {
8 static propTypes = { 8 useHorizontalStyle: boolean;
9 services: MobxPropTypes.arrayOrObservableArray.isRequired, 9 showMessageBadgeWhenMutedSetting: boolean;
10 setActive: PropTypes.func.isRequired, 10 showServiceNameSetting: boolean;
11 openSettings: PropTypes.func.isRequired, 11 showMessageBadgesEvenWhenMuted: boolean;
12 enableToolTip: PropTypes.func.isRequired, 12 services: Service[];
13 disableToolTip: PropTypes.func.isRequired, 13 setActive: (args: { serviceId: string }) => void;
14 reorder: PropTypes.func.isRequired, 14 openSettings: (args: { path: string }) => void;
15 reload: PropTypes.func.isRequired, 15 enableToolTip: () => void;
16 toggleNotifications: PropTypes.func.isRequired, 16 disableToolTip: () => void;
17 toggleAudio: PropTypes.func.isRequired, 17 reorder: (args: { oldIndex: number; newIndex: number }) => void;
18 toggleDarkMode: PropTypes.func.isRequired, 18 reload: (args: { serviceId: string }) => void;
19 deleteService: PropTypes.func.isRequired, 19 toggleNotifications: (args: { serviceId: string }) => void;
20 updateService: PropTypes.func.isRequired, 20 toggleAudio: (args: { serviceId: string }) => void;
21 hibernateService: PropTypes.func.isRequired, 21 toggleDarkMode: (args: { serviceId: string }) => void;
22 wakeUpService: PropTypes.func.isRequired, 22 deleteService: (args: { serviceId: string }) => void;
23 useHorizontalStyle: PropTypes.bool.isRequired, 23 hibernateService: (args: { serviceId: string }) => void;
24 showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired, 24 wakeUpService: (args: { serviceId: string }) => void;
25 showServiceNameSetting: PropTypes.bool.isRequired, 25 updateService: (args: {
26 showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired, 26 serviceId: string;
27 }; 27 serviceData: { isEnabled: boolean; isMediaPlaying: boolean };
28 redirect: boolean;
29 }) => void;
30}
28 31
32@observer
33class TabBar extends Component<IProps> {
29 onSortEnd = ({ oldIndex, newIndex }) => { 34 onSortEnd = ({ oldIndex, newIndex }) => {
30 const { enableToolTip, reorder } = this.props; 35 const { enableToolTip, reorder } = this.props;
31 36
@@ -35,14 +40,14 @@ class TabBar extends Component {
35 40
36 shouldPreventSorting = event => event.target.tagName !== 'LI'; 41 shouldPreventSorting = event => event.target.tagName !== 'LI';
37 42
38 toggleService = ({ serviceId, isEnabled }) => { 43 toggleService = (args: { serviceId: string; isEnabled: boolean }) => {
39 const { updateService } = this.props; 44 const { updateService } = this.props;
40 45
41 if (serviceId) { 46 if (args.serviceId) {
42 updateService({ 47 updateService({
43 serviceId, 48 serviceId: args.serviceId,
44 serviceData: { 49 serviceData: {
45 isEnabled, 50 isEnabled: args.isEnabled,
46 isMediaPlaying: false, 51 isMediaPlaying: false,
47 }, 52 },
48 redirect: false, 53 redirect: false,
@@ -120,4 +125,4 @@ class TabBar extends Component {
120 } 125 }
121} 126}
122 127
123export default observer(TabBar); 128export default TabBar;