keera-posture-0.1.3: src/Model/ReactiveModel/Preferences.hs
{-# LANGUAGE TemplateHaskell #-}
-- | This module holds the functions to access and modify the program
-- preferences in the reactive model.
module Model.ReactiveModel.Preferences where
-- External imports
import Data.Maybe
import qualified Hails.MVC.Model.ReactiveFields as RFs
import Hails.MVC.Model.ReactiveFields
(fieldGetter, fieldSetter, preTrue)
import Hails.MVC.Model.THFields
-- Internal imports
import Model.Model
import Model.ReactiveModel.ReactiveModelInternals
import Model.ReactiveModel.ModelEvents
-- A Field of type A lets us access a reactive field of type a from
-- a Model, and it triggers a ModelEvent
type Field a = RFs.Field a Model ModelEvent
-- | Basic settings
reactiveField "Language" [t|Maybe Language|]
reactiveField "CheckUpdates" [t|Bool|]
reactiveField "SendReports" [t|Bool|]
reactiveField "FirstRun" [t|Maybe Bool|]
-- | Settings with non-true preconditions for set functions
-- | Notification params
--
-- | Should the system notify the user?
setNotificationEnabled :: ReactiveModel -> Bool -> ReactiveModel
setNotificationEnabled rm n
-- Nothing has changed
| getNotificationEnabled rm == n = rm
-- Wrong params
| not n && st == StatusNotifying = rm
| n && isNothing cal = rm
-- Ok
| otherwise = triggerEvent rm' ev
where rm' = rm `onBasicModel` (\b -> b { notificationEnabled = n })
ev = NotificationEnabledChanged
st = status $ basicModel rm
cal = getCalibrationParams rm
-- | Determine whether notification is enabled
getNotificationEnabled :: ReactiveModel -> Bool
getNotificationEnabled = notificationEnabled . basicModel
-- | Should the icon change to notify the user?
setNotificationIconEnabled :: ReactiveModel -> Bool -> ReactiveModel
setNotificationIconEnabled rm n
-- Nothing has changed
| getNotificationIconEnabled rm == n = rm
-- Incorrect change
| noNotificationMethod nm' = triggerEvent rm ev
-- Ok
| otherwise = triggerEvent rm' ev
where rm' = rm `onBasicModel` (\b -> b { notificationMethods = nm' })
nm' = nm { notificationIconEnabled = n }
nm = notificationMethods $ basicModel rm
ev = NotificationIconEnabledChanged
-- | Determine whether icon-based notification is enabled
getNotificationIconEnabled :: ReactiveModel -> Bool
getNotificationIconEnabled = notificationIconEnabled . notificationMethods . basicModel
-- -- | Should the icon change to notify the user?
-- setNotificationBubbleEnabled :: ReactiveModel -> Bool -> ReactiveModel
-- setNotificationBubbleEnabled rm n
-- -- Nothing has changed
-- | getNotificationBubbleEnabled rm == n = rm
--
-- -- Incorrect change
-- | noNotificationMethod nm' = triggerEvent rm ev
--
-- -- Ok
-- | otherwise = triggerEvent rm' ev
-- where rm' = rm `onBasicModel` (\b -> b { notificationMethods = nm' })
-- nm' = nm { notificationBubbleEnabled = n }
-- nm = notificationMethods $ basicModel rm
-- ev = NotificationBubbleChanged
--
-- getNotificationBubbleEnabled :: ReactiveModel -> Bool
-- getNotificationBubbleEnabled = notificationBubbleEnabled . notificationMethods . basicModel
-- | Should the sound play to notify the user?
setNotificationSoundEnabled :: ReactiveModel -> Bool -> ReactiveModel
setNotificationSoundEnabled rm n
-- Nothing has changed
| getNotificationSoundEnabled rm == n = rm
-- Incorrect change
| noNotificationMethod nm' = triggerEvent rm ev
-- Ok
| otherwise = triggerEvent rm' ev
where rm' = rm `onBasicModel` (\b -> b { notificationMethods = nm' })
nm' = nm { notificationSoundEnabled = n }
nm = notificationMethods $ basicModel rm
ev = NotificationSoundEnabledChanged
-- | Determine whether sound notification is enabled
getNotificationSoundEnabled :: ReactiveModel -> Bool
getNotificationSoundEnabled = notificationSoundEnabled . notificationMethods . basicModel
-- | Should a popup window be shown to notify the user?
setNotificationOverlayEnabled :: ReactiveModel -> Bool -> ReactiveModel
setNotificationOverlayEnabled rm n
-- Nothing has changed
| getNotificationOverlayEnabled rm == n = rm
-- Incorrect change
| noNotificationMethod nm' = triggerEvent rm ev
-- Ok
| otherwise = triggerEvent rm' ev
where rm' = rm `onBasicModel` (\b -> b { notificationMethods = nm' })
nm' = nm { notificationOverlayEnabled = n }
nm = notificationMethods $ basicModel rm
ev = NotificationOverlayEnabledChanged
-- | Determine whether an overlay-window will be used to notify the user
getNotificationOverlayEnabled :: ReactiveModel -> Bool
getNotificationOverlayEnabled = notificationOverlayEnabled . notificationMethods . basicModel
-- | Change notification delay (time between detection and notification)
setNotificationDelay :: ReactiveModel -> Int -> ReactiveModel
setNotificationDelay rm n
-- Nothing has changed
| getNotificationDelay rm == n = rm
-- Incorrect change
| n < 1 = triggerEvent rm ev
-- Ok
| otherwise = triggerEvent rm' ev
where rm' = rm `onBasicModel` (\b -> b { notificationDelay = n })
ev = NotificationDelayChanged
-- | Obtain current notification delay
getNotificationDelay :: ReactiveModel -> Int
getNotificationDelay = notificationDelay . basicModel
-- | Should we notify when the user slouches?
setDetectionSlouchingEnabled :: ReactiveModel -> Bool -> ReactiveModel
setDetectionSlouchingEnabled rm n
-- Nothing has changed
| getDetectionSlouchingEnabled rm == n = rm
-- Incorrect change
| noDetectionMethod dm' = triggerEvent rm ev
-- Ok
| otherwise = triggerEvent rm' ev
where rm' = rm `onBasicModel` (\b -> b { detectionMethods = dm' })
dm' = dm { detectionSlouchingEnabled = n }
dm = detectionMethods $ basicModel rm
ev = DetectionSlouchingEnabledChanged
-- | Get the current slouching notification status
getDetectionSlouchingEnabled :: ReactiveModel -> Bool
getDetectionSlouchingEnabled = detectionSlouchingEnabled . detectionMethods . basicModel
-- | Should we notify when the user hunches?
setDetectionHunchingEnabled :: ReactiveModel -> Bool -> ReactiveModel
setDetectionHunchingEnabled rm n
-- Nothing has changed
| getDetectionHunchingEnabled rm == n = rm
-- Incorrect change
| noDetectionMethod dm' = triggerEvent rm ev
-- Ok
| otherwise = triggerEvent rm' ev
where rm' = rm `onBasicModel` (\b -> b { detectionMethods = dm' })
dm' = dm { detectionHunchingEnabled = n }
dm = detectionMethods $ basicModel rm
ev = DetectionHunchingEnabledChanged
-- | Get the current hunching notification status
getDetectionHunchingEnabled :: ReactiveModel -> Bool
getDetectionHunchingEnabled = detectionHunchingEnabled . detectionMethods . basicModel
-- Auxiliary function that should not be exported
--
-- Determine whether any notification method is enabled
noNotificationMethod :: NotificationMethods -> Bool
noNotificationMethod nm =
not $ notificationIconEnabled nm -- || notificationBubbleEnabled nm
|| notificationSoundEnabled nm || notificationOverlayEnabled nm
-- Auxiliary function that should not be exported
--
-- Determine whether any detection method is enabled
noDetectionMethod :: DetectionMethods -> Bool
noDetectionMethod nm =
not $ detectionSlouchingEnabled nm || detectionHunchingEnabled nm
-- -- | Change the camera selection
-- --
-- -- The model remains unchanged if the list is the same that the model holds
-- -- currently or if any id is negative.
-- setCameraList :: ReactiveModel -> [(Int, String)] -> ReactiveModel
-- setCameraList rm n
-- | getCameraList rm == n = rm
-- | all ((0 <=) . fst) n = triggerEvent rm ev
-- | otherwise = triggerEvent rm' ev
-- where rm' = rm `onBasicModel` (\b -> b { cameraList = n })
-- ev = CameraListChanged
--
-- getCameraList :: ReactiveModel -> [(Int, String)]
-- getCameraList = cameraList . basicModel
-- Invariant: it cannot be the case that the camera is changed
-- and the status remains set.
-- | Change the camera selection
setCamera :: ReactiveModel -> Int -> ReactiveModel
setCamera rm n
| getCamera rm == n = rm
| n < 0 = triggerEvent rm ev
| otherwise = setCameraStatus rm'' Nothing
where rm'' = triggerEvent rm' ev
rm' = rm `onBasicModel` (\b -> b { camera = n })
ev = CameraChanged
-- | Get the camera selection
getCamera :: ReactiveModel -> Int
getCamera = camera . basicModel
-- | Change the camera status
setCameraStatus :: ReactiveModel -> Maybe Bool -> ReactiveModel
setCameraStatus rm n
| getCameraStatus rm == n = rm
| otherwise = triggerEvent rm' ev
where rm' = rm `onBasicModel` (\b -> b { cameraStatus = n })
ev = CameraStatusChanged
-- | Change the camera status
getCameraStatus :: ReactiveModel -> Maybe Bool
getCameraStatus = cameraStatus . basicModel
-- | Change Calibration parameters
setCalibrationParams :: ReactiveModel -> Maybe (Int, Int, Int, Int) -> ReactiveModel
setCalibrationParams rm n
-- Nothing has changed
| getCalibrationParams rm == n = rm
-- Wrong parameters
| isJust n && (x < 0 || y < 0 || w < 0 || h < 0) = triggerEvent rm ev
-- -- It's set to nothing, so the notification cannot be enabled
| isNothing n && det = setNotificationEnabled rm'' False
-- Ok
| otherwise = rm''
where rm'' = triggerEvent rm' ev
rm' = rm `onBasicModel` (\b -> b { calibrationParams = n })
ev = CalibrationParamsChanged
det = getNotificationEnabled rm
(Just (x, y, w, h)) = n
-- | Get the current calibration parameters
getCalibrationParams :: ReactiveModel -> Maybe (Int, Int, Int, Int)
getCalibrationParams = calibrationParams . basicModel
-- | Set the correction factor to be used by the detection system
setCorrectionFactor :: ReactiveModel -> Int -> ReactiveModel
setCorrectionFactor rm n
-- Nothing has changed
| getCorrectionFactor rm == n = rm
-- Wrong parameters
| n < 0 || n > 10 = triggerEvent rm ev
-- Ok
| otherwise = triggerEvent rm' ev
where rm' = rm `onBasicModel` (\b -> b { correctionFactor = n })
ev = CorrectionFactorChanged
-- | Get the correction factor
getCorrectionFactor :: ReactiveModel -> Int
getCorrectionFactor = correctionFactor . basicModel