{-# LANGUAGE TemplateHaskell #-} module Taskell.Data.Task where import ClassyPrelude import Control.Lens ((%~), (&), (.~), (?~), (^.), (^?), ix, makeLenses) import Data.Sequence as S ((|>), adjust', deleteAt, insertAt) import Data.Text (strip) import Data.Time.Zones (TZ) import Taskell.Data.Date (Due(..), inputToTime) import qualified Taskell.Data.Subtask as ST (Subtask, Update, complete, duplicate, name) data Task = Task { _name :: Text , _description :: Maybe Text , _subtasks :: Seq ST.Subtask , _due :: Maybe Due } deriving (Show, Eq) type Update = Task -> Task -- create lenses $(makeLenses ''Task) -- operations create :: Text -> Maybe Due -> Maybe Text -> Seq ST.Subtask -> Task create name' due' description' subtasks' = Task name' description' subtasks' due' blank :: Task blank = Task "" Nothing empty Nothing new :: Text -> Task new text = blank & (name .~ text) setDescription :: Text -> Update setDescription text = description .~ if null (strip text) then Nothing else Just text maybeAppend :: Text -> Maybe Text -> Maybe Text maybeAppend text (Just current) = Just (concat [current, "\n", text]) maybeAppend text Nothing = Just text appendDescription :: Text -> Update appendDescription text = if null (strip text) then id else description %~ maybeAppend text setDue :: TZ -> UTCTime -> Text -> Task -> Maybe Task setDue tz now date task = if null date then Just (task & due .~ Nothing) else (\d -> task & due ?~ d) <$> inputToTime tz now (strip date) clearDue :: Update clearDue task = task & due .~ Nothing getSubtask :: Int -> Task -> Maybe ST.Subtask getSubtask idx = (^? subtasks . ix idx) addSubtaskAtIndex :: Int -> ST.Subtask -> Update addSubtaskAtIndex idx subtask = subtasks %~ S.insertAt idx subtask addSubtask :: ST.Subtask -> Update addSubtask subtask = subtasks %~ (|> subtask) hasSubtasks :: Task -> Bool hasSubtasks = not . null . (^. subtasks) updateSubtask :: Int -> ST.Update -> Update updateSubtask idx fn = subtasks %~ adjust' fn idx removeSubtask :: Int -> Update removeSubtask idx = subtasks %~ S.deleteAt idx countSubtasks :: Task -> Int countSubtasks = length . (^. subtasks) countCompleteSubtasks :: Task -> Int countCompleteSubtasks = length . filter (^. ST.complete) . (^. subtasks) contains :: Text -> Task -> Bool contains text task = check (task ^. name) || maybe False check (task ^. description) || not (null sts) where check = isInfixOf (toLower text) . toLower sts = filter check $ (^. ST.name) <$> (task ^. subtasks) isBlank :: Task -> Bool isBlank task = null (task ^. name) && isNothing (task ^. description) && null (task ^. subtasks) && isNothing (task ^. due) duplicate :: Task -> Task duplicate (Task n d st du) = Task n d (ST.duplicate <$> st) du