module Taskell.UI.Draw.Task
    ( TaskWidget(..)
    , renderTask
    , parts
    ) where

import ClassyPrelude

import Control.Lens ((^.))

import Brick

import           Taskell.Data.Date          (deadline, timeToText)
import qualified Taskell.Data.Task          as T (Task, contains, countCompleteSubtasks,
                                                  countSubtasks, description, due, hasSubtasks,
                                                  name)
import           Taskell.Events.State.Types (current, mode, searchTerm, time, timeZone)
import           Taskell.IO.Config.Layout   (descriptionIndicator)
import           Taskell.Types              (ListIndex (..), TaskIndex (..))
import           Taskell.UI.Draw.Field      (getText, textField, widgetFromMaybe)
import           Taskell.UI.Draw.Mode
import           Taskell.UI.Draw.Types      (DSWidget, DrawState (..), ReaderDrawState, TWidget)
import           Taskell.UI.Theme
import           Taskell.UI.Types           (ResourceName)

data TaskWidget = TaskWidget
    { TaskWidget -> TWidget
textW     :: TWidget
    , TaskWidget -> TWidget
dateW     :: TWidget
    , TaskWidget -> TWidget
summaryW  :: TWidget
    , TaskWidget -> TWidget
subtasksW :: TWidget
    }

-- | Takes a task's 'due' property and renders a date with appropriate styling (e.g. red if overdue)
renderDate :: T.Task -> DSWidget
renderDate :: Task -> DSWidget
renderDate Task
task = do
    UTCTime
now <- (State -> Getting UTCTime State UTCTime -> UTCTime
forall s a. s -> Getting a s a -> a
^. Getting UTCTime State UTCTime
Lens' State UTCTime
time) (State -> UTCTime)
-> ReaderT DrawState Identity State
-> ReaderT DrawState Identity UTCTime
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (DrawState -> State) -> ReaderT DrawState Identity State
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DrawState -> State
dsState
    TZ
tz <- (State -> Getting TZ State TZ -> TZ
forall s a. s -> Getting a s a -> a
^. Getting TZ State TZ
Lens' State TZ
timeZone) (State -> TZ)
-> ReaderT DrawState Identity State
-> ReaderT DrawState Identity TZ
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (DrawState -> State) -> ReaderT DrawState Identity State
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DrawState -> State
dsState
    TWidget -> DSWidget
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TWidget -> DSWidget)
-> (Maybe TWidget -> TWidget) -> Maybe TWidget -> DSWidget
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. TWidget -> Maybe TWidget -> TWidget
forall a. a -> Maybe a -> a
fromMaybe TWidget
forall n. Widget n
emptyWidget (Maybe TWidget -> DSWidget) -> Maybe TWidget -> DSWidget
forall a b. (a -> b) -> a -> b
$
        (\Due
date -> AttrName -> TWidget -> TWidget
forall n. AttrName -> Widget n -> Widget n
withAttr (Deadline -> AttrName
dlToAttr (Deadline -> AttrName) -> Deadline -> AttrName
forall a b. (a -> b) -> a -> b
$ UTCTime -> Due -> Deadline
deadline UTCTime
now Due
date) (Text -> TWidget
forall n. Text -> Widget n
txt (Text -> TWidget) -> Text -> TWidget
forall a b. (a -> b) -> a -> b
$ TZ -> UTCTime -> Due -> Text
timeToText TZ
tz UTCTime
now Due
date)) (Due -> TWidget) -> Maybe Due -> Maybe TWidget
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
        Task
task Task -> Getting (Maybe Due) Task (Maybe Due) -> Maybe Due
forall s a. s -> Getting a s a -> a
^. Getting (Maybe Due) Task (Maybe Due)
Lens' Task (Maybe Due)
T.due

-- | Renders the appropriate completed sub task count e.g. "[2/3]"
renderSubtaskCount :: T.Task -> DSWidget
renderSubtaskCount :: Task -> DSWidget
renderSubtaskCount Task
task =
    TWidget -> DSWidget
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TWidget -> DSWidget)
-> (Maybe TWidget -> TWidget) -> Maybe TWidget -> DSWidget
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. TWidget -> Maybe TWidget -> TWidget
forall a. a -> Maybe a -> a
fromMaybe TWidget
forall n. Widget n
emptyWidget (Maybe TWidget -> DSWidget) -> Maybe TWidget -> DSWidget
forall a b. (a -> b) -> a -> b
$ Maybe TWidget -> Maybe TWidget -> Bool -> Maybe TWidget
forall a. a -> a -> Bool -> a
bool Maybe TWidget
forall a. Maybe a
Nothing (TWidget -> Maybe TWidget
forall a. a -> Maybe a
Just TWidget
forall n. Widget n
indicator) (Task -> Bool
T.hasSubtasks Task
task)
  where
    complete :: Text
complete = Int -> Text
forall a. Show a => a -> Text
tshow (Int -> Text) -> Int -> Text
forall a b. (a -> b) -> a -> b
$ Task -> Int
T.countCompleteSubtasks Task
task
    total :: Text
total = Int -> Text
forall a. Show a => a -> Text
tshow (Int -> Text) -> Int -> Text
forall a b. (a -> b) -> a -> b
$ Task -> Int
T.countSubtasks Task
task
    indicator :: Widget n
indicator = Text -> Widget n
forall n. Text -> Widget n
txt (Text -> Widget n) -> Text -> Widget n
forall a b. (a -> b) -> a -> b
$ [Text] -> Element [Text]
forall mono.
(MonoFoldable mono, Monoid (Element mono)) =>
mono -> Element mono
concat [Text
"[", Text
complete, Text
"/", Text
total, Text
"]"]

-- | Renders the description indicator
renderDescIndicator :: T.Task -> DSWidget
renderDescIndicator :: Task -> DSWidget
renderDescIndicator Task
task = do
    Text
indicator <- Config -> Text
descriptionIndicator (Config -> Text)
-> ReaderT DrawState Identity Config
-> ReaderT DrawState Identity Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (DrawState -> Config) -> ReaderT DrawState Identity Config
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DrawState -> Config
dsLayout
    TWidget -> DSWidget
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TWidget -> DSWidget)
-> (Maybe TWidget -> TWidget) -> Maybe TWidget -> DSWidget
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. TWidget -> Maybe TWidget -> TWidget
forall a. a -> Maybe a -> a
fromMaybe TWidget
forall n. Widget n
emptyWidget (Maybe TWidget -> DSWidget) -> Maybe TWidget -> DSWidget
forall a b. (a -> b) -> a -> b
$ TWidget -> Text -> TWidget
forall a b. a -> b -> a
const (Text -> TWidget
forall n. Text -> Widget n
txt Text
indicator) (Text -> TWidget) -> Maybe Text -> Maybe TWidget
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Task
task Task -> Getting (Maybe Text) Task (Maybe Text) -> Maybe Text
forall s a. s -> Getting a s a -> a
^. Getting (Maybe Text) Task (Maybe Text)
Lens' Task (Maybe Text)
T.description -- show the description indicator if one is set

-- | Renders the task text
renderText :: T.Task -> DSWidget
renderText :: Task -> DSWidget
renderText Task
task = TWidget -> DSWidget
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TWidget -> DSWidget) -> TWidget -> DSWidget
forall a b. (a -> b) -> a -> b
$ Text -> TWidget
textField (Task
task Task -> Getting Text Task Text -> Text
forall s a. s -> Getting a s a -> a
^. Getting Text Task Text
Lens' Task Text
T.name)

-- | Renders the appropriate indicators: description, sub task count, and due date
indicators :: T.Task -> DSWidget
indicators :: Task -> DSWidget
indicators Task
task = do
    [TWidget]
widgets <- [DSWidget] -> ReaderT DrawState Identity [TWidget]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence (((Task -> DSWidget) -> Task -> DSWidget
forall a b. (a -> b) -> a -> b
$ Task
task) ((Task -> DSWidget) -> DSWidget)
-> [Task -> DSWidget] -> [DSWidget]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Task -> DSWidget
renderDescIndicator, Task -> DSWidget
renderSubtaskCount, Task -> DSWidget
renderDate])
    TWidget -> DSWidget
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TWidget -> DSWidget)
-> ([TWidget] -> TWidget) -> [TWidget] -> DSWidget
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [TWidget] -> TWidget
forall n. [Widget n] -> Widget n
hBox ([TWidget] -> DSWidget) -> [TWidget] -> DSWidget
forall a b. (a -> b) -> a -> b
$ Padding -> TWidget -> TWidget
forall n. Padding -> Widget n -> Widget n
padRight (Int -> Padding
Pad Int
1) (TWidget -> TWidget) -> [TWidget] -> [TWidget]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [TWidget]
widgets

-- | The individual parts of a task widget
parts :: T.Task -> ReaderDrawState TaskWidget
parts :: Task -> ReaderDrawState TaskWidget
parts Task
task =
    TWidget -> TWidget -> TWidget -> TWidget -> TaskWidget
TaskWidget (TWidget -> TWidget -> TWidget -> TWidget -> TaskWidget)
-> DSWidget
-> ReaderT
     DrawState Identity (TWidget -> TWidget -> TWidget -> TaskWidget)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Task -> DSWidget
renderText Task
task ReaderT
  DrawState Identity (TWidget -> TWidget -> TWidget -> TaskWidget)
-> DSWidget
-> ReaderT DrawState Identity (TWidget -> TWidget -> TaskWidget)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Task -> DSWidget
renderDate Task
task ReaderT DrawState Identity (TWidget -> TWidget -> TaskWidget)
-> DSWidget -> ReaderT DrawState Identity (TWidget -> TaskWidget)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Task -> DSWidget
renderDescIndicator Task
task ReaderT DrawState Identity (TWidget -> TaskWidget)
-> DSWidget -> ReaderDrawState TaskWidget
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*>
    Task -> DSWidget
renderSubtaskCount Task
task

-- | Renders an individual task
renderTask' :: (Int -> ResourceName) -> Int -> Int -> T.Task -> DSWidget
renderTask' :: (Int -> ResourceName) -> Int -> Int -> Task -> DSWidget
renderTask' Int -> ResourceName
rn Int
listIndex Int
taskIndex Task
task = do
    Bool
eTitle <- Mode -> Bool
editingTitle (Mode -> Bool) -> (State -> Mode) -> State -> Bool
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (State -> Getting Mode State Mode -> Mode
forall s a. s -> Getting a s a -> a
^. Getting Mode State Mode
Lens' State Mode
mode) (State -> Bool)
-> ReaderT DrawState Identity State
-> ReaderT DrawState Identity Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (DrawState -> State) -> ReaderT DrawState Identity State
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DrawState -> State
dsState -- is the title being edited? (for visibility)
    Bool
selected <- ((ListIndex, TaskIndex) -> (ListIndex, TaskIndex) -> Bool
forall a. Eq a => a -> a -> Bool
== (Int -> ListIndex
ListIndex Int
listIndex, Int -> TaskIndex
TaskIndex Int
taskIndex)) ((ListIndex, TaskIndex) -> Bool)
-> (State -> (ListIndex, TaskIndex)) -> State -> Bool
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (State
-> Getting (ListIndex, TaskIndex) State (ListIndex, TaskIndex)
-> (ListIndex, TaskIndex)
forall s a. s -> Getting a s a -> a
^. Getting (ListIndex, TaskIndex) State (ListIndex, TaskIndex)
Lens' State (ListIndex, TaskIndex)
current) (State -> Bool)
-> ReaderT DrawState Identity State
-> ReaderT DrawState Identity Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (DrawState -> State) -> ReaderT DrawState Identity State
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DrawState -> State
dsState -- is the current task selected?
    Maybe Field
taskField <- Mode -> Maybe Field
getField (Mode -> Maybe Field) -> (State -> Mode) -> State -> Maybe Field
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (State -> Getting Mode State Mode -> Mode
forall s a. s -> Getting a s a -> a
^. Getting Mode State Mode
Lens' State Mode
mode) (State -> Maybe Field)
-> ReaderT DrawState Identity State
-> ReaderT DrawState Identity (Maybe Field)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (DrawState -> State) -> ReaderT DrawState Identity State
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DrawState -> State
dsState -- get the field, if it's being edited
    TWidget
after <- Task -> DSWidget
indicators Task
task -- get the indicators widget
    TWidget
widget <- Task -> DSWidget
renderText Task
task
    let name :: ResourceName
name = Int -> ResourceName
rn Int
taskIndex
        widget' :: TWidget
widget' = TWidget -> Maybe Field -> TWidget
widgetFromMaybe TWidget
widget Maybe Field
taskField
    TWidget -> DSWidget
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TWidget -> DSWidget) -> TWidget -> DSWidget
forall a b. (a -> b) -> a -> b
$
        ResourceName -> TWidget -> TWidget
forall n. Ord n => n -> Widget n -> Widget n
cached ResourceName
name (TWidget -> TWidget) -> (TWidget -> TWidget) -> TWidget -> TWidget
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
.
        (if Bool
selected Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
eTitle
             then TWidget -> TWidget
forall n. Widget n -> Widget n
visible
             else TWidget -> TWidget
forall k (cat :: k -> k -> *) (a :: k). Category cat => cat a a
id) (TWidget -> TWidget) -> (TWidget -> TWidget) -> TWidget -> TWidget
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
.
        Padding -> TWidget -> TWidget
forall n. Padding -> Widget n -> Widget n
padBottom (Int -> Padding
Pad Int
1) (TWidget -> TWidget) -> (TWidget -> TWidget) -> TWidget -> TWidget
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
.
        (TWidget -> TWidget -> TWidget
forall n. Widget n -> Widget n -> Widget n
<=> AttrName -> TWidget -> TWidget
forall n. AttrName -> Widget n -> Widget n
withAttr AttrName
disabledAttr TWidget
after) (TWidget -> TWidget) -> (TWidget -> TWidget) -> TWidget -> TWidget
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
.
        AttrName -> TWidget -> TWidget
forall n. AttrName -> Widget n -> Widget n
withAttr
            (if Bool
selected
                 then AttrName
taskCurrentAttr
                 else AttrName
taskAttr) (TWidget -> TWidget) -> TWidget -> TWidget
forall a b. (a -> b) -> a -> b
$
        if Bool
selected Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
eTitle
            then TWidget
widget'
            else TWidget
widget

renderTask :: (Int -> ResourceName) -> Int -> Int -> T.Task -> DSWidget
renderTask :: (Int -> ResourceName) -> Int -> Int -> Task -> DSWidget
renderTask Int -> ResourceName
rn Int
listIndex Int
taskIndex Task
task = do
    Maybe Text
searchT <- (Field -> Text
getText (Field -> Text) -> Maybe Field -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (Maybe Field -> Maybe Text)
-> (State -> Maybe Field) -> State -> Maybe Text
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (State -> Getting (Maybe Field) State (Maybe Field) -> Maybe Field
forall s a. s -> Getting a s a -> a
^. Getting (Maybe Field) State (Maybe Field)
Lens' State (Maybe Field)
searchTerm) (State -> Maybe Text)
-> ReaderT DrawState Identity State
-> ReaderT DrawState Identity (Maybe Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (DrawState -> State) -> ReaderT DrawState Identity State
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DrawState -> State
dsState
    let taskWidget :: DSWidget
taskWidget = (Int -> ResourceName) -> Int -> Int -> Task -> DSWidget
renderTask' Int -> ResourceName
rn Int
listIndex Int
taskIndex Task
task
    case Maybe Text
searchT of
        Maybe Text
Nothing -> DSWidget
taskWidget
        Just Text
term ->
            if Text -> Task -> Bool
T.contains Text
term Task
task
                then DSWidget
taskWidget
                else TWidget -> DSWidget
forall (f :: * -> *) a. Applicative f => a -> f a
pure TWidget
forall n. Widget n
emptyWidget