matterhorn-50200.17.0: src/Matterhorn/Draw/PostListWindow.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
module Matterhorn.Draw.PostListWindow where
import Prelude ()
import Matterhorn.Prelude
import Brick
import Brick.Widgets.Border
import Brick.Widgets.Center
import Control.Monad.Trans.Reader ( withReaderT )
import qualified Data.Text as T
import Lens.Micro.Platform ( (%~), to )
import Network.Mattermost.Lenses
import Network.Mattermost.Types
import Matterhorn.Draw.Messages
import Matterhorn.Draw.Util
import Matterhorn.Themes
import Matterhorn.Types
hLimitWithPadding :: Int -> Widget n -> Widget n
hLimitWithPadding pad contents = Widget
{ hSize = Fixed
, vSize = (vSize contents)
, render =
withReaderT (& availWidthL %~ (\ n -> n - (2 * pad))) $ render $ cropToContext contents
}
drawPostListWindow :: PostListContents -> ChatState -> TeamId -> Widget Name
drawPostListWindow contents st tId = joinBorders $ drawPostsBox contents st tId
-- | Draw a PostListWindow as a floating window on top of whatever
-- is rendered beneath it
drawPostsBox :: PostListContents -> ChatState -> TeamId -> Widget Name
drawPostsBox contents st tId =
centerLayer $ hLimitWithPadding 10 $ borderWithLabel contentHeader $
padRight (Pad 1) messageListContents
where -- The 'window title' of the window
hs = getHighlightSet st tId
contentHeader = withAttr channelListHeaderAttr $ txt $ case contents of
PostListFlagged -> "Flagged posts"
PostListPinned cId ->
let cName = case findChannelById cId (st^.csChannels) of
Nothing -> "<UNKNOWN>"
Just cc -> mkChannelName st (cc^.ccInfo)
in "Posts pinned in " <> cName
PostListSearch terms searching -> "Search results" <> if searching
then ": " <> terms
else " (" <> (T.pack . show . length) entries <> "): " <> terms
entries = filterMessages knownChannel $ st^.csTeam(tId).tsPostListWindow.postListPosts
messages = insertDateMarkers
entries
(getDateFormat st)
(st^.timeZone)
knownChannel msg =
case msg^.mChannelId of
Just cId | Nothing <- st^?csChannels.channelByIdL(cId) -> False
_ -> True
-- The overall contents, with a sensible default even if there
-- are no messages
messageListContents
| null messages =
padTopBottom 1 $
hCenter $
withDefAttr clientEmphAttr $
str $ case contents of
PostListFlagged -> "You have no flagged messages."
PostListPinned _ -> "This channel has no pinned messages."
PostListSearch _ searching ->
if searching
then "Searching ..."
else "No search results found"
| otherwise = vBox renderedMessageList
-- The render-message function we're using
renderMessageForWindow msg tState tag =
let renderedMsg = renderSingleMessage st hs True Nothing msg tState tag
in case msg^.mOriginalPost of
-- We should factor out some of the channel name logic at
-- some point, but we can do that later
Just post
| Just chan <- st^?csChannels.channelByIdL(post^.postChannelIdL) ->
case chan^.ccInfo.cdType of
Direct
| Just u <- flip userById st =<< chan^.ccInfo.cdDMUserId ->
(forceAttr channelNameAttr (txt (addUserSigil $ u^.uiName)) <=>
(str " " <+> renderedMsg))
_ -> (forceAttr channelNameAttr (txt (chan^.ccInfo.to (mkChannelName st))) <=>
(str " " <+> renderedMsg))
_ | CP _ <- msg^.mType -> str "[BUG: unknown channel]"
| otherwise -> renderedMsg
-- The full message list, rendered with the current selection
renderedMessageList =
let (s, (before, after)) = splitDirSeqOn matchesMessage messagesWithStates
matchesMessage (m, _) = m^.mMessageId == (MessagePostId <$> st^.csTeam(tId).tsPostListWindow.postListSelected)
messagesWithStates = (, InThreadShowParent) <$> messages
tag = PostList
in case s of
Nothing ->
map (\(m, tst) -> renderMessageForWindow m tst tag) (toList messagesWithStates)
Just curMsg ->
[unsafeRenderMessageSelection (curMsg, (before, after)) renderMessageForWindow tag]