From 969eda02a66050cf4518ddfa657e86d1d6d8b6c3 Mon Sep 17 00:00:00 2001 From: Markus Hatvan Date: Tue, 10 Aug 2021 19:04:54 +0200 Subject: 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 --- .../services/content/ConnectionLostBanner.js | 36 ++-- src/components/services/tabs/TabItem.js | 193 ++++++++++++--------- 2 files changed, 129 insertions(+), 100 deletions(-) (limited to 'src/components/services') diff --git a/src/components/services/content/ConnectionLostBanner.js b/src/components/services/content/ConnectionLostBanner.js index 0b9d3122c..343ddf8b4 100644 --- a/src/components/services/content/ConnectionLostBanner.js +++ b/src/components/services/content/ConnectionLostBanner.js @@ -5,9 +5,7 @@ import injectSheet from 'react-jss'; import { Icon } from '@meetfranz/ui'; import { intlShape, defineMessages } from 'react-intl'; -import { - mdiAlert, -} from '@mdi/js'; +import { mdiAlert } from '@mdi/js'; import { LIVE_API_FERDI_WEBSITE } from '../../../config'; // import { Button } from '@meetfranz/forms'; @@ -26,7 +24,13 @@ const messages = defineMessages({ }, }); -const styles = (theme) => ({ +let buttonTransition = 'none'; + +if (window.matchMedia('(prefers-reduced-motion: no-preference)')) { + buttonTransition = 'opacity 0.25s'; +} + +const styles = theme => ({ root: { background: theme.colorBackground, borderRadius: theme.borderRadius, @@ -47,7 +51,7 @@ const styles = (theme) => ({ opacity: 0.7, }, button: { - transition: 'opacity 0.25s', + transition: buttonTransition, color: theme.colorText, border: [1, 'solid', theme.colorText], borderRadius: theme.borderRadiusSmall, @@ -65,13 +69,14 @@ const styles = (theme) => ({ }, }); -@injectSheet(styles) @observer +@injectSheet(styles) +@observer class ConnectionLostBanner extends Component { static propTypes = { classes: PropTypes.object.isRequired, name: PropTypes.string.isRequired, reload: PropTypes.func.isRequired, - } + }; static contextTypes = { intl: intlShape, @@ -80,20 +85,13 @@ class ConnectionLostBanner extends Component { inputRef = React.createRef(); render() { - const { - classes, - name, - reload, - } = this.props; + const { classes, name, reload } = this.props; const { intl } = this.context; return (
- +

{intl.formatMessage(messages.text, { name })}
@@ -104,11 +102,7 @@ class ConnectionLostBanner extends Component { {intl.formatMessage(messages.moreInformation)}

-
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 @@ -import { - Menu, dialog, app, getCurrentWindow, -} from '@electron/remote'; +import { Menu, dialog, app, getCurrentWindow } from '@electron/remote'; import React, { Component } from 'react'; import { defineMessages, intlShape } from 'react-intl'; import PropTypes from 'prop-types'; @@ -14,7 +12,9 @@ import { observable, autorun } from 'mobx'; import ServiceModel from '../../../models/Service'; import { ctrlKey, cmdKey } from '../../../environment'; -const IS_SERVICE_DEBUGGING_ENABLED = (localStorage.getItem('debug') || '').includes('Ferdi:Service'); +const IS_SERVICE_DEBUGGING_ENABLED = ( + localStorage.getItem('debug') || '' +).includes('Ferdi:Service'); const messages = defineMessages({ reload: { @@ -63,10 +63,21 @@ const messages = defineMessages({ }, confirmDeleteService: { id: 'tabs.item.confirmDeleteService', - defaultMessage: '!!!Do you really want to delete the {serviceName} service?', + defaultMessage: + '!!!Do you really want to delete the {serviceName} service?', }, }); +let pollIndicatorTransition = 'none'; +let polledTransition = 'none'; +let pollAnsweredTransition = 'none'; + +if (window.matchMedia('(prefers-reduced-motion: no-preference)')) { + pollIndicatorTransition = 'background 0.5s'; + polledTransition = 'background 0.1s'; + pollAnsweredTransition = 'background 0.1s'; +} + const styles = { pollIndicator: { position: 'absolute', @@ -75,7 +86,7 @@ const styles = { height: 10, borderRadius: 5, background: 'gray', - transition: 'background 0.5s', + transition: pollIndicatorTransition, }, pollIndicatorPoll: { left: 2, @@ -85,18 +96,20 @@ const styles = { }, polled: { background: 'yellow !important', - transition: 'background 0.1s', + transition: polledTransition, }, pollAnswered: { background: 'green !important', - transition: 'background 0.1s', + transition: pollAnsweredTransition, }, stale: { background: 'red !important', }, }; -@injectSheet(styles) @observer class TabItem extends Component { +@injectSheet(styles) +@observer +class TabItem extends Component { static propTypes = { classes: PropTypes.object.isRequired, service: PropTypes.instanceOf(ServiceModel).isRequired, @@ -131,13 +144,17 @@ const styles = { if (Date.now() - service.lastPoll < ms('0.2s')) { this.isPolled = true; - setTimeout(() => { this.isPolled = false; }, ms('1s')); + setTimeout(() => { + this.isPolled = false; + }, ms('1s')); } if (Date.now() - service.lastPollAnswer < ms('0.2s')) { this.isPollAnswered = true; - setTimeout(() => { this.isPollAnswered = false; }, ms('1s')); + setTimeout(() => { + this.isPollAnswered = false; + }, ms('1s')); } }); } @@ -163,62 +180,85 @@ const styles = { } = this.props; const { intl } = this.context; - const menuTemplate = [{ - label: service.name || service.recipe.name, - enabled: false, - }, { - type: 'separator', - }, { - label: intl.formatMessage(messages.reload), - click: reload, - accelerator: `${cmdKey}+R`, - }, { - label: intl.formatMessage(messages.edit), - click: () => openSettings({ - path: `services/edit/${service.id}`, - }), - }, { - type: 'separator', - }, { - label: service.isNotificationEnabled - ? intl.formatMessage(messages.disableNotifications) - : intl.formatMessage(messages.enableNotifications), - click: () => toggleNotifications(), - }, { - label: service.isMuted - ? intl.formatMessage(messages.enableAudio) - : intl.formatMessage(messages.disableAudio), - click: () => toggleAudio(), - }, { - label: intl.formatMessage(service.isEnabled ? messages.disableService : messages.enableService), - click: () => (service.isEnabled ? disableService() : enableService()), - }, { - label: intl.formatMessage(service.isHibernating ? messages.wakeUpService : messages.hibernateService), - click: () => (service.isHibernating ? wakeUpService() : hibernateService()), - enabled: service.canHibernate, - }, { - type: 'separator', - }, { - label: intl.formatMessage(messages.deleteService), - click: () => { - const selection = dialog.showMessageBoxSync(app.mainWindow, { - type: 'question', - message: intl.formatMessage(messages.deleteService), - detail: intl.formatMessage(messages.confirmDeleteService, { serviceName: service.name || service.recipe.name }), - buttons: [ - 'Yes', - 'No', - ], - }); - if (selection === 0) { - deleteService(); - } + const menuTemplate = [ + { + label: service.name || service.recipe.name, + enabled: false, + }, + { + type: 'separator', + }, + { + label: intl.formatMessage(messages.reload), + click: reload, + accelerator: `${cmdKey}+R`, + }, + { + label: intl.formatMessage(messages.edit), + click: () => + openSettings({ + path: `services/edit/${service.id}`, + }), + }, + { + type: 'separator', }, - }]; + { + label: service.isNotificationEnabled + ? intl.formatMessage(messages.disableNotifications) + : intl.formatMessage(messages.enableNotifications), + click: () => toggleNotifications(), + }, + { + label: service.isMuted + ? intl.formatMessage(messages.enableAudio) + : intl.formatMessage(messages.disableAudio), + click: () => toggleAudio(), + }, + { + label: intl.formatMessage( + service.isEnabled ? messages.disableService : messages.enableService, + ), + click: () => (service.isEnabled ? disableService() : enableService()), + }, + { + label: intl.formatMessage( + service.isHibernating + ? messages.wakeUpService + : messages.hibernateService, + ), + click: () => + (service.isHibernating ? wakeUpService() : hibernateService()), + enabled: service.canHibernate, + }, + { + type: 'separator', + }, + { + label: intl.formatMessage(messages.deleteService), + click: () => { + const selection = dialog.showMessageBoxSync(app.mainWindow, { + type: 'question', + message: intl.formatMessage(messages.deleteService), + detail: intl.formatMessage(messages.confirmDeleteService, { + serviceName: service.name || service.recipe.name, + }), + buttons: ['Yes', 'No'], + }); + if (selection === 0) { + deleteService(); + } + }, + }, + ]; const menu = Menu.buildFromTemplate(menuTemplate); let notificationBadge = null; - if ((showMessageBadgeWhenMutedSetting || service.isNotificationEnabled) && showMessageBadgesEvenWhenMuted && service.isBadgeEnabled) { + if ( + (showMessageBadgeWhenMutedSetting || service.isNotificationEnabled) && + showMessageBadgesEvenWhenMuted && + service.isBadgeEnabled + ) { notificationBadge = ( {service.unreadDirectMessageCount > 0 && ( @@ -226,17 +266,13 @@ const styles = { {service.unreadDirectMessageCount} )} - {service.unreadIndirectMessageCount > 0 - && service.unreadDirectMessageCount === 0 - && service.isIndirectMessageBadgeEnabled && ( - - • - + {service.unreadIndirectMessageCount > 0 && + service.unreadDirectMessageCount === 0 && + service.isIndirectMessageBadgeEnabled && ( + )} {service.isHibernating && ( - - • - + )} ); @@ -245,7 +281,8 @@ const styles = { return (
  • menu.popup(getCurrentWindow())} - data-tip={`${service.name} ${shortcutIndex <= 9 ? `(${ctrlKey}+${shortcutIndex})` : ''}`} + data-tip={`${service.name} ${ + shortcutIndex <= 9 ? `(${ctrlKey}+${shortcutIndex})` : '' + }`} > - + {notificationBadge} {IS_SERVICE_DEBUGGING_ENABLED && ( <> -- cgit v1.2.3-70-g09d2