diff options
author | Balaji Vijayakumar <kuttibalaji.v6@gmail.com> | 2022-10-26 09:47:11 +0530 |
---|---|---|
committer | Vijay Aravamudhan <vraravam@users.noreply.github.com> | 2022-10-26 10:15:16 +0530 |
commit | 354ffea92be3a1030c730b6bb8ece7f680e01b12 (patch) | |
tree | 6425e972752c9b250e861b16da1a3120bc6db13c /src/components/services/tabs/TabItem.js | |
parent | 6.2.1-nightly.29 [skip ci] (diff) | |
download | ferdium-app-354ffea92be3a1030c730b6bb8ece7f680e01b12.tar.gz ferdium-app-354ffea92be3a1030c730b6bb8ece7f680e01b12.tar.zst ferdium-app-354ffea92be3a1030c730b6bb8ece7f680e01b12.zip |
refactor: convert TabBar to typescript
Diffstat (limited to 'src/components/services/tabs/TabItem.js')
-rw-r--r-- | src/components/services/tabs/TabItem.js | 419 |
1 files changed, 0 insertions, 419 deletions
diff --git a/src/components/services/tabs/TabItem.js b/src/components/services/tabs/TabItem.js deleted file mode 100644 index 0aab82a6f..000000000 --- a/src/components/services/tabs/TabItem.js +++ /dev/null | |||
@@ -1,419 +0,0 @@ | |||
1 | import { Menu, dialog, app } from '@electron/remote'; | ||
2 | import { Component } from 'react'; | ||
3 | import { defineMessages, injectIntl } from 'react-intl'; | ||
4 | import PropTypes from 'prop-types'; | ||
5 | import { inject, observer } from 'mobx-react'; | ||
6 | import classnames from 'classnames'; | ||
7 | import { SortableElement } from 'react-sortable-hoc'; | ||
8 | import injectSheet from 'react-jss'; | ||
9 | import ms from 'ms'; | ||
10 | |||
11 | import { observable, autorun, reaction, makeObservable } from 'mobx'; | ||
12 | import { mdiExclamation, mdiVolumeSource } from '@mdi/js'; | ||
13 | import ServiceModel from '../../../models/Service'; | ||
14 | import { cmdOrCtrlShortcutKey, shiftKey, altKey } from '../../../environment'; | ||
15 | import globalMessages from '../../../i18n/globalMessages'; | ||
16 | import SettingsStore from '../../../stores/SettingsStore'; | ||
17 | import Icon from '../../ui/icon'; | ||
18 | |||
19 | const IS_SERVICE_DEBUGGING_ENABLED = ( | ||
20 | localStorage.getItem('debug') || '' | ||
21 | ).includes('Ferdium:Service'); | ||
22 | |||
23 | const messages = defineMessages({ | ||
24 | reload: { | ||
25 | id: 'tabs.item.reload', | ||
26 | defaultMessage: 'Reload', | ||
27 | }, | ||
28 | disableNotifications: { | ||
29 | id: 'tabs.item.disableNotifications', | ||
30 | defaultMessage: 'Disable notifications', | ||
31 | }, | ||
32 | enableNotifications: { | ||
33 | id: 'tabs.item.enableNotification', | ||
34 | defaultMessage: 'Enable notifications', | ||
35 | }, | ||
36 | disableAudio: { | ||
37 | id: 'tabs.item.disableAudio', | ||
38 | defaultMessage: 'Disable audio', | ||
39 | }, | ||
40 | enableAudio: { | ||
41 | id: 'tabs.item.enableAudio', | ||
42 | defaultMessage: 'Enable audio', | ||
43 | }, | ||
44 | enableDarkMode: { | ||
45 | id: 'tabs.item.enableDarkMode', | ||
46 | defaultMessage: 'Enable Dark mode', | ||
47 | }, | ||
48 | disableDarkMode: { | ||
49 | id: 'tabs.item.disableDarkMode', | ||
50 | defaultMessage: 'Disable Dark mode', | ||
51 | }, | ||
52 | disableService: { | ||
53 | id: 'tabs.item.disableService', | ||
54 | defaultMessage: 'Disable service', | ||
55 | }, | ||
56 | enableService: { | ||
57 | id: 'tabs.item.enableService', | ||
58 | defaultMessage: 'Enable service', | ||
59 | }, | ||
60 | hibernateService: { | ||
61 | id: 'tabs.item.hibernateService', | ||
62 | defaultMessage: 'Hibernate service', | ||
63 | }, | ||
64 | wakeUpService: { | ||
65 | id: 'tabs.item.wakeUpService', | ||
66 | defaultMessage: 'Wake up service', | ||
67 | }, | ||
68 | deleteService: { | ||
69 | id: 'tabs.item.deleteService', | ||
70 | defaultMessage: 'Delete service', | ||
71 | }, | ||
72 | confirmDeleteService: { | ||
73 | id: 'tabs.item.confirmDeleteService', | ||
74 | defaultMessage: 'Do you really want to delete the {serviceName} service?', | ||
75 | }, | ||
76 | }); | ||
77 | |||
78 | let pollIndicatorTransition = 'none'; | ||
79 | let polledTransition = 'none'; | ||
80 | let pollAnsweredTransition = 'none'; | ||
81 | |||
82 | if (window && window.matchMedia('(prefers-reduced-motion: no-preference)')) { | ||
83 | pollIndicatorTransition = 'background 0.5s'; | ||
84 | polledTransition = 'background 0.1s'; | ||
85 | pollAnsweredTransition = 'background 0.1s'; | ||
86 | } | ||
87 | |||
88 | const styles = { | ||
89 | pollIndicator: { | ||
90 | position: 'absolute', | ||
91 | bottom: 2, | ||
92 | width: 10, | ||
93 | height: 10, | ||
94 | borderRadius: 5, | ||
95 | background: 'gray', | ||
96 | transition: pollIndicatorTransition, | ||
97 | }, | ||
98 | pollIndicatorPoll: { | ||
99 | left: 2, | ||
100 | }, | ||
101 | pollIndicatorAnswer: { | ||
102 | left: 14, | ||
103 | }, | ||
104 | polled: { | ||
105 | background: 'yellow !important', | ||
106 | transition: polledTransition, | ||
107 | }, | ||
108 | pollAnswered: { | ||
109 | background: 'green !important', | ||
110 | transition: pollAnsweredTransition, | ||
111 | }, | ||
112 | stale: { | ||
113 | background: 'red !important', | ||
114 | }, | ||
115 | }; | ||
116 | |||
117 | class TabItem extends Component { | ||
118 | static propTypes = { | ||
119 | classes: PropTypes.object.isRequired, | ||
120 | service: PropTypes.instanceOf(ServiceModel).isRequired, | ||
121 | clickHandler: PropTypes.func.isRequired, | ||
122 | shortcutIndex: PropTypes.number.isRequired, | ||
123 | reload: PropTypes.func.isRequired, | ||
124 | toggleNotifications: PropTypes.func.isRequired, | ||
125 | toggleAudio: PropTypes.func.isRequired, | ||
126 | toggleDarkMode: PropTypes.func.isRequired, | ||
127 | openSettings: PropTypes.func.isRequired, | ||
128 | deleteService: PropTypes.func.isRequired, | ||
129 | disableService: PropTypes.func.isRequired, | ||
130 | enableService: PropTypes.func.isRequired, | ||
131 | hibernateService: PropTypes.func.isRequired, | ||
132 | wakeUpService: PropTypes.func.isRequired, | ||
133 | showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired, | ||
134 | showServiceNameSetting: PropTypes.bool.isRequired, | ||
135 | showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired, | ||
136 | stores: PropTypes.shape({ | ||
137 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | ||
138 | }).isRequired, | ||
139 | }; | ||
140 | |||
141 | @observable isPolled = false; | ||
142 | |||
143 | @observable isPollAnswered = false; | ||
144 | |||
145 | constructor(props) { | ||
146 | super(props); | ||
147 | |||
148 | makeObservable(this); | ||
149 | |||
150 | this.state = { | ||
151 | showShortcutIndex: false, | ||
152 | }; | ||
153 | |||
154 | reaction( | ||
155 | () => this.props.stores.settings.app.enableLongPressServiceHint, | ||
156 | () => { | ||
157 | this.checkForLongPress( | ||
158 | this.props.stores.settings.app.enableLongPressServiceHint, | ||
159 | ); | ||
160 | }, | ||
161 | ); | ||
162 | } | ||
163 | |||
164 | handleShortcutIndex = (event, showShortcutIndex = true) => { | ||
165 | if (event.key === 'Shift') { | ||
166 | this.setState({ showShortcutIndex }); | ||
167 | } | ||
168 | }; | ||
169 | |||
170 | checkForLongPress = enableLongPressServiceHint => { | ||
171 | if (enableLongPressServiceHint) { | ||
172 | document.addEventListener('keydown', e => { | ||
173 | this.handleShortcutIndex(e); | ||
174 | }); | ||
175 | |||
176 | document.addEventListener('keyup', e => { | ||
177 | this.handleShortcutIndex(e, false); | ||
178 | }); | ||
179 | } | ||
180 | }; | ||
181 | |||
182 | componentDidMount() { | ||
183 | const { service, stores } = this.props; | ||
184 | |||
185 | if (IS_SERVICE_DEBUGGING_ENABLED) { | ||
186 | autorun(() => { | ||
187 | if (Date.now() - service.lastPoll < ms('0.2s')) { | ||
188 | this.isPolled = true; | ||
189 | |||
190 | setTimeout(() => { | ||
191 | this.isPolled = false; | ||
192 | }, ms('1s')); | ||
193 | } | ||
194 | |||
195 | if (Date.now() - service.lastPollAnswer < ms('0.2s')) { | ||
196 | this.isPollAnswered = true; | ||
197 | |||
198 | setTimeout(() => { | ||
199 | this.isPollAnswered = false; | ||
200 | }, ms('1s')); | ||
201 | } | ||
202 | }); | ||
203 | } | ||
204 | |||
205 | this.checkForLongPress(stores.settings.app.enableLongPressServiceHint); | ||
206 | } | ||
207 | |||
208 | render() { | ||
209 | const { | ||
210 | classes, | ||
211 | service, | ||
212 | clickHandler, | ||
213 | shortcutIndex, | ||
214 | reload, | ||
215 | toggleNotifications, | ||
216 | toggleAudio, | ||
217 | toggleDarkMode, | ||
218 | deleteService, | ||
219 | disableService, | ||
220 | enableService, | ||
221 | hibernateService, | ||
222 | wakeUpService, | ||
223 | openSettings, | ||
224 | showMessageBadgeWhenMutedSetting, | ||
225 | showServiceNameSetting, | ||
226 | showMessageBadgesEvenWhenMuted, | ||
227 | } = this.props; | ||
228 | const { intl } = this.props; | ||
229 | |||
230 | const menuTemplate = [ | ||
231 | { | ||
232 | label: service.name || service.recipe.name, | ||
233 | enabled: false, | ||
234 | }, | ||
235 | { | ||
236 | type: 'separator', | ||
237 | }, | ||
238 | { | ||
239 | label: intl.formatMessage(messages.reload), | ||
240 | click: reload, | ||
241 | accelerator: `${cmdOrCtrlShortcutKey()}+R`, | ||
242 | enabled: service.isEnabled, | ||
243 | }, | ||
244 | { | ||
245 | label: intl.formatMessage(globalMessages.edit), | ||
246 | click: () => | ||
247 | openSettings({ | ||
248 | path: `services/edit/${service.id}`, | ||
249 | }), | ||
250 | }, | ||
251 | { | ||
252 | type: 'separator', | ||
253 | }, | ||
254 | { | ||
255 | label: service.isNotificationEnabled | ||
256 | ? intl.formatMessage(messages.disableNotifications) | ||
257 | : intl.formatMessage(messages.enableNotifications), | ||
258 | click: () => toggleNotifications(), | ||
259 | accelerator: `${cmdOrCtrlShortcutKey()}+${altKey()}+N`, | ||
260 | enabled: service.isEnabled, | ||
261 | }, | ||
262 | { | ||
263 | label: service.isMuted | ||
264 | ? intl.formatMessage(messages.enableAudio) | ||
265 | : intl.formatMessage(messages.disableAudio), | ||
266 | click: () => toggleAudio(), | ||
267 | accelerator: `${cmdOrCtrlShortcutKey()}+${shiftKey()}+A`, | ||
268 | enabled: service.isEnabled, | ||
269 | }, | ||
270 | { | ||
271 | label: service.isDarkModeEnabled | ||
272 | ? intl.formatMessage(messages.disableDarkMode) | ||
273 | : intl.formatMessage(messages.enableDarkMode), | ||
274 | click: () => toggleDarkMode(), | ||
275 | accelerator: `${shiftKey()}+${altKey()}+D`, | ||
276 | enabled: service.isEnabled, | ||
277 | }, | ||
278 | { | ||
279 | label: intl.formatMessage( | ||
280 | service.isEnabled ? messages.disableService : messages.enableService, | ||
281 | ), | ||
282 | click: () => (service.isEnabled ? disableService() : enableService()), | ||
283 | accelerator: `${cmdOrCtrlShortcutKey()}+${shiftKey()}+S`, | ||
284 | }, | ||
285 | { | ||
286 | label: intl.formatMessage( | ||
287 | service.isHibernating | ||
288 | ? messages.wakeUpService | ||
289 | : messages.hibernateService, | ||
290 | ), | ||
291 | // eslint-disable-next-line no-confusing-arrow | ||
292 | click: () => | ||
293 | service.isHibernating ? wakeUpService() : hibernateService(), | ||
294 | enabled: service.isEnabled && service.canHibernate, | ||
295 | }, | ||
296 | { | ||
297 | type: 'separator', | ||
298 | }, | ||
299 | { | ||
300 | label: intl.formatMessage(messages.deleteService), | ||
301 | click: () => { | ||
302 | const selection = dialog.showMessageBoxSync(app.mainWindow, { | ||
303 | type: 'question', | ||
304 | message: intl.formatMessage(messages.deleteService), | ||
305 | detail: intl.formatMessage(messages.confirmDeleteService, { | ||
306 | serviceName: service.name || service.recipe.name, | ||
307 | }), | ||
308 | buttons: [ | ||
309 | intl.formatMessage(globalMessages.yes), | ||
310 | intl.formatMessage(globalMessages.no), | ||
311 | ], | ||
312 | }); | ||
313 | if (selection === 0) { | ||
314 | deleteService(); | ||
315 | } | ||
316 | }, | ||
317 | }, | ||
318 | ]; | ||
319 | const menu = Menu.buildFromTemplate(menuTemplate); | ||
320 | |||
321 | let notificationBadge = null; | ||
322 | if ( | ||
323 | (showMessageBadgeWhenMutedSetting || service.isNotificationEnabled) && | ||
324 | showMessageBadgesEvenWhenMuted && | ||
325 | 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 | |||
353 | const showMediaBadge = | ||
354 | service.isMediaBadgeEnabled && | ||
355 | service.isMediaPlaying && | ||
356 | service.isEnabled; | ||
357 | const mediaBadge = ( | ||
358 | <Icon icon={mdiVolumeSource} className="tab-item__icon" /> | ||
359 | ); | ||
360 | |||
361 | return ( | ||
362 | <li | ||
363 | className={classnames({ | ||
364 | [classes.stale]: | ||
365 | IS_SERVICE_DEBUGGING_ENABLED && service.lostRecipeConnection, | ||
366 | 'tab-item': true, | ||
367 | 'is-active': service.isActive, | ||
368 | 'has-custom-icon': service.hasCustomIcon, | ||
369 | 'is-disabled': !service.isEnabled, | ||
370 | 'is-label-enabled': showServiceNameSetting, | ||
371 | })} | ||
372 | onClick={clickHandler} | ||
373 | onContextMenu={() => menu.popup()} | ||
374 | data-tip={`${service.name} ${ | ||
375 | shortcutIndex <= 9 | ||
376 | ? `(${cmdOrCtrlShortcutKey(false)}+${shortcutIndex})` | ||
377 | : '' | ||
378 | }`} | ||
379 | > | ||
380 | <img src={service.icon} className="tab-item__icon" alt="" /> | ||
381 | {showServiceNameSetting && ( | ||
382 | <span className="tab-item__label">{service.name}</span> | ||
383 | )} | ||
384 | {notificationBadge} | ||
385 | {errorBadge} | ||
386 | {showMediaBadge && mediaBadge} | ||
387 | {IS_SERVICE_DEBUGGING_ENABLED && ( | ||
388 | <> | ||
389 | <div | ||
390 | className={classnames({ | ||
391 | [classes.pollIndicator]: true, | ||
392 | [classes.pollIndicatorPoll]: true, | ||
393 | [classes.polled]: this.isPolled, | ||
394 | })} | ||
395 | /> | ||
396 | <div | ||
397 | className={classnames({ | ||
398 | [classes.pollIndicator]: true, | ||
399 | [classes.pollIndicatorAnswer]: true, | ||
400 | [classes.pollAnswered]: this.isPollAnswered, | ||
401 | })} | ||
402 | /> | ||
403 | </> | ||
404 | )} | ||
405 | {shortcutIndex <= 9 && this.state.showShortcutIndex && ( | ||
406 | <span className="tab-item__shortcut-index">{shortcutIndex}</span> | ||
407 | )} | ||
408 | </li> | ||
409 | ); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | export default injectIntl( | ||
414 | SortableElement( | ||
415 | injectSheet(styles, { injectTheme: true })( | ||
416 | inject('stores')(observer(TabItem)), | ||
417 | ), | ||
418 | ), | ||
419 | ); | ||