{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE BangPatterns #-}

{- |
Module      : RsiBreak.Widget.Clockdown
Copyright   : (c) Ruben Astudillo, 2023
License     : BSD-2
Maintainer  : ruben.astud@gmail.com

Main composite of the the application.
-}
module RsiBreak.Widget.Clockdown (
    ClockModel (ClockModel),
    handleEvent,
    buildUI,
) where

import Control.Lens (ALens', lens, makeLensesFor)
import Data.String (IsString (fromString))
import Data.Text (Text)
import Data.Time (NominalDiffTime, defaultTimeLocale, formatTime)
import Monomer
import RsiBreak.Widget.Settings qualified as Settings
import RsiBreak.Model.Settings qualified as Settings
import RsiBreak.Widget.Timer qualified as Timer

greenBgStyle, blueBgStyle :: StyleState
greenBgStyle :: StyleState
greenBgStyle = StyleState
forall a. Monoid a => a
mempty{_sstBgColor :: Maybe Color
_sstBgColor = Color -> Maybe Color
forall a. a -> Maybe a
Just (Int -> Int -> Int -> Double -> Color
Color Int
0 Int
128 Int
0 Double
1)}
blueBgStyle :: StyleState
blueBgStyle = StyleState
forall a. Monoid a => a
mempty{_sstBgColor :: Maybe Color
_sstBgColor = Color -> Maybe Color
forall a. a -> Maybe a
Just (Int -> Int -> Int -> Double -> Color
Color Int
0 Int
0 Int
128 Double
1)}

data ClockModel = ClockModel
    { ClockModel -> Text
_cmClock :: Text
    , ClockModel -> TimerState
_cmTimer :: Timer.TimerState
    , ClockModel -> TimerSetting
_cmSettings :: Settings.TimerSetting
    }
    deriving (ClockModel -> ClockModel -> Bool
(ClockModel -> ClockModel -> Bool)
-> (ClockModel -> ClockModel -> Bool) -> Eq ClockModel
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ClockModel -> ClockModel -> Bool
== :: ClockModel -> ClockModel -> Bool
$c/= :: ClockModel -> ClockModel -> Bool
/= :: ClockModel -> ClockModel -> Bool
Eq)

$(makeLensesFor [("_cmClock", "cmClock"), ("_cmSettings", "cmSettings")] ''ClockModel)

data ClockEvent = ClockUpdate NominalDiffTime | ClockCancelTimer

mainCounter :: Text
mainCounter :: Text
mainCounter = Text
"MainCounter"

mainCounterKey :: WidgetKey
mainCounterKey :: WidgetKey
mainCounterKey = Text -> WidgetKey
WidgetKey Text
mainCounter

buildUI :: UIBuilder ClockModel ClockEvent
buildUI :: UIBuilder ClockModel ClockEvent
buildUI WidgetEnv ClockModel ClockEvent
_wenv (ClockModel Text
_ TimerState
timer TimerSetting
_) =
    [WidgetNode ClockModel ClockEvent]
-> WidgetNode ClockModel ClockEvent
forall (t :: * -> *) s e.
Traversable t =>
t (WidgetNode s e) -> WidgetNode s e
vstack
        [ Text -> WidgetNode ClockModel ClockEvent
forall s e. Text -> WidgetNode s e
label Text
"Rsi break!"
        , ALens' ClockModel Text
-> [TextFieldCfg ClockModel ClockEvent]
-> WidgetNode ClockModel ClockEvent
forall e s.
WidgetEvent e =>
ALens' s Text -> [TextFieldCfg s e] -> WidgetNode s e
textField_ ALens' ClockModel Text
Lens' ClockModel Text
cmClock [TextFieldCfg ClockModel ClockEvent
forall t. CmbReadOnly t => t
readOnly] WidgetNode ClockModel ClockEvent
-> [StyleState] -> WidgetNode ClockModel ClockEvent
forall t. CmbStyleBasic t => t -> [StyleState] -> t
`styleBasic` [TimerState -> StyleState
countdownStyle TimerState
timer]
        , WidgetNode ClockModel ClockEvent
forall s e. WidgetNode s e
spacer
        , WidgetType
-> ALens' ClockModel TimerSetting
-> UIBuilder TimerSetting TimerSettingEvent
-> EventHandler
     TimerSetting TimerSettingEvent ClockModel ClockEvent
-> WidgetNode ClockModel ClockEvent
forall s e ep sp.
(CompositeModel s, CompositeEvent e, CompositeEvent ep,
 CompParentModel sp) =>
WidgetType
-> ALens' sp s
-> UIBuilder s e
-> EventHandler s e sp ep
-> WidgetNode sp ep
composite WidgetType
"settings-parameters" ALens' ClockModel TimerSetting
Lens' ClockModel TimerSetting
cmSettings UIBuilder TimerSetting TimerSettingEvent
Settings.buildUI (ClockEvent
-> EventHandler
     TimerSetting TimerSettingEvent ClockModel ClockEvent
forall ep sp.
ep -> EventHandler TimerSetting TimerSettingEvent sp ep
Settings.handleEvent ClockEvent
ClockCancelTimer)
        , WidgetNode ClockModel ClockEvent
forall s e. WidgetNode s e
spacer
        , WidgetType
-> ALens' ClockModel TimerModel
-> UIBuilder TimerModel TimerEvent
-> EventHandler TimerModel TimerEvent ClockModel ClockEvent
-> WidgetNode ClockModel ClockEvent
forall s e ep sp.
(CompositeModel s, CompositeEvent e, CompositeEvent ep,
 CompParentModel sp) =>
WidgetType
-> ALens' sp s
-> UIBuilder s e
-> EventHandler s e sp ep
-> WidgetNode sp ep
composite WidgetType
"timer" ALens' ClockModel TimerModel
toTimerModel UIBuilder TimerModel TimerEvent
Timer.buildUI ((NominalDiffTime -> ClockEvent)
-> EventHandler TimerModel TimerEvent ClockModel ClockEvent
forall ep es.
(NominalDiffTime -> ep) -> EventHandler TimerModel TimerEvent es ep
Timer.handleEvent NominalDiffTime -> ClockEvent
ClockUpdate) WidgetNode ClockModel ClockEvent
-> Text -> WidgetNode ClockModel ClockEvent
forall s e. WidgetNode s e -> Text -> WidgetNode s e
`nodeKey` Text
mainCounter
        ]
        WidgetNode ClockModel ClockEvent
-> [StyleState] -> WidgetNode ClockModel ClockEvent
forall t. CmbStyleBasic t => t -> [StyleState] -> t
`styleBasic` [Double -> StyleState
forall t. CmbPadding t => Double -> t
padding Double
10]

handleEvent :: EventHandler ClockModel ClockEvent es ep
handleEvent :: forall es ep. EventHandler ClockModel ClockEvent es ep
handleEvent WidgetEnv ClockModel ClockEvent
_wenv WidgetNode ClockModel ClockEvent
_node ClockModel
model (ClockUpdate NominalDiffTime
td) =
    let !tdText :: Text
tdText = String -> Text
forall a. IsString a => String -> a
fromString (TimeLocale -> String -> NominalDiffTime -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
"%m:%02S" NominalDiffTime
td)
     in [ClockModel -> EventResponse ClockModel ClockEvent es ep
forall s e sp ep. s -> EventResponse s e sp ep
Model (ClockModel
model{_cmClock :: Text
_cmClock = Text
tdText}), WidgetRequest ClockModel ClockEvent
-> EventResponse ClockModel ClockEvent es ep
forall s e sp ep. WidgetRequest s e -> EventResponse s e sp ep
Request WidgetRequest ClockModel ClockEvent
forall s e. WidgetRequest s e
RenderOnce]
handleEvent WidgetEnv ClockModel ClockEvent
_ WidgetNode ClockModel ClockEvent
_ ClockModel
_ ClockEvent
ClockCancelTimer = [WidgetKey
-> TimerEvent -> EventResponse ClockModel ClockEvent es ep
forall s e sp ep i.
Typeable i =>
WidgetKey -> i -> EventResponse s e sp ep
Message WidgetKey
mainCounterKey TimerEvent
Timer.TimerStop]

countdownStyle :: Timer.TimerState -> StyleState
countdownStyle :: TimerState -> StyleState
countdownStyle TimerState
settings = case TimerState
settings of
    Timer.TimerWorkWait Async ()
_ -> StyleState
greenBgStyle
    Timer.TimerRestWait Async ()
_ -> StyleState
blueBgStyle
    TimerState
_ -> StyleState
forall a. Monoid a => a
mempty

toTimerModel :: ALens' ClockModel Timer.TimerModel
toTimerModel :: ALens' ClockModel TimerModel
toTimerModel = (ClockModel -> TimerModel)
-> (ClockModel -> TimerModel -> ClockModel)
-> Lens ClockModel ClockModel TimerModel TimerModel
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens ClockModel -> TimerModel
getter ClockModel -> TimerModel -> ClockModel
setter
  where
    getter :: ClockModel -> TimerModel
getter ClockModel
clock = TimerSetting -> TimerState -> TimerModel
Timer.TimerModel (ClockModel -> TimerSetting
_cmSettings ClockModel
clock) (ClockModel -> TimerState
_cmTimer ClockModel
clock)
    setter :: ClockModel -> TimerModel -> ClockModel
setter ClockModel
clock TimerModel
timer =
        ClockModel
clock
            { _cmTimer :: TimerState
_cmTimer = TimerModel -> TimerState
Timer.tmState TimerModel
timer
            , _cmSettings :: TimerSetting
_cmSettings = TimerModel -> TimerSetting
Timer.tmSettings TimerModel
timer
            }