packages feed

pomohoro-0.1.2.4: app/Main.hs

module Main where
import Protolude

import Options.Applicative hiding ((<>))
import System.Posix.Daemonize
import Data.Text as Text
import Data.Time
import System.Timeout

import Settings
import Timeclock
import Notifications
import Networking


data Command
    = Start { _account :: Text, _comment :: Text }
    | Status
    | Interrupt
    | RemindMe { _minutes :: Int, _message :: Text }
    deriving Show


args :: Parser Command
args =
    subparser (mconcat [
        command "start" (info (
            Start
                <$> textArgument
                <*> textRestArguments
        ) (progDesc (mconcat [
            "Start a new work session for the specified timeclock",
            " account (or default if none specified)"
        ]))),
        command "status" (info (
            pure Status
        ) (progDesc
            "How long has the current session been going on for?"
        )),
        command "int" (info (
            pure Interrupt
        ) (progDesc
            ("Interrupt the ongoing work session")
        )),
        command "rem" (info (
            RemindMe
                <$> argument auto (value 5)
                <*> textRestArguments 
        ) (progDesc (mconcat [
            "Wait for the specified number of minutes and then send",
            " a notification. Good for keeping time on breaks"
        ])))])


textArgument :: Parser Text
textArgument =
    fmap pack (strArgument (value ""))


textRestArguments :: Parser Text
textRestArguments =
    fmap (unwords . fmap pack) (many (strArgument mempty))


main :: IO ()
main = do
    settings <- loadSettings
    parsed <- execParser (info (helper <*> args) (progDesc (mconcat
        [ "A small pomodoro timer based on CLI usage and FreeDesktop.org"
        , " notifications. Optionally writes pomodoro sessions to a"
        , " timeclock file for budgeting and reporting."])))
    case parsed of
        Start account comment -> startWork settings account comment
        Status -> queryStatus settings
        Interrupt -> interrupt settings
        RemindMe minutes message -> remindMe minutes message


startWork :: Settings -> Text -> Text -> IO ()
startWork settings account comment = do
    sendUDP settings "status"
    response <- timeout 1000000 (recvUDP settings)
    case response of
        Just _ ->
            putStrLn ("Another session already active. Exiting." :: Text)
        Nothing ->
            daemonize $ do
                startTime <- getZonedTime
                appendFile (_timeclockPath settings) (clockin
                    startTime
                    (if Text.null account then _defaultAccount settings else account)
                    comment)
                void (timeout (usecFromMinutes (_sessionLength settings))
                    (handleSession settings startTime))
                stopTime <- getZonedTime
                appendFile (_timeclockPath settings) (clockout stopTime)
                notifySend "Work is over!"
                    ("You have worked for " <> show (minuteDiff stopTime startTime) <> " minutes. Well done!")


handleSession :: Settings -> ZonedTime -> IO ()
handleSession settings startTime = do
    request <- recvUDP settings
    case request of
        "interrupt" -> pure ()
        "status" -> do
            nowTime <- getZonedTime
            sendUDP settings (show (minuteDiff nowTime startTime))
            handleSession settings startTime
        _ -> handleSession settings startTime


queryStatus :: Settings -> IO ()
queryStatus settings = do
    sendUDP settings "status"
    response <- timeout 1000000 (recvUDP settings)
    case response of
        Just mins -> 
            putStrLn ("Current work session: " <> mins <> "/" <> show (_sessionLength settings) <> " minute(s)")
        Nothing ->
            putStrLn ("No work session active." :: Text)
    

interrupt :: Settings -> IO ()
interrupt settings =
    sendUDP settings "interrupt"


remindMe :: Int -> Text -> IO ()
remindMe minutes message =
    daemonize $ do
        threadDelay (usecFromMinutes minutes)
        notifySend "Time's up!" message