import moment , { Moment } from "moment" ; import { PowerMonitor } from "electron" ; import { Settings , NotificationType } from "../../types/settings" ; import { BreakTime } from "../../types/breaks" ; import { IpcChannel } from "../../types/ipc" ; import { sendIpc } from "./ipc" ; import { getSettings } from "./store" ; import { buildTray } from "./tray" ; import { showNotification } from "./notifications" ; import { createBreakWindows } from "./windows" ; let powerMonitor ; let breakTime = null ; let havingBreak = false ; let postponedCount = 0 ; let idleStart = null ; let lockStart = null ; let lastTick = null ; export function getBreakTime ( ) { return breakTime ; } export function getBreakLength ( ) { const settings = getSettings ( ) ; return settings . breakLength ; } function zeroPad ( n ) { const nStr = String ( n ) ; return nStr . length === 1 ? `0${ nStr }` : nStr ; } function getSeconds ( date ) { return ( date . getHours ( ) * 60 * 60 + date . getMinutes ( ) * 60 + date . getSeconds ( ) || 1 ) ; } function getIdleResetSeconds ( ) { const settings = getSettings ( ) ; return getSeconds ( new Date ( settings . idleResetLength ) ) ; } function getBreakSeconds ( ) { const settings = getSettings ( ) ; return getSeconds ( new Date ( settings . breakFrequency ) ) ; } function createIdleNotification ( ) { const settings = getSettings ( ) ; if ( ! settings . idleResetEnabled || idleStart === null ) { return ; } let idleSeconds = Number ( ( ( + new Date ( ) - + idleStart ) / 1000 ) . toFixed ( 0 ) ) ; let idleMinutes = 0 ; let idleHours = 0 ; if ( idleSeconds > 60 ) { idleMinutes = Math . floor ( idleSeconds / 60 ) ; idleSeconds -= idleMinutes * 60 ; } if ( idleMinutes > 60 ) { idleHours = Math . floor ( idleMinutes / 60 ) ; idleMinutes -= idleHours * 60 ; } if ( settings . idleResetNotification ) { showNotification ( "Break countdown reset" , `Idle for ${ zeroPad ( idleHours ) }:${ zeroPad ( idleMinutes ) }:${ zeroPad ( idleSeconds ) }` ) ; } } export function createBreak ( isPostpone = false ) { const settings = getSettings ( ) ; if ( idleStart ) { createIdleNotification ( ) ; idleStart = null ; postponedCount = 0 ; } const freq = new Date ( isPostpone ? settings . postponeLength : settings . breakFrequency ) ; breakTime = moment ( ) . add ( freq . getHours ( ) , "hours" ) . add ( freq . getMinutes ( ) , "minutes" ) . add ( freq . getSeconds ( ) , "seconds" ) ; buildTray ( ) ; } export function endPopupBreak ( ) { if ( breakTime !== null && breakTime < moment ( ) ) { breakTime = null ; havingBreak = false ; postponedCount = 0 ; } } export function getAllowPostpone ( ) { const settings = getSettings ( ) ; return ! settings . postponeLimit || postponedCount < settings . postponeLimit ; } export function postponeBreak ( ) { postponedCount ++ ; havingBreak = false ; createBreak ( true ) ; } function doBreak ( ) { havingBreak = true ; const settings = getSettings ( ) ; if ( settings . notificationType === NotificationType . Notification ) { showNotification ( settings . breakTitle , settings . breakMessage ) ; if ( settings . gongEnabled ) { sendIpc ( IpcChannel . GongStartPlay ) ; } havingBreak = false ; createBreak ( ) ; } if ( settings . notificationType === NotificationType . Popup ) { createBreakWindows ( ) ; } } interface Days { 0 : boolean ; 1 : boolean ; 2 : boolean ; 3 : boolean ; 4 : boolean ; 5 : boolean ; 6 : boolean ; } export function checkInWorkingHours ( ) { const settings = getSettings ( ) ; if ( ! settings . workingHoursEnabled ) { return true ; } const now = moment ( ) ; const days = { 0 : settings . workingHoursSunday , 1 : settings . workingHoursMonday , 2 : settings . workingHoursTuesday , 3 : settings . workingHoursWednesday , 4 : settings . workingHoursThursday , 5 : settings . workingHoursFriday , 6 : settings . workingHoursSaturday , } ; const isWorkingDay = days [ now . day ( ) as keyof Days ] ; if ( ! isWorkingDay ) { return false ; } let hoursFrom = new Date ( settings . workingHoursFrom ) ; let hoursTo = new Date ( settings . workingHoursTo ) ; hoursFrom = moment ( ) . set ( "hours" , hoursFrom . getHours ( ) ) . set ( "minutes" , hoursFrom . getMinutes ( ) ) . set ( "seconds" , 0 ) ; hoursTo = moment ( ) . set ( "hours" , hoursTo . getHours ( ) ) . set ( "minutes" , hoursTo . getMinutes ( ) ) . set ( "seconds" , 0 ) ; if ( now < hoursFrom ) { return false ; } if ( now > hoursTo ) { return false ; } return true ; } enum IdleState { Active = "active" , Idle = "idle" , Locked = "locked" , Unknown = "unknown" } export function checkIdle ( ) { const settings = getSettings ( ) ; const state = powerMonitor . getSystemIdleState ( getIdleResetSeconds ( ) ) as IdleState ; if ( state === IdleState . Locked ) { if ( ! lockStart ) { lockStart = new Date ( ) ; return false ; } else { const lockSeconds = Number ( ( ( + new Date ( ) - + lockStart ) / 1000 ) . toFixed ( 0 ) ) ; return lockSeconds > getIdleResetSeconds ( ) ; } } lockStart = null ; if ( ! settings . idleResetEnabled ) { return false ; } return state === IdleState . Idle ; } function checkShouldHaveBreak ( ) { const settings = getSettings ( ) ; const inWorkingHours = checkInWorkingHours ( ) ; const idle = checkIdle ( ) ; return ! havingBreak && settings . breaksEnabled && inWorkingHours && ! idle ; } function checkBreak ( ) { const now = moment ( ) ; if ( breakTime !== null && now > breakTime ) { doBreak ( ) ; } } export function startBreakNow ( ) { breakTime = moment ( ) ; } function tick ( ) { try { const shouldHaveBreak = checkShouldHaveBreak ( ) ; const secondsSinceLastTick = lastTick ? Math . abs ( + new Date ( ) - + lastTick ) / 1000 : 0 ; const breakSeconds = getBreakSeconds ( ) ; const lockSeconds = lockStart && Math . abs ( + new Date ( ) - + lockStart ) / 1000 ; if ( lockStart && lockSeconds !== null && lockSeconds > breakSeconds ) { idleStart = null ; lockStart = null ; } else if ( secondsSinceLastTick > breakSeconds ) { lockStart = null ; breakTime = null ; } else if ( secondsSinceLastTick > getIdleResetSeconds ( ) ) { if ( ! idleStart ) { lockStart = null ; idleStart = lastTick ; } createBreak ( ) ; } if ( ! shouldHaveBreak && ! havingBreak && breakTime ) { if ( checkIdle ( ) ) { idleStart = new Date ( ) ; } breakTime = null ; buildTray ( ) ; return ; } if ( shouldHaveBreak && ! breakTime ) { createBreak ( ) ; return ; } if ( shouldHaveBreak ) { checkBreak ( ) ; } } finally { lastTick = new Date ( ) ; } } let tickInterval ; export function initBreaks ( ) { powerMonitor = require ( "electron" ) . powerMonitor ; const settings = getSettings ( ) ; if ( settings . breaksEnabled ) { createBreak ( ) ; } if ( tickInterval ) { clearInterval ( tickInterval ) ; } tickInterval = setInterval ( tick , 1000 ) ; }