diff options
author | 2017-11-11 19:30:03 +0100 | |
---|---|---|
committer | 2017-11-11 19:30:03 +0100 | |
commit | 0643ceed47d4ffa3aae1ec559af584b575024947 (patch) | |
tree | 6c114cdb1d5f7aec869e8b254ed1dfb2ba03b13f /src | |
parent | Merge pull request #255 from meetfranz/feature/117-disable-gpu (diff) | |
parent | slightly reduce tab height (diff) | |
download | ferdium-app-0643ceed47d4ffa3aae1ec559af584b575024947.tar.gz ferdium-app-0643ceed47d4ffa3aae1ec559af584b575024947.tar.zst ferdium-app-0643ceed47d4ffa3aae1ec559af584b575024947.zip |
Merge pull request #252 from meetfranz/feature/mute-service
[WIP] Mute services
Diffstat (limited to 'src')
-rw-r--r-- | src/actions/app.js | 4 | ||||
-rw-r--r-- | src/actions/service.js | 3 | ||||
-rw-r--r-- | src/components/layout/Sidebar.js | 52 | ||||
-rw-r--r-- | src/components/services/content/ServiceWebview.js | 44 | ||||
-rw-r--r-- | src/components/services/content/Services.js | 3 | ||||
-rw-r--r-- | src/components/services/tabs/TabBarSortableList.js | 22 | ||||
-rw-r--r-- | src/components/services/tabs/TabItem.js | 15 | ||||
-rw-r--r-- | src/components/services/tabs/Tabbar.js | 3 | ||||
-rw-r--r-- | src/components/settings/services/EditServiceForm.js | 12 | ||||
-rw-r--r-- | src/components/settings/services/ServiceItem.js | 22 | ||||
-rw-r--r-- | src/config.js | 1 | ||||
-rw-r--r-- | src/containers/layout/AppLayoutContainer.js | 16 | ||||
-rw-r--r-- | src/containers/settings/EditServiceScreen.js | 15 | ||||
-rw-r--r-- | src/i18n/locales/en-US.json | 19 | ||||
-rw-r--r-- | src/models/Service.js | 3 | ||||
-rw-r--r-- | src/stores/AppStore.js | 27 | ||||
-rw-r--r-- | src/stores/ServicesStore.js | 19 | ||||
-rw-r--r-- | src/styles/layout.scss | 33 | ||||
-rw-r--r-- | src/styles/settings.scss | 2 | ||||
-rw-r--r-- | src/styles/tabs.scss | 8 |
20 files changed, 220 insertions, 103 deletions
diff --git a/src/actions/app.js b/src/actions/app.js index 5db4b739e..25ff9344d 100644 --- a/src/actions/app.js +++ b/src/actions/app.js | |||
@@ -20,4 +20,8 @@ export default { | |||
20 | resetUpdateStatus: {}, | 20 | resetUpdateStatus: {}, |
21 | installUpdate: {}, | 21 | installUpdate: {}, |
22 | healthCheck: {}, | 22 | healthCheck: {}, |
23 | muteApp: { | ||
24 | isMuted: PropTypes.bool.isRequired, | ||
25 | }, | ||
26 | toggleMuteApp: {}, | ||
23 | }; | 27 | }; |
diff --git a/src/actions/service.js b/src/actions/service.js index ea6ea5acc..1b918251b 100644 --- a/src/actions/service.js +++ b/src/actions/service.js | |||
@@ -71,6 +71,9 @@ export default { | |||
71 | toggleNotifications: { | 71 | toggleNotifications: { |
72 | serviceId: PropTypes.string.isRequired, | 72 | serviceId: PropTypes.string.isRequired, |
73 | }, | 73 | }, |
74 | toggleAudio: { | ||
75 | serviceId: PropTypes.string.isRequired, | ||
76 | }, | ||
74 | openDevTools: { | 77 | openDevTools: { |
75 | serviceId: PropTypes.string.isRequired, | 78 | serviceId: PropTypes.string.isRequired, |
76 | }, | 79 | }, |
diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js index 6a5c0f365..ea34e8702 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js | |||
@@ -11,16 +11,25 @@ const messages = defineMessages({ | |||
11 | id: 'sidebar.settings', | 11 | id: 'sidebar.settings', |
12 | defaultMessage: '!!!Settings', | 12 | defaultMessage: '!!!Settings', |
13 | }, | 13 | }, |
14 | addNewService: { | ||
15 | id: 'sidebar.addNewService', | ||
16 | defaultMessage: '!!!Add new service', | ||
17 | }, | ||
18 | mute: { | ||
19 | id: 'sidebar.mute', | ||
20 | defaultMessage: '!!!Disable audio', | ||
21 | }, | ||
22 | unmute: { | ||
23 | id: 'sidebar.unmute', | ||
24 | defaultMessage: '!!!Enable audio', | ||
25 | }, | ||
14 | }); | 26 | }); |
15 | 27 | ||
16 | export default class Sidebar extends Component { | 28 | export default class Sidebar extends Component { |
17 | static propTypes = { | 29 | static propTypes = { |
18 | openSettings: PropTypes.func.isRequired, | 30 | openSettings: PropTypes.func.isRequired, |
19 | isPremiumUser: PropTypes.bool, | 31 | toggleMuteApp: PropTypes.func.isRequired, |
20 | } | 32 | isAppMuted: PropTypes.bool.isRequired, |
21 | |||
22 | static defaultProps = { | ||
23 | isPremiumUser: false, | ||
24 | } | 33 | } |
25 | 34 | ||
26 | static contextTypes = { | 35 | static contextTypes = { |
@@ -40,8 +49,9 @@ export default class Sidebar extends Component { | |||
40 | } | 49 | } |
41 | 50 | ||
42 | render() { | 51 | render() { |
43 | const { openSettings, isPremiumUser } = this.props; | 52 | const { openSettings, toggleMuteApp, isAppMuted } = this.props; |
44 | const { intl } = this.context; | 53 | const { intl } = this.context; |
54 | |||
45 | return ( | 55 | return ( |
46 | <div className="sidebar"> | 56 | <div className="sidebar"> |
47 | <Tabbar | 57 | <Tabbar |
@@ -50,21 +60,25 @@ export default class Sidebar extends Component { | |||
50 | disableToolTip={() => this.disableToolTip()} | 60 | disableToolTip={() => this.disableToolTip()} |
51 | /> | 61 | /> |
52 | <button | 62 | <button |
53 | onClick={openSettings} | 63 | onClick={toggleMuteApp} |
54 | className="sidebar__settings-button" | 64 | className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`} |
65 | data-tip={`${intl.formatMessage(isAppMuted ? messages.unmute : messages.mute)} (${ctrlKey}+Shift+M)`} | ||
66 | > | ||
67 | <i className={`mdi mdi-bell${isAppMuted ? '-off' : ''}`} /> | ||
68 | </button> | ||
69 | <button | ||
70 | onClick={() => openSettings({ path: 'recipes' })} | ||
71 | className="sidebar__button sidebar__button--new-service" | ||
72 | data-tip={`${intl.formatMessage(messages.addNewService)} (${ctrlKey}+N)`} | ||
73 | > | ||
74 | <i className="mdi mdi-plus-box" /> | ||
75 | </button> | ||
76 | <button | ||
77 | onClick={() => openSettings({ path: 'app' })} | ||
78 | className="sidebar__button sidebar__button--settings" | ||
55 | data-tip={`${intl.formatMessage(messages.settings)} (${ctrlKey}+,)`} | 79 | data-tip={`${intl.formatMessage(messages.settings)} (${ctrlKey}+,)`} |
56 | > | 80 | > |
57 | {isPremiumUser && ( | 81 | <i className="mdi mdi-settings" /> |
58 | <span className="emoji"> | ||
59 | <img src="./assets/images/emoji/star.png" alt="" /> | ||
60 | </span> | ||
61 | )} | ||
62 | <img | ||
63 | src="./assets/images/logo.svg" | ||
64 | className="sidebar__logo" | ||
65 | alt="" | ||
66 | /> | ||
67 | {intl.formatMessage(messages.settings)} | ||
68 | </button> | 82 | </button> |
69 | {this.state.tooltipEnabled && ( | 83 | {this.state.tooltipEnabled && ( |
70 | <ReactTooltip place="right" type="dark" effect="solid" /> | 84 | <ReactTooltip place="right" type="dark" effect="solid" /> |
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js index a71017a6e..abbf21dee 100644 --- a/src/components/services/content/ServiceWebview.js +++ b/src/components/services/content/ServiceWebview.js | |||
@@ -16,6 +16,7 @@ export default class ServiceWebview extends Component { | |||
16 | service: PropTypes.instanceOf(ServiceModel).isRequired, | 16 | service: PropTypes.instanceOf(ServiceModel).isRequired, |
17 | setWebviewReference: PropTypes.func.isRequired, | 17 | setWebviewReference: PropTypes.func.isRequired, |
18 | reload: PropTypes.func.isRequired, | 18 | reload: PropTypes.func.isRequired, |
19 | isAppMuted: PropTypes.bool.isRequired, | ||
19 | enable: PropTypes.func.isRequired, | 20 | enable: PropTypes.func.isRequired, |
20 | }; | 21 | }; |
21 | 22 | ||
@@ -58,6 +59,7 @@ export default class ServiceWebview extends Component { | |||
58 | service, | 59 | service, |
59 | setWebviewReference, | 60 | setWebviewReference, |
60 | reload, | 61 | reload, |
62 | isAppMuted, | ||
61 | enable, | 63 | enable, |
62 | } = this.props; | 64 | } = this.props; |
63 | 65 | ||
@@ -90,31 +92,23 @@ export default class ServiceWebview extends Component { | |||
90 | enable={enable} | 92 | enable={enable} |
91 | /> | 93 | /> |
92 | )} | 94 | )} |
93 | {service.isEnabled && ( | 95 | <Webview |
94 | <div className="services__webview-wrapper"> | 96 | ref={(element) => { this.webview = element; }} |
95 | <Webview | 97 | autosize |
96 | ref={(element) => { this.webview = element; }} | 98 | src={service.url} |
97 | 99 | preload="./webview/plugin.js" | |
98 | autosize | 100 | partition={`persist:service-${service.id}`} |
99 | src={service.url} | 101 | onDidAttach={() => setWebviewReference({ |
100 | preload="./webview/plugin.js" | 102 | serviceId: service.id, |
101 | partition={`persist:service-${service.id}`} | 103 | webview: this.webview.view, |
102 | 104 | })} | |
103 | onDidAttach={() => setWebviewReference({ | 105 | onUpdateTargetUrl={this.updateTargetUrl} |
104 | serviceId: service.id, | 106 | useragent={service.userAgent} |
105 | webview: this.webview.view, | 107 | muted={isAppMuted || service.isMuted} |
106 | })} | 108 | disablewebsecurity |
107 | 109 | allowpopups | |
108 | onUpdateTargetUrl={this.updateTargetUrl} | 110 | /> |
109 | 111 | {statusBar} | |
110 | useragent={service.userAgent} | ||
111 | |||
112 | disablewebsecurity | ||
113 | allowpopups | ||
114 | /> | ||
115 | {statusBar} | ||
116 | </div> | ||
117 | )} | ||
118 | </div> | 112 | </div> |
119 | ); | 113 | ); |
120 | } | 114 | } |
diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js index 5230508f7..b1322afc2 100644 --- a/src/components/services/content/Services.js +++ b/src/components/services/content/Services.js | |||
@@ -26,6 +26,7 @@ export default class Services extends Component { | |||
26 | handleIPCMessage: PropTypes.func.isRequired, | 26 | handleIPCMessage: PropTypes.func.isRequired, |
27 | openWindow: PropTypes.func.isRequired, | 27 | openWindow: PropTypes.func.isRequired, |
28 | reload: PropTypes.func.isRequired, | 28 | reload: PropTypes.func.isRequired, |
29 | isAppMuted: PropTypes.bool.isRequired, | ||
29 | update: PropTypes.func.isRequired, | 30 | update: PropTypes.func.isRequired, |
30 | }; | 31 | }; |
31 | 32 | ||
@@ -45,6 +46,7 @@ export default class Services extends Component { | |||
45 | setWebviewReference, | 46 | setWebviewReference, |
46 | openWindow, | 47 | openWindow, |
47 | reload, | 48 | reload, |
49 | isAppMuted, | ||
48 | update, | 50 | update, |
49 | } = this.props; | 51 | } = this.props; |
50 | const { intl } = this.context; | 52 | const { intl } = this.context; |
@@ -78,6 +80,7 @@ export default class Services extends Component { | |||
78 | setWebviewReference={setWebviewReference} | 80 | setWebviewReference={setWebviewReference} |
79 | openWindow={openWindow} | 81 | openWindow={openWindow} |
80 | reload={() => reload({ serviceId: service.id })} | 82 | reload={() => reload({ serviceId: service.id })} |
83 | isAppMuted={isAppMuted} | ||
81 | enable={() => update({ | 84 | enable={() => update({ |
82 | serviceId: service.id, | 85 | serviceId: service.id, |
83 | serviceData: { | 86 | serviceData: { |
diff --git a/src/components/services/tabs/TabBarSortableList.js b/src/components/services/tabs/TabBarSortableList.js index 3340cbbbb..2daf55676 100644 --- a/src/components/services/tabs/TabBarSortableList.js +++ b/src/components/services/tabs/TabBarSortableList.js | |||
@@ -2,17 +2,8 @@ import React, { Component } from 'react'; | |||
2 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | 2 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; |
3 | import PropTypes from 'prop-types'; | 3 | import PropTypes from 'prop-types'; |
4 | import { SortableContainer } from 'react-sortable-hoc'; | 4 | import { SortableContainer } from 'react-sortable-hoc'; |
5 | import { defineMessages, intlShape } from 'react-intl'; | ||
6 | 5 | ||
7 | import TabItem from './TabItem'; | 6 | import TabItem from './TabItem'; |
8 | import { ctrlKey } from '../../../environment'; | ||
9 | |||
10 | const messages = defineMessages({ | ||
11 | addNewService: { | ||
12 | id: 'sidebar.addNewService', | ||
13 | defaultMessage: '!!!Add new service', | ||
14 | }, | ||
15 | }); | ||
16 | 7 | ||
17 | @observer | 8 | @observer |
18 | class TabBarSortableList extends Component { | 9 | class TabBarSortableList extends Component { |
@@ -22,29 +13,25 @@ class TabBarSortableList extends Component { | |||
22 | openSettings: PropTypes.func.isRequired, | 13 | openSettings: PropTypes.func.isRequired, |
23 | reload: PropTypes.func.isRequired, | 14 | reload: PropTypes.func.isRequired, |
24 | toggleNotifications: PropTypes.func.isRequired, | 15 | toggleNotifications: PropTypes.func.isRequired, |
16 | toggleAudio: PropTypes.func.isRequired, | ||
25 | deleteService: PropTypes.func.isRequired, | 17 | deleteService: PropTypes.func.isRequired, |
26 | disableService: PropTypes.func.isRequired, | 18 | disableService: PropTypes.func.isRequired, |
27 | enableService: PropTypes.func.isRequired, | 19 | enableService: PropTypes.func.isRequired, |
28 | } | 20 | } |
29 | 21 | ||
30 | static contextTypes = { | ||
31 | intl: intlShape, | ||
32 | }; | ||
33 | |||
34 | render() { | 22 | render() { |
35 | const { | 23 | const { |
36 | services, | 24 | services, |
37 | setActive, | 25 | setActive, |
38 | reload, | 26 | reload, |
39 | toggleNotifications, | 27 | toggleNotifications, |
28 | toggleAudio, | ||
40 | deleteService, | 29 | deleteService, |
41 | disableService, | 30 | disableService, |
42 | enableService, | 31 | enableService, |
43 | openSettings, | 32 | openSettings, |
44 | } = this.props; | 33 | } = this.props; |
45 | 34 | ||
46 | const { intl } = this.context; | ||
47 | |||
48 | return ( | 35 | return ( |
49 | <ul | 36 | <ul |
50 | className="tabs" | 37 | className="tabs" |
@@ -58,13 +45,14 @@ class TabBarSortableList extends Component { | |||
58 | shortcutIndex={index + 1} | 45 | shortcutIndex={index + 1} |
59 | reload={() => reload({ serviceId: service.id })} | 46 | reload={() => reload({ serviceId: service.id })} |
60 | toggleNotifications={() => toggleNotifications({ serviceId: service.id })} | 47 | toggleNotifications={() => toggleNotifications({ serviceId: service.id })} |
48 | toggleAudio={() => toggleAudio({ serviceId: service.id })} | ||
61 | deleteService={() => deleteService({ serviceId: service.id })} | 49 | deleteService={() => deleteService({ serviceId: service.id })} |
62 | disableService={() => disableService({ serviceId: service.id })} | 50 | disableService={() => disableService({ serviceId: service.id })} |
63 | enableService={() => enableService({ serviceId: service.id })} | 51 | enableService={() => enableService({ serviceId: service.id })} |
64 | openSettings={openSettings} | 52 | openSettings={openSettings} |
65 | /> | 53 | /> |
66 | ))} | 54 | ))} |
67 | <li> | 55 | {/* <li> |
68 | <button | 56 | <button |
69 | className="sidebar__add-service" | 57 | className="sidebar__add-service" |
70 | onClick={() => openSettings({ path: 'recipes' })} | 58 | onClick={() => openSettings({ path: 'recipes' })} |
@@ -72,7 +60,7 @@ class TabBarSortableList extends Component { | |||
72 | > | 60 | > |
73 | <span className="mdi mdi-plus" /> | 61 | <span className="mdi mdi-plus" /> |
74 | </button> | 62 | </button> |
75 | </li> | 63 | </li> */} |
76 | </ul> | 64 | </ul> |
77 | ); | 65 | ); |
78 | } | 66 | } |
diff --git a/src/components/services/tabs/TabItem.js b/src/components/services/tabs/TabItem.js index 638e17d95..a7136c43f 100644 --- a/src/components/services/tabs/TabItem.js +++ b/src/components/services/tabs/TabItem.js | |||
@@ -28,6 +28,14 @@ const messages = defineMessages({ | |||
28 | id: 'tabs.item.enableNotification', | 28 | id: 'tabs.item.enableNotification', |
29 | defaultMessage: '!!!Enable notifications', | 29 | defaultMessage: '!!!Enable notifications', |
30 | }, | 30 | }, |
31 | disableAudio: { | ||
32 | id: 'tabs.item.disableAudio', | ||
33 | defaultMessage: '!!!Disable audio', | ||
34 | }, | ||
35 | enableAudio: { | ||
36 | id: 'tabs.item.enableAudio', | ||
37 | defaultMessage: '!!!Enable audio', | ||
38 | }, | ||
31 | disableService: { | 39 | disableService: { |
32 | id: 'tabs.item.disableService', | 40 | id: 'tabs.item.disableService', |
33 | defaultMessage: '!!!Disable Service', | 41 | defaultMessage: '!!!Disable Service', |
@@ -50,6 +58,7 @@ class TabItem extends Component { | |||
50 | shortcutIndex: PropTypes.number.isRequired, | 58 | shortcutIndex: PropTypes.number.isRequired, |
51 | reload: PropTypes.func.isRequired, | 59 | reload: PropTypes.func.isRequired, |
52 | toggleNotifications: PropTypes.func.isRequired, | 60 | toggleNotifications: PropTypes.func.isRequired, |
61 | toggleAudio: PropTypes.func.isRequired, | ||
53 | openSettings: PropTypes.func.isRequired, | 62 | openSettings: PropTypes.func.isRequired, |
54 | deleteService: PropTypes.func.isRequired, | 63 | deleteService: PropTypes.func.isRequired, |
55 | disableService: PropTypes.func.isRequired, | 64 | disableService: PropTypes.func.isRequired, |
@@ -67,6 +76,7 @@ class TabItem extends Component { | |||
67 | shortcutIndex, | 76 | shortcutIndex, |
68 | reload, | 77 | reload, |
69 | toggleNotifications, | 78 | toggleNotifications, |
79 | toggleAudio, | ||
70 | deleteService, | 80 | deleteService, |
71 | disableService, | 81 | disableService, |
72 | enableService, | 82 | enableService, |
@@ -96,6 +106,11 @@ class TabItem extends Component { | |||
96 | : intl.formatMessage(messages.enableNotifications), | 106 | : intl.formatMessage(messages.enableNotifications), |
97 | click: () => toggleNotifications(), | 107 | click: () => toggleNotifications(), |
98 | }, { | 108 | }, { |
109 | label: service.isMuted | ||
110 | ? intl.formatMessage(messages.enableAudio) | ||
111 | : intl.formatMessage(messages.disableAudio), | ||
112 | click: () => toggleAudio(), | ||
113 | }, { | ||
99 | label: intl.formatMessage(service.isEnabled ? messages.disableService : messages.enableService), | 114 | label: intl.formatMessage(service.isEnabled ? messages.disableService : messages.enableService), |
100 | click: () => (service.isEnabled ? disableService() : enableService()), | 115 | click: () => (service.isEnabled ? disableService() : enableService()), |
101 | }, { | 116 | }, { |
diff --git a/src/components/services/tabs/Tabbar.js b/src/components/services/tabs/Tabbar.js index 5f63aed16..fd4325107 100644 --- a/src/components/services/tabs/Tabbar.js +++ b/src/components/services/tabs/Tabbar.js | |||
@@ -15,6 +15,7 @@ export default class TabBar extends Component { | |||
15 | reorder: PropTypes.func.isRequired, | 15 | reorder: PropTypes.func.isRequired, |
16 | reload: PropTypes.func.isRequired, | 16 | reload: PropTypes.func.isRequired, |
17 | toggleNotifications: PropTypes.func.isRequired, | 17 | toggleNotifications: PropTypes.func.isRequired, |
18 | toggleAudio: PropTypes.func.isRequired, | ||
18 | deleteService: PropTypes.func.isRequired, | 19 | deleteService: PropTypes.func.isRequired, |
19 | updateService: PropTypes.func.isRequired, | 20 | updateService: PropTypes.func.isRequired, |
20 | } | 21 | } |
@@ -59,6 +60,7 @@ export default class TabBar extends Component { | |||
59 | disableToolTip, | 60 | disableToolTip, |
60 | reload, | 61 | reload, |
61 | toggleNotifications, | 62 | toggleNotifications, |
63 | toggleAudio, | ||
62 | deleteService, | 64 | deleteService, |
63 | } = this.props; | 65 | } = this.props; |
64 | 66 | ||
@@ -71,6 +73,7 @@ export default class TabBar extends Component { | |||
71 | onSortStart={disableToolTip} | 73 | onSortStart={disableToolTip} |
72 | reload={reload} | 74 | reload={reload} |
73 | toggleNotifications={toggleNotifications} | 75 | toggleNotifications={toggleNotifications} |
76 | toggleAudio={toggleAudio} | ||
74 | deleteService={deleteService} | 77 | deleteService={deleteService} |
75 | disableService={args => this.disableService(args)} | 78 | disableService={args => this.disableService(args)} |
76 | enableService={args => this.enableService(args)} | 79 | enableService={args => this.enableService(args)} |
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js index 9b359a78e..753781507 100644 --- a/src/components/settings/services/EditServiceForm.js +++ b/src/components/settings/services/EditServiceForm.js | |||
@@ -61,7 +61,11 @@ const messages = defineMessages({ | |||
61 | }, | 61 | }, |
62 | indirectMessageInfo: { | 62 | indirectMessageInfo: { |
63 | id: 'settings.service.form.indirectMessageInfo', | 63 | id: 'settings.service.form.indirectMessageInfo', |
64 | defaultMessage: '!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...', // eslint-disable-line | 64 | defaultMessage: '!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...', |
65 | }, | ||
66 | isMutedInfo: { | ||
67 | id: 'settings.service.form.isMutedInfo', | ||
68 | defaultMessage: '!!!When disabled, all notification sounds and audio playback are muted', | ||
65 | }, | 69 | }, |
66 | }); | 70 | }); |
67 | 71 | ||
@@ -231,11 +235,15 @@ export default class EditServiceForm extends Component { | |||
231 | {recipe.hasIndirectMessages && ( | 235 | {recipe.hasIndirectMessages && ( |
232 | <div> | 236 | <div> |
233 | <Toggle field={form.$('isIndirectMessageBadgeEnabled')} /> | 237 | <Toggle field={form.$('isIndirectMessageBadgeEnabled')} /> |
234 | <p className="settings__indirect-message-help"> | 238 | <p className="settings__help"> |
235 | {intl.formatMessage(messages.indirectMessageInfo)} | 239 | {intl.formatMessage(messages.indirectMessageInfo)} |
236 | </p> | 240 | </p> |
237 | </div> | 241 | </div> |
238 | )} | 242 | )} |
243 | <Toggle field={form.$('isMuted')} /> | ||
244 | <p className="settings__help"> | ||
245 | {intl.formatMessage(messages.isMutedInfo)} | ||
246 | </p> | ||
239 | <Toggle field={form.$('isEnabled')} /> | 247 | <Toggle field={form.$('isEnabled')} /> |
240 | </div> | 248 | </div> |
241 | {recipe.message && ( | 249 | {recipe.message && ( |
diff --git a/src/components/settings/services/ServiceItem.js b/src/components/settings/services/ServiceItem.js index 20d8581d0..9743315b0 100644 --- a/src/components/settings/services/ServiceItem.js +++ b/src/components/settings/services/ServiceItem.js | |||
@@ -16,6 +16,10 @@ const messages = defineMessages({ | |||
16 | id: 'settings.services.tooltip.notificationsDisabled', | 16 | id: 'settings.services.tooltip.notificationsDisabled', |
17 | defaultMessage: '!!!Notifications are disabled', | 17 | defaultMessage: '!!!Notifications are disabled', |
18 | }, | 18 | }, |
19 | tooltipIsMuted: { | ||
20 | id: 'settings.services.tooltip.isMuted', | ||
21 | defaultMessage: '!!!All sounds are muted', | ||
22 | }, | ||
19 | }); | 23 | }); |
20 | 24 | ||
21 | @observer | 25 | @observer |
@@ -66,6 +70,17 @@ export default class ServiceItem extends Component { | |||
66 | className="service-table__column-info" | 70 | className="service-table__column-info" |
67 | onClick={goToServiceForm} | 71 | onClick={goToServiceForm} |
68 | > | 72 | > |
73 | {service.isMuted && ( | ||
74 | <span | ||
75 | className="mdi mdi-bell-off" | ||
76 | data-tip={intl.formatMessage(messages.tooltipIsMuted)} | ||
77 | /> | ||
78 | )} | ||
79 | </td> | ||
80 | <td | ||
81 | className="service-table__column-info" | ||
82 | onClick={goToServiceForm} | ||
83 | > | ||
69 | {!service.isEnabled && ( | 84 | {!service.isEnabled && ( |
70 | <span | 85 | <span |
71 | className="mdi mdi-power" | 86 | className="mdi mdi-power" |
@@ -85,13 +100,6 @@ export default class ServiceItem extends Component { | |||
85 | )} | 100 | )} |
86 | <ReactTooltip place="top" type="dark" effect="solid" /> | 101 | <ReactTooltip place="top" type="dark" effect="solid" /> |
87 | </td> | 102 | </td> |
88 | {/* <td className="service-table__column-action"> | ||
89 | <input | ||
90 | type="checkbox" | ||
91 | onChange={toggleAction} | ||
92 | checked={service.isEnabled} | ||
93 | /> | ||
94 | </td> */} | ||
95 | </tr> | 103 | </tr> |
96 | ); | 104 | ); |
97 | } | 105 | } |
diff --git a/src/config.js b/src/config.js index 868c0cdf1..1627993f5 100644 --- a/src/config.js +++ b/src/config.js | |||
@@ -13,4 +13,5 @@ export const DEFAULT_APP_SETTINGS = { | |||
13 | showDisabledServices: true, | 13 | showDisabledServices: true, |
14 | locale: 'en-US', | 14 | locale: 'en-US', |
15 | beta: false, | 15 | beta: false, |
16 | isAppMuted: false, | ||
16 | }; | 17 | }; |
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index cd3251082..8e5b3d2ed 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js | |||
@@ -7,7 +7,7 @@ import RecipesStore from '../../stores/RecipesStore'; | |||
7 | import ServicesStore from '../../stores/ServicesStore'; | 7 | import ServicesStore from '../../stores/ServicesStore'; |
8 | import UIStore from '../../stores/UIStore'; | 8 | import UIStore from '../../stores/UIStore'; |
9 | import NewsStore from '../../stores/NewsStore'; | 9 | import NewsStore from '../../stores/NewsStore'; |
10 | import UserStore from '../../stores/UserStore'; | 10 | import SettingsStore from '../../stores/SettingsStore'; |
11 | import RequestStore from '../../stores/RequestStore'; | 11 | import RequestStore from '../../stores/RequestStore'; |
12 | import GlobalErrorStore from '../../stores/GlobalErrorStore'; | 12 | import GlobalErrorStore from '../../stores/GlobalErrorStore'; |
13 | 13 | ||
@@ -29,8 +29,8 @@ export default class AppLayoutContainer extends Component { | |||
29 | services, | 29 | services, |
30 | ui, | 30 | ui, |
31 | news, | 31 | news, |
32 | settings, | ||
32 | globalError, | 33 | globalError, |
33 | user, | ||
34 | requests, | 34 | requests, |
35 | } = this.props.stores; | 35 | } = this.props.stores; |
36 | 36 | ||
@@ -43,6 +43,7 @@ export default class AppLayoutContainer extends Component { | |||
43 | reorder, | 43 | reorder, |
44 | reload, | 44 | reload, |
45 | toggleNotifications, | 45 | toggleNotifications, |
46 | toggleAudio, | ||
46 | deleteService, | 47 | deleteService, |
47 | updateService, | 48 | updateService, |
48 | } = this.props.actions.service; | 49 | } = this.props.actions.service; |
@@ -53,6 +54,7 @@ export default class AppLayoutContainer extends Component { | |||
53 | 54 | ||
54 | const { | 55 | const { |
55 | installUpdate, | 56 | installUpdate, |
57 | toggleMuteApp, | ||
56 | } = this.props.actions.app; | 58 | } = this.props.actions.app; |
57 | 59 | ||
58 | const { | 60 | const { |
@@ -78,14 +80,16 @@ export default class AppLayoutContainer extends Component { | |||
78 | <Sidebar | 80 | <Sidebar |
79 | services={services.allDisplayed} | 81 | services={services.allDisplayed} |
80 | setActive={setActive} | 82 | setActive={setActive} |
83 | isAppMuted={Boolean(app.isSystemMuted) || Boolean(settings.all.isMuted)} | ||
81 | openSettings={openSettings} | 84 | openSettings={openSettings} |
82 | closeSettings={closeSettings} | 85 | closeSettings={closeSettings} |
83 | reorder={reorder} | 86 | reorder={reorder} |
84 | reload={reload} | 87 | reload={reload} |
85 | toggleNotifications={toggleNotifications} | 88 | toggleNotifications={toggleNotifications} |
89 | toggleAudio={toggleAudio} | ||
86 | deleteService={deleteService} | 90 | deleteService={deleteService} |
87 | updateService={updateService} | 91 | updateService={updateService} |
88 | isPremiumUser={user.data.isPremium} | 92 | toggleMuteApp={toggleMuteApp} |
89 | /> | 93 | /> |
90 | ); | 94 | ); |
91 | 95 | ||
@@ -96,6 +100,7 @@ export default class AppLayoutContainer extends Component { | |||
96 | setWebviewReference={setWebviewReference} | 100 | setWebviewReference={setWebviewReference} |
97 | openWindow={openWindow} | 101 | openWindow={openWindow} |
98 | reload={reload} | 102 | reload={reload} |
103 | isAppMuted={settings.all.isMuted || false} | ||
99 | update={updateService} | 104 | update={updateService} |
100 | /> | 105 | /> |
101 | ); | 106 | ); |
@@ -130,7 +135,7 @@ AppLayoutContainer.wrappedComponent.propTypes = { | |||
130 | app: PropTypes.instanceOf(AppStore).isRequired, | 135 | app: PropTypes.instanceOf(AppStore).isRequired, |
131 | ui: PropTypes.instanceOf(UIStore).isRequired, | 136 | ui: PropTypes.instanceOf(UIStore).isRequired, |
132 | news: PropTypes.instanceOf(NewsStore).isRequired, | 137 | news: PropTypes.instanceOf(NewsStore).isRequired, |
133 | user: PropTypes.instanceOf(UserStore).isRequired, | 138 | settings: PropTypes.instanceOf(SettingsStore).isRequired, |
134 | requests: PropTypes.instanceOf(RequestStore).isRequired, | 139 | requests: PropTypes.instanceOf(RequestStore).isRequired, |
135 | globalError: PropTypes.instanceOf(GlobalErrorStore).isRequired, | 140 | globalError: PropTypes.instanceOf(GlobalErrorStore).isRequired, |
136 | }).isRequired, | 141 | }).isRequired, |
@@ -139,6 +144,7 @@ AppLayoutContainer.wrappedComponent.propTypes = { | |||
139 | setActive: PropTypes.func.isRequired, | 144 | setActive: PropTypes.func.isRequired, |
140 | reload: PropTypes.func.isRequired, | 145 | reload: PropTypes.func.isRequired, |
141 | toggleNotifications: PropTypes.func.isRequired, | 146 | toggleNotifications: PropTypes.func.isRequired, |
147 | toggleAudio: PropTypes.func.isRequired, | ||
142 | handleIPCMessage: PropTypes.func.isRequired, | 148 | handleIPCMessage: PropTypes.func.isRequired, |
143 | setWebviewReference: PropTypes.func.isRequired, | 149 | setWebviewReference: PropTypes.func.isRequired, |
144 | openWindow: PropTypes.func.isRequired, | 150 | openWindow: PropTypes.func.isRequired, |
@@ -156,7 +162,7 @@ AppLayoutContainer.wrappedComponent.propTypes = { | |||
156 | }).isRequired, | 162 | }).isRequired, |
157 | app: PropTypes.shape({ | 163 | app: PropTypes.shape({ |
158 | installUpdate: PropTypes.func.isRequired, | 164 | installUpdate: PropTypes.func.isRequired, |
159 | healthCheck: PropTypes.func.isRequired, | 165 | toggleMuteApp: PropTypes.func.isRequired, |
160 | }).isRequired, | 166 | }).isRequired, |
161 | requests: PropTypes.shape({ | 167 | requests: PropTypes.shape({ |
162 | retryRequiredRequests: PropTypes.func.isRequired, | 168 | retryRequiredRequests: PropTypes.func.isRequired, |
diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.js index 6c614b941..191ef447b 100644 --- a/src/containers/settings/EditServiceScreen.js +++ b/src/containers/settings/EditServiceScreen.js | |||
@@ -9,7 +9,6 @@ import ServicesStore from '../../stores/ServicesStore'; | |||
9 | import Form from '../../lib/Form'; | 9 | import Form from '../../lib/Form'; |
10 | import { gaPage } from '../../lib/analytics'; | 10 | import { gaPage } from '../../lib/analytics'; |
11 | 11 | ||
12 | |||
13 | import ServiceError from '../../components/settings/services/ServiceError'; | 12 | import ServiceError from '../../components/settings/services/ServiceError'; |
14 | import EditServiceForm from '../../components/settings/services/EditServiceForm'; | 13 | import EditServiceForm from '../../components/settings/services/EditServiceForm'; |
15 | import { required, url, oneRequired } from '../../helpers/validation-helpers'; | 14 | import { required, url, oneRequired } from '../../helpers/validation-helpers'; |
@@ -27,6 +26,10 @@ const messages = defineMessages({ | |||
27 | id: 'settings.service.form.enableNotification', | 26 | id: 'settings.service.form.enableNotification', |
28 | defaultMessage: '!!!Enable Notifications', | 27 | defaultMessage: '!!!Enable Notifications', |
29 | }, | 28 | }, |
29 | enableAudio: { | ||
30 | id: 'settings.service.form.enableAudio', | ||
31 | defaultMessage: '!!!Enable audio', | ||
32 | }, | ||
30 | team: { | 33 | team: { |
31 | id: 'settings.service.form.team', | 34 | id: 'settings.service.form.team', |
32 | defaultMessage: '!!!Team', | 35 | defaultMessage: '!!!Team', |
@@ -51,11 +54,14 @@ export default class EditServiceScreen extends Component { | |||
51 | gaPage('Settings/Service/Edit'); | 54 | gaPage('Settings/Service/Edit'); |
52 | } | 55 | } |
53 | 56 | ||
54 | onSubmit(serviceData) { | 57 | onSubmit(data) { |
55 | const { action } = this.props.router.params; | 58 | const { action } = this.props.router.params; |
56 | const { recipes, services } = this.props.stores; | 59 | const { recipes, services } = this.props.stores; |
57 | const { createService, updateService } = this.props.actions.service; | 60 | const { createService, updateService } = this.props.actions.service; |
58 | 61 | ||
62 | const serviceData = data; | ||
63 | serviceData.isMuted = !serviceData.isMuted; | ||
64 | |||
59 | if (action === 'edit') { | 65 | if (action === 'edit') { |
60 | updateService({ serviceId: services.activeSettings.id, serviceData }); | 66 | updateService({ serviceId: services.activeSettings.id, serviceData }); |
61 | } else { | 67 | } else { |
@@ -82,6 +88,11 @@ export default class EditServiceScreen extends Component { | |||
82 | value: service.isNotificationEnabled, | 88 | value: service.isNotificationEnabled, |
83 | default: true, | 89 | default: true, |
84 | }, | 90 | }, |
91 | isMuted: { | ||
92 | label: intl.formatMessage(messages.enableAudio), | ||
93 | value: !service.isMuted, | ||
94 | default: true, | ||
95 | }, | ||
85 | }, | 96 | }, |
86 | }; | 97 | }; |
87 | 98 | ||
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 505e19f0f..fd8ba0fef 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json | |||
@@ -61,6 +61,8 @@ | |||
61 | "infobar.requiredRequestsFailed": "Could not load services and user information", | 61 | "infobar.requiredRequestsFailed": "Could not load services and user information", |
62 | "sidebar.settings": "Settings", | 62 | "sidebar.settings": "Settings", |
63 | "sidebar.addNewService": "Add new service", | 63 | "sidebar.addNewService": "Add new service", |
64 | "sidebar.mute": "Disable audio", | ||
65 | "sidebar.unmute": "Enable audio", | ||
64 | "services.welcome": "Welcome to Franz", | 66 | "services.welcome": "Welcome to Franz", |
65 | "services.getStarted": "Get started", | 67 | "services.getStarted": "Get started", |
66 | "settings.account.headline": "Account", | 68 | "settings.account.headline": "Account", |
@@ -106,11 +108,20 @@ | |||
106 | "settings.service.form.customUrlPremiumInfo": "To add self hosted services, you need a Franz Premium Supporter Account.", | 108 | "settings.service.form.customUrlPremiumInfo": "To add self hosted services, you need a Franz Premium Supporter Account.", |
107 | "settings.service.form.customUrlUpgradeAccount": "Upgrade your account", | 109 | "settings.service.form.customUrlUpgradeAccount": "Upgrade your account", |
108 | "settings.service.form.indirectMessageInfo": "You will be notified about all new messages in a channel, not just @username, @channel, @here, ...", | 110 | "settings.service.form.indirectMessageInfo": "You will be notified about all new messages in a channel, not just @username, @channel, @here, ...", |
111 | "settings.service.form.name": "Name", | ||
112 | "settings.service.form.enableService": "Enable service", | ||
113 | "settings.service.form.enableNotification": "Enable notifications", | ||
114 | "settings.service.form.team": "Team", | ||
115 | "settings.service.form.customUrl": "Custom server", | ||
116 | "settings.service.form.indirectMessages": "Show message badge for all new messages", | ||
117 | "settings.service.form.enableAudio": "Enable audio", | ||
118 | "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", | ||
109 | "settings.service.error.headline": "Error", | 119 | "settings.service.error.headline": "Error", |
110 | "settings.service.error.goBack": "Back to services", | 120 | "settings.service.error.goBack": "Back to services", |
111 | "settings.service.error.message": "Could not load service recipe.", | 121 | "settings.service.error.message": "Could not load service recipe.", |
112 | "settings.services.tooltip.isDisabled": "Service is disabled", | 122 | "settings.services.tooltip.isDisabled": "Service is disabled", |
113 | "settings.services.tooltip.notificationsDisabled": "Notifications are disabled", | 123 | "settings.services.tooltip.notificationsDisabled": "Notifications are disabled", |
124 | "settings.services.tooltip.isMuted": "All sounds are muted", | ||
114 | "settings.services.headline": "Your services", | 125 | "settings.services.headline": "Your services", |
115 | "settings.services.noServicesAdded": "You haven't added any services yet.", | 126 | "settings.services.noServicesAdded": "You haven't added any services yet.", |
116 | "settings.services.discoverServices": "Discover services", | 127 | "settings.services.discoverServices": "Discover services", |
@@ -135,12 +146,6 @@ | |||
135 | "settings.app.form.showDisabledServices": "Display disabled services tabs", | 146 | "settings.app.form.showDisabledServices": "Display disabled services tabs", |
136 | "settings.app.form.beta": "Include beta versions", | 147 | "settings.app.form.beta": "Include beta versions", |
137 | "settings.app.currentVersion": "Current version:", | 148 | "settings.app.currentVersion": "Current version:", |
138 | "settings.service.form.name": "Name", | ||
139 | "settings.service.form.enableService": "Enable service", | ||
140 | "settings.service.form.enableNotification": "Enable notifications", | ||
141 | "settings.service.form.team": "Team", | ||
142 | "settings.service.form.customUrl": "Custom server", | ||
143 | "settings.service.form.indirectMessages": "Show message badge for all new messages", | ||
144 | "settings.user.form.firstname": "Firstname", | 149 | "settings.user.form.firstname": "Firstname", |
145 | "settings.user.form.lastname": "Lastname", | 150 | "settings.user.form.lastname": "Lastname", |
146 | "settings.user.form.email": "Email", | 151 | "settings.user.form.email": "Email", |
@@ -166,6 +171,8 @@ | |||
166 | "tabs.item.edit": "Edit", | 171 | "tabs.item.edit": "Edit", |
167 | "tabs.item.disableNotifications": "Disable notifications", | 172 | "tabs.item.disableNotifications": "Disable notifications", |
168 | "tabs.item.enableNotification": "Enable notifications", | 173 | "tabs.item.enableNotification": "Enable notifications", |
174 | "tabs.item.disableAudio": "Disable audio", | ||
175 | "tabs.item.enableAudio": "Enable audio", | ||
169 | "tabs.item.disableService": "Disable service", | 176 | "tabs.item.disableService": "Disable service", |
170 | "tabs.item.enableService": "Enable service", | 177 | "tabs.item.enableService": "Enable service", |
171 | "tabs.item.deleteService": "Delete service", | 178 | "tabs.item.deleteService": "Delete service", |
diff --git a/src/models/Service.js b/src/models/Service.js index dc53807f7..eb68493fe 100644 --- a/src/models/Service.js +++ b/src/models/Service.js | |||
@@ -18,6 +18,7 @@ export default class Service { | |||
18 | 18 | ||
19 | @observable order = 99; | 19 | @observable order = 99; |
20 | @observable isEnabled = true; | 20 | @observable isEnabled = true; |
21 | @observable isMuted = false; | ||
21 | @observable team = ''; | 22 | @observable team = ''; |
22 | @observable customUrl = ''; | 23 | @observable customUrl = ''; |
23 | @observable isNotificationEnabled = true; | 24 | @observable isNotificationEnabled = true; |
@@ -54,6 +55,8 @@ export default class Service { | |||
54 | this.isIndirectMessageBadgeEnabled = data.isIndirectMessageBadgeEnabled !== undefined | 55 | this.isIndirectMessageBadgeEnabled = data.isIndirectMessageBadgeEnabled !== undefined |
55 | ? data.isIndirectMessageBadgeEnabled : this.isIndirectMessageBadgeEnabled; | 56 | ? data.isIndirectMessageBadgeEnabled : this.isIndirectMessageBadgeEnabled; |
56 | 57 | ||
58 | this.isMuted = data.isMuted !== undefined ? data.isMuted : this.isMuted; | ||
59 | |||
57 | this.recipe = recipe; | 60 | this.recipe = recipe; |
58 | } | 61 | } |
59 | 62 | ||
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index e9faad911..14bdab094 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -2,7 +2,7 @@ import { remote, ipcRenderer, shell } from 'electron'; | |||
2 | import { action, observable } from 'mobx'; | 2 | import { action, observable } from 'mobx'; |
3 | import moment from 'moment'; | 3 | import moment from 'moment'; |
4 | import key from 'keymaster'; | 4 | import key from 'keymaster'; |
5 | // import path from 'path'; | 5 | import { getDoNotDisturb } from '@meetfranz/electron-notification-state'; |
6 | import idleTimer from '@paulcbetts/system-idle-time'; | 6 | import idleTimer from '@paulcbetts/system-idle-time'; |
7 | import AutoLaunch from 'auto-launch'; | 7 | import AutoLaunch from 'auto-launch'; |
8 | 8 | ||
@@ -45,6 +45,8 @@ export default class AppStore extends Store { | |||
45 | miner = null; | 45 | miner = null; |
46 | @observable minerHashrate = 0.0; | 46 | @observable minerHashrate = 0.0; |
47 | 47 | ||
48 | @observable isSystemMuted = false; | ||
49 | |||
48 | constructor(...args) { | 50 | constructor(...args) { |
49 | super(...args); | 51 | super(...args); |
50 | 52 | ||
@@ -57,6 +59,8 @@ export default class AppStore extends Store { | |||
57 | this.actions.app.installUpdate.listen(this._installUpdate.bind(this)); | 59 | this.actions.app.installUpdate.listen(this._installUpdate.bind(this)); |
58 | this.actions.app.resetUpdateStatus.listen(this._resetUpdateStatus.bind(this)); | 60 | this.actions.app.resetUpdateStatus.listen(this._resetUpdateStatus.bind(this)); |
59 | this.actions.app.healthCheck.listen(this._healthCheck.bind(this)); | 61 | this.actions.app.healthCheck.listen(this._healthCheck.bind(this)); |
62 | this.actions.app.muteApp.listen(this._muteApp.bind(this)); | ||
63 | this.actions.app.toggleMuteApp.listen(this._toggleMuteApp.bind(this)); | ||
60 | 64 | ||
61 | this.registerReactions([ | 65 | this.registerReactions([ |
62 | this._offlineCheck.bind(this), | 66 | this._offlineCheck.bind(this), |
@@ -81,6 +85,11 @@ export default class AppStore extends Store { | |||
81 | // Needs to be delayed a bit | 85 | // Needs to be delayed a bit |
82 | this._autoStart(); | 86 | this._autoStart(); |
83 | 87 | ||
88 | // Check if system is muted | ||
89 | // There are no events to subscribe so we need to poll everey 5s | ||
90 | this._systemDND(); | ||
91 | setInterval(() => this._systemDND(), 5000); | ||
92 | |||
84 | // Check for updates once every 4 hours | 93 | // Check for updates once every 4 hours |
85 | setInterval(() => this._checkForUpdates(), CHECK_INTERVAL); | 94 | setInterval(() => this._checkForUpdates(), CHECK_INTERVAL); |
86 | // Check for an update in 30s (need a delay to prevent Squirrel Installer lock file issues) | 95 | // Check for an update in 30s (need a delay to prevent Squirrel Installer lock file issues) |
@@ -202,6 +211,18 @@ export default class AppStore extends Store { | |||
202 | this.healthCheckRequest.execute(); | 211 | this.healthCheckRequest.execute(); |
203 | } | 212 | } |
204 | 213 | ||
214 | @action _muteApp({ isMuted }) { | ||
215 | this.actions.settings.update({ | ||
216 | settings: { | ||
217 | isMuted, | ||
218 | }, | ||
219 | }); | ||
220 | } | ||
221 | |||
222 | @action _toggleMuteApp() { | ||
223 | this._muteApp({ isMuted: !this.stores.settings.all.isMuted }); | ||
224 | } | ||
225 | |||
205 | // Reactions | 226 | // Reactions |
206 | _offlineCheck() { | 227 | _offlineCheck() { |
207 | if (!this.isOnline) { | 228 | if (!this.isOnline) { |
@@ -297,4 +318,8 @@ export default class AppStore extends Store { | |||
297 | async _checkAutoStart() { | 318 | async _checkAutoStart() { |
298 | return autoLauncher.isEnabled() || false; | 319 | return autoLauncher.isEnabled() || false; |
299 | } | 320 | } |
321 | |||
322 | _systemDND() { | ||
323 | this.isSystemMuted = getDoNotDisturb(); | ||
324 | } | ||
300 | } | 325 | } |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 6c41c22cf..269cd1526 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -48,6 +48,7 @@ export default class ServicesStore extends Store { | |||
48 | this.actions.service.reloadUpdatedServices.listen(this._reloadUpdatedServices.bind(this)); | 48 | this.actions.service.reloadUpdatedServices.listen(this._reloadUpdatedServices.bind(this)); |
49 | this.actions.service.reorder.listen(this._reorder.bind(this)); | 49 | this.actions.service.reorder.listen(this._reorder.bind(this)); |
50 | this.actions.service.toggleNotifications.listen(this._toggleNotifications.bind(this)); | 50 | this.actions.service.toggleNotifications.listen(this._toggleNotifications.bind(this)); |
51 | this.actions.service.toggleAudio.listen(this._toggleAudio.bind(this)); | ||
51 | this.actions.service.openDevTools.listen(this._openDevTools.bind(this)); | 52 | this.actions.service.openDevTools.listen(this._openDevTools.bind(this)); |
52 | this.actions.service.openDevToolsForActiveService.listen(this._openDevToolsForActiveService.bind(this)); | 53 | this.actions.service.openDevToolsForActiveService.listen(this._openDevToolsForActiveService.bind(this)); |
53 | 54 | ||
@@ -293,7 +294,7 @@ export default class ServicesStore extends Store { | |||
293 | }); | 294 | }); |
294 | } else if (channel === 'notification') { | 295 | } else if (channel === 'notification') { |
295 | const options = args[0].options; | 296 | const options = args[0].options; |
296 | if (service.recipe.hasNotificationSound) { | 297 | if (service.recipe.hasNotificationSound || service.isMuted) { |
297 | Object.assign(options, { | 298 | Object.assign(options, { |
298 | silent: true, | 299 | silent: true, |
299 | }); | 300 | }); |
@@ -405,11 +406,25 @@ export default class ServicesStore extends Store { | |||
405 | @action _toggleNotifications({ serviceId }) { | 406 | @action _toggleNotifications({ serviceId }) { |
406 | const service = this.one(serviceId); | 407 | const service = this.one(serviceId); |
407 | 408 | ||
409 | this.actions.service.updateService({ | ||
410 | serviceId, | ||
411 | serviceData: { | ||
412 | isNotificationEnabled: !service.isNotificationEnabled, | ||
413 | }, | ||
414 | redirect: false, | ||
415 | }); | ||
416 | } | ||
417 | |||
418 | @action _toggleAudio({ serviceId }) { | ||
419 | const service = this.one(serviceId); | ||
420 | |||
408 | service.isNotificationEnabled = !service.isNotificationEnabled; | 421 | service.isNotificationEnabled = !service.isNotificationEnabled; |
409 | 422 | ||
410 | this.actions.service.updateService({ | 423 | this.actions.service.updateService({ |
411 | serviceId, | 424 | serviceId, |
412 | serviceData: service, | 425 | serviceData: { |
426 | isMuted: !service.isMuted, | ||
427 | }, | ||
413 | redirect: false, | 428 | redirect: false, |
414 | }); | 429 | }); |
415 | } | 430 | } |
diff --git a/src/styles/layout.scss b/src/styles/layout.scss index d87df2684..afdd7dec7 100644 --- a/src/styles/layout.scss +++ b/src/styles/layout.scss | |||
@@ -42,6 +42,7 @@ html { | |||
42 | z-index: 200; | 42 | z-index: 200; |
43 | text-align: center; | 43 | text-align: center; |
44 | color: $theme-text-color; | 44 | color: $theme-text-color; |
45 | padding-bottom: 10px; | ||
45 | 46 | ||
46 | .sidebar__add-service { | 47 | .sidebar__add-service { |
47 | width: 32px; | 48 | width: 32px; |
@@ -52,26 +53,28 @@ html { | |||
52 | color: $theme-gray-light; | 53 | color: $theme-gray-light; |
53 | } | 54 | } |
54 | 55 | ||
55 | .sidebar__settings-button { | 56 | .sidebar__button { |
56 | height: auto; | 57 | width: $theme-sidebar-width; |
57 | padding: 20px 0; | 58 | padding: 7px 0; |
58 | font-size: 12px; | 59 | font-size: 24px; |
59 | position: relative; | 60 | position: relative; |
61 | color: $theme-gray-light; | ||
60 | 62 | ||
61 | .emoji { | 63 | &:hover { |
62 | position: absolute; | 64 | color: darken($theme-gray-light, 10%); |
63 | top: 18px; | 65 | } |
64 | right: 12px; | ||
65 | 66 | ||
66 | img { | 67 | &:active { |
67 | width: 18px; | 68 | color: lighten($theme-gray-light, 10%); |
68 | } | ||
69 | } | 69 | } |
70 | } | ||
71 | 70 | ||
72 | .sidebar__logo { | 71 | &.is-muted { |
73 | width: 40px; | 72 | color: $theme-brand-primary; |
74 | height: auto; | 73 | } |
74 | |||
75 | &--new-service { | ||
76 | padding-bottom: 6px; | ||
77 | } | ||
75 | } | 78 | } |
76 | 79 | ||
77 | & > div { | 80 | & > div { |
diff --git a/src/styles/settings.scss b/src/styles/settings.scss index 9b19deb4e..48d12a807 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss | |||
@@ -169,7 +169,7 @@ | |||
169 | } | 169 | } |
170 | } | 170 | } |
171 | 171 | ||
172 | .settings__indirect-message-help { | 172 | .settings__help { |
173 | margin: -10px 0 20px 55px;; | 173 | margin: -10px 0 20px 55px;; |
174 | font-size: 12px; | 174 | font-size: 12px; |
175 | color: $theme-gray-light; | 175 | color: $theme-gray-light; |
diff --git a/src/styles/tabs.scss b/src/styles/tabs.scss index 3e5904d2c..8347de3b4 100644 --- a/src/styles/tabs.scss +++ b/src/styles/tabs.scss | |||
@@ -20,7 +20,7 @@ | |||
20 | align-items: center; | 20 | align-items: center; |
21 | position: relative; | 21 | position: relative; |
22 | width: $theme-sidebar-width; | 22 | width: $theme-sidebar-width; |
23 | height: $theme-sidebar-width; | 23 | height: 65px; |
24 | min-height: 50px; | 24 | min-height: 50px; |
25 | transition: background $theme-transition-time; | 25 | transition: background $theme-transition-time; |
26 | 26 | ||
@@ -47,6 +47,12 @@ | |||
47 | } | 47 | } |
48 | } | 48 | } |
49 | 49 | ||
50 | &:active { | ||
51 | .tab-item__icon { | ||
52 | opacity: 0.7; | ||
53 | } | ||
54 | } | ||
55 | |||
50 | .tab-item__icon { | 56 | .tab-item__icon { |
51 | width: 30px; | 57 | width: 30px; |
52 | height: auto; | 58 | height: auto; |