aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/services/tabs/TabItem.js
diff options
context:
space:
mode:
authorLibravatar Markus Hatvan <markus_hatvan@aon.at>2021-08-10 19:04:54 +0200
committerLibravatar GitHub <noreply@github.com>2021-08-10 22:34:54 +0530
commit969eda02a66050cf4518ddfa657e86d1d6d8b6c3 (patch)
tree9f21b062f0c188f2c3ddfbb6594670982610aadf /src/components/services/tabs/TabItem.js
parentrefactor: Move platform-specific logic for shortcut keys into common location. (diff)
downloadferdium-app-969eda02a66050cf4518ddfa657e86d1d6d8b6c3.tar.gz
ferdium-app-969eda02a66050cf4518ddfa657e86d1d6d8b6c3.tar.zst
ferdium-app-969eda02a66050cf4518ddfa657e86d1d6d8b6c3.zip
feat: follow OS reduced motion setting (#1757)
- add missing meta charset to index.html - dont restrict scaling for user in index.html - load animations.css conditionally based on motion preference - load transitions conditionally in js and css based on motion preference Co-authored-by: Vijay Raghavan Aravamudhan <vraravam@users.noreply.github.com>
Diffstat (limited to 'src/components/services/tabs/TabItem.js')
-rw-r--r--src/components/services/tabs/TabItem.js193
1 files changed, 114 insertions, 79 deletions
diff --git a/src/components/services/tabs/TabItem.js b/src/components/services/tabs/TabItem.js
index ccf3333f8..023e152c7 100644
--- a/src/components/services/tabs/TabItem.js
+++ b/src/components/services/tabs/TabItem.js
@@ -1,6 +1,4 @@
1import { 1import { Menu, dialog, app, getCurrentWindow } from '@electron/remote';
2 Menu, dialog, app, getCurrentWindow,
3} from '@electron/remote';
4import React, { Component } from 'react'; 2import React, { Component } from 'react';
5import { defineMessages, intlShape } from 'react-intl'; 3import { defineMessages, intlShape } from 'react-intl';
6import PropTypes from 'prop-types'; 4import PropTypes from 'prop-types';
@@ -14,7 +12,9 @@ import { observable, autorun } from 'mobx';
14import ServiceModel from '../../../models/Service'; 12import ServiceModel from '../../../models/Service';
15import { ctrlKey, cmdKey } from '../../../environment'; 13import { ctrlKey, cmdKey } from '../../../environment';
16 14
17const IS_SERVICE_DEBUGGING_ENABLED = (localStorage.getItem('debug') || '').includes('Ferdi:Service'); 15const IS_SERVICE_DEBUGGING_ENABLED = (
16 localStorage.getItem('debug') || ''
17).includes('Ferdi:Service');
18 18
19const messages = defineMessages({ 19const messages = defineMessages({
20 reload: { 20 reload: {
@@ -63,10 +63,21 @@ const messages = defineMessages({
63 }, 63 },
64 confirmDeleteService: { 64 confirmDeleteService: {
65 id: 'tabs.item.confirmDeleteService', 65 id: 'tabs.item.confirmDeleteService',
66 defaultMessage: '!!!Do you really want to delete the {serviceName} service?', 66 defaultMessage:
67 '!!!Do you really want to delete the {serviceName} service?',
67 }, 68 },
68}); 69});
69 70
71let pollIndicatorTransition = 'none';
72let polledTransition = 'none';
73let pollAnsweredTransition = 'none';
74
75if (window.matchMedia('(prefers-reduced-motion: no-preference)')) {
76 pollIndicatorTransition = 'background 0.5s';
77 polledTransition = 'background 0.1s';
78 pollAnsweredTransition = 'background 0.1s';
79}
80
70const styles = { 81const styles = {
71 pollIndicator: { 82 pollIndicator: {
72 position: 'absolute', 83 position: 'absolute',
@@ -75,7 +86,7 @@ const styles = {
75 height: 10, 86 height: 10,
76 borderRadius: 5, 87 borderRadius: 5,
77 background: 'gray', 88 background: 'gray',
78 transition: 'background 0.5s', 89 transition: pollIndicatorTransition,
79 }, 90 },
80 pollIndicatorPoll: { 91 pollIndicatorPoll: {
81 left: 2, 92 left: 2,
@@ -85,18 +96,20 @@ const styles = {
85 }, 96 },
86 polled: { 97 polled: {
87 background: 'yellow !important', 98 background: 'yellow !important',
88 transition: 'background 0.1s', 99 transition: polledTransition,
89 }, 100 },
90 pollAnswered: { 101 pollAnswered: {
91 background: 'green !important', 102 background: 'green !important',
92 transition: 'background 0.1s', 103 transition: pollAnsweredTransition,
93 }, 104 },
94 stale: { 105 stale: {
95 background: 'red !important', 106 background: 'red !important',
96 }, 107 },
97}; 108};
98 109
99@injectSheet(styles) @observer class TabItem extends Component { 110@injectSheet(styles)
111@observer
112class TabItem extends Component {
100 static propTypes = { 113 static propTypes = {
101 classes: PropTypes.object.isRequired, 114 classes: PropTypes.object.isRequired,
102 service: PropTypes.instanceOf(ServiceModel).isRequired, 115 service: PropTypes.instanceOf(ServiceModel).isRequired,
@@ -131,13 +144,17 @@ const styles = {
131 if (Date.now() - service.lastPoll < ms('0.2s')) { 144 if (Date.now() - service.lastPoll < ms('0.2s')) {
132 this.isPolled = true; 145 this.isPolled = true;
133 146
134 setTimeout(() => { this.isPolled = false; }, ms('1s')); 147 setTimeout(() => {
148 this.isPolled = false;
149 }, ms('1s'));
135 } 150 }
136 151
137 if (Date.now() - service.lastPollAnswer < ms('0.2s')) { 152 if (Date.now() - service.lastPollAnswer < ms('0.2s')) {
138 this.isPollAnswered = true; 153 this.isPollAnswered = true;
139 154
140 setTimeout(() => { this.isPollAnswered = false; }, ms('1s')); 155 setTimeout(() => {
156 this.isPollAnswered = false;
157 }, ms('1s'));
141 } 158 }
142 }); 159 });
143 } 160 }
@@ -163,62 +180,85 @@ const styles = {
163 } = this.props; 180 } = this.props;
164 const { intl } = this.context; 181 const { intl } = this.context;
165 182
166 const menuTemplate = [{ 183 const menuTemplate = [
167 label: service.name || service.recipe.name, 184 {
168 enabled: false, 185 label: service.name || service.recipe.name,
169 }, { 186 enabled: false,
170 type: 'separator', 187 },
171 }, { 188 {
172 label: intl.formatMessage(messages.reload), 189 type: 'separator',
173 click: reload, 190 },
174 accelerator: `${cmdKey}+R`, 191 {
175 }, { 192 label: intl.formatMessage(messages.reload),
176 label: intl.formatMessage(messages.edit), 193 click: reload,
177 click: () => openSettings({ 194 accelerator: `${cmdKey}+R`,
178 path: `services/edit/${service.id}`, 195 },
179 }), 196 {
180 }, { 197 label: intl.formatMessage(messages.edit),
181 type: 'separator', 198 click: () =>
182 }, { 199 openSettings({
183 label: service.isNotificationEnabled 200 path: `services/edit/${service.id}`,
184 ? intl.formatMessage(messages.disableNotifications) 201 }),
185 : intl.formatMessage(messages.enableNotifications), 202 },
186 click: () => toggleNotifications(), 203 {
187 }, { 204 type: 'separator',
188 label: service.isMuted
189 ? intl.formatMessage(messages.enableAudio)
190 : intl.formatMessage(messages.disableAudio),
191 click: () => toggleAudio(),
192 }, {
193 label: intl.formatMessage(service.isEnabled ? messages.disableService : messages.enableService),
194 click: () => (service.isEnabled ? disableService() : enableService()),
195 }, {
196 label: intl.formatMessage(service.isHibernating ? messages.wakeUpService : messages.hibernateService),
197 click: () => (service.isHibernating ? wakeUpService() : hibernateService()),
198 enabled: service.canHibernate,
199 }, {
200 type: 'separator',
201 }, {
202 label: intl.formatMessage(messages.deleteService),
203 click: () => {
204 const selection = dialog.showMessageBoxSync(app.mainWindow, {
205 type: 'question',
206 message: intl.formatMessage(messages.deleteService),
207 detail: intl.formatMessage(messages.confirmDeleteService, { serviceName: service.name || service.recipe.name }),
208 buttons: [
209 'Yes',
210 'No',
211 ],
212 });
213 if (selection === 0) {
214 deleteService();
215 }
216 }, 205 },
217 }]; 206 {
207 label: service.isNotificationEnabled
208 ? intl.formatMessage(messages.disableNotifications)
209 : intl.formatMessage(messages.enableNotifications),
210 click: () => toggleNotifications(),
211 },
212 {
213 label: service.isMuted
214 ? intl.formatMessage(messages.enableAudio)
215 : intl.formatMessage(messages.disableAudio),
216 click: () => toggleAudio(),
217 },
218 {
219 label: intl.formatMessage(
220 service.isEnabled ? messages.disableService : messages.enableService,
221 ),
222 click: () => (service.isEnabled ? disableService() : enableService()),
223 },
224 {
225 label: intl.formatMessage(
226 service.isHibernating
227 ? messages.wakeUpService
228 : messages.hibernateService,
229 ),
230 click: () =>
231 (service.isHibernating ? wakeUpService() : hibernateService()),
232 enabled: service.canHibernate,
233 },
234 {
235 type: 'separator',
236 },
237 {
238 label: intl.formatMessage(messages.deleteService),
239 click: () => {
240 const selection = dialog.showMessageBoxSync(app.mainWindow, {
241 type: 'question',
242 message: intl.formatMessage(messages.deleteService),
243 detail: intl.formatMessage(messages.confirmDeleteService, {
244 serviceName: service.name || service.recipe.name,
245 }),
246 buttons: ['Yes', 'No'],
247 });
248 if (selection === 0) {
249 deleteService();
250 }
251 },
252 },
253 ];
218 const menu = Menu.buildFromTemplate(menuTemplate); 254 const menu = Menu.buildFromTemplate(menuTemplate);
219 255
220 let notificationBadge = null; 256 let notificationBadge = null;
221 if ((showMessageBadgeWhenMutedSetting || service.isNotificationEnabled) && showMessageBadgesEvenWhenMuted && service.isBadgeEnabled) { 257 if (
258 (showMessageBadgeWhenMutedSetting || service.isNotificationEnabled) &&
259 showMessageBadgesEvenWhenMuted &&
260 service.isBadgeEnabled
261 ) {
222 notificationBadge = ( 262 notificationBadge = (
223 <span> 263 <span>
224 {service.unreadDirectMessageCount > 0 && ( 264 {service.unreadDirectMessageCount > 0 && (
@@ -226,17 +266,13 @@ const styles = {
226 {service.unreadDirectMessageCount} 266 {service.unreadDirectMessageCount}
227 </span> 267 </span>
228 )} 268 )}
229 {service.unreadIndirectMessageCount > 0 269 {service.unreadIndirectMessageCount > 0 &&
230 && service.unreadDirectMessageCount === 0 270 service.unreadDirectMessageCount === 0 &&
231 && service.isIndirectMessageBadgeEnabled && ( 271 service.isIndirectMessageBadgeEnabled && (
232 <span className="tab-item__message-count is-indirect"> 272 <span className="tab-item__message-count is-indirect">•</span>
233
234 </span>
235 )} 273 )}
236 {service.isHibernating && ( 274 {service.isHibernating && (
237 <span className="tab-item__message-count hibernating"> 275 <span className="tab-item__message-count hibernating">•</span>
238
239 </span>
240 )} 276 )}
241 </span> 277 </span>
242 ); 278 );
@@ -245,7 +281,8 @@ const styles = {
245 return ( 281 return (
246 <li 282 <li
247 className={classnames({ 283 className={classnames({
248 [classes.stale]: IS_SERVICE_DEBUGGING_ENABLED && service.lostRecipeConnection, 284 [classes.stale]:
285 IS_SERVICE_DEBUGGING_ENABLED && service.lostRecipeConnection,
249 'tab-item': true, 286 'tab-item': true,
250 'is-active': service.isActive, 287 'is-active': service.isActive,
251 'has-custom-icon': service.hasCustomIcon, 288 'has-custom-icon': service.hasCustomIcon,
@@ -253,13 +290,11 @@ const styles = {
253 })} 290 })}
254 onClick={clickHandler} 291 onClick={clickHandler}
255 onContextMenu={() => menu.popup(getCurrentWindow())} 292 onContextMenu={() => menu.popup(getCurrentWindow())}
256 data-tip={`${service.name} ${shortcutIndex <= 9 ? `(${ctrlKey}+${shortcutIndex})` : ''}`} 293 data-tip={`${service.name} ${
294 shortcutIndex <= 9 ? `(${ctrlKey}+${shortcutIndex})` : ''
295 }`}
257 > 296 >
258 <img 297 <img src={service.icon} className="tab-item__icon" alt="" />
259 src={service.icon}
260 className="tab-item__icon"
261 alt=""
262 />
263 {notificationBadge} 298 {notificationBadge}
264 {IS_SERVICE_DEBUGGING_ENABLED && ( 299 {IS_SERVICE_DEBUGGING_ENABLED && (
265 <> 300 <>