1
1
import * as ConfigUtil from './config-util' ;
2
-
2
+ import { ipcRenderer } from 'electron' ;
3
+ import schedule from 'node-schedule' ;
3
4
type SettingName = 'showNotification' | 'silent' | 'flashTaskbarOnMessage' ;
4
5
5
6
export interface DNDSettings {
@@ -13,6 +14,10 @@ interface Toggle {
13
14
newSettings : DNDSettings ;
14
15
}
15
16
17
+ /* Node-schedule job instance accepts time parameter and schedules to turn off DND
18
+ and pops a toast that DND has ended. Cancel a pre-existing job before scheduling a new one. */
19
+ let job : schedule . Job = null ;
20
+
16
21
export function toggle ( ) : Toggle {
17
22
const dnd = ! ConfigUtil . getConfigItem ( 'dnd' , false ) ;
18
23
const dndSettingList : SettingName [ ] = [ 'showNotification' , 'silent' ] ;
@@ -37,6 +42,10 @@ export function toggle(): Toggle {
37
42
ConfigUtil . setConfigItem ( 'dndPreviousSettings' , oldSettings ) ;
38
43
} else {
39
44
newSettings = ConfigUtil . getConfigItem ( 'dndPreviousSettings' ) ;
45
+ ConfigUtil . setConfigItem ( 'dndSwitchOff' , null ) ;
46
+ if ( job !== null ) {
47
+ job . cancel ( ) ;
48
+ }
40
49
}
41
50
42
51
for ( const settingName of dndSettingList ) {
@@ -46,3 +55,125 @@ export function toggle(): Toggle {
46
55
ConfigUtil . setConfigItem ( 'dnd' , dnd ) ;
47
56
return { dnd, newSettings} ;
48
57
}
58
+
59
+ /* Create the DND menu and closed it when focussed out. */
60
+ export const makeMenu = ( ) : void => {
61
+ const actionsContainer = document . querySelector ( '#actions-container' ) ;
62
+ const dndExist = document . querySelectorAll ( '.dnd-menu' ) ;
63
+ if ( dndExist . length === 0 ) {
64
+ const dndMenu = document . createElement ( 'ul' ) ;
65
+ dndMenu . className = 'dnd-menu' ;
66
+ const dndOptions : { [ key : string ] : string } = {
67
+ '30 Minutes' : 'thirty_min' ,
68
+ '1 Hour' : 'one_hr' ,
69
+ '6 Hours' : 'six_hr' ,
70
+ '12 Hours' : 'twelve_hr' ,
71
+ 'Until I Resume' : 'custom'
72
+ } ;
73
+
74
+ Object . keys ( dndOptions ) . forEach ( key => {
75
+ const opt = document . createElement ( 'li' ) ;
76
+ opt . className = 'dnd-time-btn' ;
77
+ opt . innerHTML = key ;
78
+ opt . id = dndOptions [ key ] ;
79
+ opt . addEventListener ( 'click' , ( ) => {
80
+ configureDND ( opt , dndMenu ) ;
81
+ } , false ) ;
82
+ dndMenu . append ( opt ) ;
83
+ } ) ;
84
+ actionsContainer . append ( dndMenu ) ;
85
+
86
+ const dndMenuFocusOut = ( event : Event ) => {
87
+ console . log ( event ) ;
88
+ if ( ( event . target as HTMLLIElement ) . innerHTML !== 'notifications' ) {
89
+ dndMenu . remove ( ) ;
90
+ document . removeEventListener ( 'click' , dndMenuFocusOut ) ;
91
+ }
92
+ } ;
93
+
94
+ document . addEventListener ( 'keydown' , event => {
95
+ if ( event . key === 'Escape' ) {
96
+ dndMenu . remove ( ) ;
97
+ document . removeEventListener ( 'click' , dndMenuFocusOut ) ;
98
+ }
99
+ } ) ;
100
+ document . addEventListener ( 'click' , dndMenuFocusOut ) ;
101
+ }
102
+ } ;
103
+
104
+ /* Configure DND as per user's selected option and pops a toast showing dnd switch off time. */
105
+ const configureDND = ( opt : HTMLLIElement , dndMenu : HTMLUListElement ) : void => {
106
+ let dndOffTime ;
107
+ dndOffTime = new Date ( ) ;
108
+ const optionElement = document . querySelector ( '#' + opt . id ) ;
109
+ dndMenu . style . height = '75px' ;
110
+ optionElement . className = 'dnd-options-btn' ;
111
+ switch ( opt . id ) {
112
+ case 'thirty_min' :
113
+ dndOffTime . setMinutes ( dndOffTime . getMinutes ( ) + 30 ) ;
114
+ break ;
115
+ case 'one_hr' :
116
+ dndOffTime . setMinutes ( dndOffTime . getMinutes ( ) + 60 ) ;
117
+ break ;
118
+ case 'six_hr' :
119
+ dndOffTime . setMinutes ( dndOffTime . getMinutes ( ) + 360 ) ;
120
+ break ;
121
+ case 'twelve_hr' :
122
+ dndOffTime . setMinutes ( dndOffTime . getMinutes ( ) + 720 ) ;
123
+ break ;
124
+ default :
125
+ dndOffTime = null ;
126
+ break ;
127
+ }
128
+
129
+ ConfigUtil . setConfigItem ( 'dndSwitchOff' , dndOffTime ) ;
130
+
131
+ dndMenu . remove ( ) ;
132
+ showDNDTimeLeft ( ) ;
133
+ setDNDTimer ( ) ;
134
+ const state = toggle ( ) ;
135
+ ipcRenderer . send ( 'forward-message' , 'toggle-dnd' , state . dnd , state . newSettings ) ;
136
+ } ;
137
+
138
+ /* Fetch DND switch off time and toggle DND off if the time has elapsed. */
139
+ export const setDNDTimer = ( ) : void => {
140
+ const dbTime = ConfigUtil . getConfigItem ( 'dndSwitchOff' ) ;
141
+ if ( dbTime !== null ) {
142
+ const time = new Date ( dbTime ) ;
143
+ // Handle the case when user closes the app before switch off time and stars it after the time has elapsed.
144
+ if ( time < new Date ( ) ) {
145
+ toggle ( ) ;
146
+ return ;
147
+ }
148
+
149
+ if ( job !== null ) {
150
+ job . cancel ( ) ;
151
+ }
152
+
153
+ job = schedule . scheduleJob ( time , ( ) => {
154
+ ConfigUtil . setConfigItem ( 'dndSwitchOff' , null ) ;
155
+ const state = toggle ( ) ;
156
+ ipcRenderer . send ( 'forward-message' , 'toggle-dnd' , state . dnd , state . newSettings ) ;
157
+ showToast ( 'DND has ended' ) ;
158
+ } ) ;
159
+ }
160
+ } ;
161
+
162
+ /* Show a toast with the clock time when DND will go off. */
163
+ export const showDNDTimeLeft = ( ) : void => {
164
+ const check = ConfigUtil . getConfigItem ( 'dndSwitchOff' ) ;
165
+ if ( check !== null ) {
166
+ const dbTime = new Date ( check ) ;
167
+ const timeLeft = `DND goes off at ${ dbTime . getHours ( ) } : ${ ( dbTime . getMinutes ( ) < 10 ? ( `0${ dbTime . getMinutes ( ) } ` ) : dbTime . getMinutes ( ) ) } ` ;
168
+ showToast ( timeLeft ) ;
169
+ }
170
+ } ;
171
+
172
+ export const showToast = ( t : string ) : void => {
173
+ const actionsContainer = document . querySelector ( '#actions-container' ) ;
174
+ const toast = document . createElement ( 'p' ) ;
175
+ toast . className = 'toast' ;
176
+ toast . innerHTML = t ;
177
+ actionsContainer . append ( toast ) ;
178
+ setTimeout ( ( ) => toast . remove ( ) , 4000 ) ;
179
+ } ;
0 commit comments