packages feed

matterhorn-50200.17.0: src/Matterhorn/State/PostListWindow.hs

module Matterhorn.State.PostListWindow
  ( enterFlaggedPostListMode
  , enterPinnedPostListMode
  , enterSearchResultPostListMode
  , postListJumpToCurrent
  , postListSelectUp
  , postListSelectDown
  , postListUnflagSelected
  , exitPostListMode
  )
where

import           GHC.Exts ( IsList(..) )
import           Prelude ()
import           Matterhorn.Prelude

import qualified Data.Foldable as F
import qualified Data.Text as T
import           Lens.Micro.Platform ( (.=) )
import           Network.Mattermost.Endpoints
import           Network.Mattermost.Types

import           Matterhorn.State.Messages ( jumpToPost )
import           Matterhorn.State.Common
import           Matterhorn.State.MessageSelect
import           Matterhorn.State.Messages ( addObtainedMessages
                                           , asyncFetchMessagesSurrounding )
import           Matterhorn.Types
import           Matterhorn.Types.DirectionalSeq (emptyDirSeq)


-- | Create a PostListWindow with the given content description and
-- with a specified list of messages.
enterPostListMode :: TeamId -> PostListContents -> Messages -> MH ()
enterPostListMode tId contents msgs = do
  csTeam(tId).tsPostListWindow.postListPosts .= msgs
  let mlatest = getLatestPostMsg msgs
      pId = mlatest >>= messagePostId
      cId = mlatest >>= \m -> m^.mChannelId
  csTeam(tId).tsPostListWindow.postListSelected .= pId
  pushMode tId $ PostListWindow contents
  case (pId, cId) of
    (Just p, Just c) -> asyncFetchMessagesSurrounding c p
    _ -> return ()

-- | Clear out the state of a PostListWindow
exitPostListMode :: TeamId -> MH ()
exitPostListMode tId = do
  csTeam(tId).tsPostListWindow.postListPosts .= emptyDirSeq
  csTeam(tId).tsPostListWindow.postListSelected .= Nothing
  popMode tId

createPostList :: TeamId -> PostListContents -> (Session -> IO Posts) -> MH ()
createPostList tId contentsType fetchOp = do
  session <- getSession
  doAsyncWith Preempt $ do
    posts <- fetchOp session
    return $ Just $ do
      messages <- installMessagesFromPosts (Just tId) posts
      -- n.b. do not use addNewPostedMessage because these messages
      -- are not new, and so no notifications or channel highlighting
      -- or other post-processing should be performed.
      let plist = F.toList $ postsPosts posts
          postsSpec p = Posts { postsPosts = fromList [(postId p, p)]
                              , postsOrder = fromList [postId p]
                              }
      mapM_ (\p -> addObtainedMessages (postChannelId p) 0 False $ postsSpec p) plist
      enterPostListMode tId contentsType messages


-- | Create a PostListWindow with flagged messages from the server.
enterFlaggedPostListMode :: TeamId -> MH ()
enterFlaggedPostListMode tId = do
    createPostList tId PostListFlagged $
        mmGetListOfFlaggedPosts UserMe defaultFlaggedPostsQuery

-- | Create a PostListWindow with pinned messages from the server for
-- the current channel.
enterPinnedPostListMode :: TeamId -> MH ()
enterPinnedPostListMode tId =
    withCurrentChannel tId $ \cId _ -> do
        createPostList tId (PostListPinned cId) $ mmGetChannelPinnedPosts cId

-- | Create a PostListWindow with post search result messages from the
-- server.
enterSearchResultPostListMode :: TeamId -> Text -> MH ()
enterSearchResultPostListMode tId terms
  | T.null (T.strip terms) = postInfoMessage "Search command requires at least one search term."
  | otherwise = do
      enterPostListMode tId (PostListSearch terms True) noMessages
      createPostList tId (PostListSearch terms False) $
        mmSearchForTeamPosts tId (SearchPosts terms False)


-- | Move the selection up in the PostListWindow, which corresponds
-- to finding a chronologically /newer/ message.
postListSelectDown :: TeamId -> MH ()
postListSelectDown tId = do
  selId <- use (csTeam(tId).tsPostListWindow.postListSelected)
  posts <- use (csTeam(tId).tsPostListWindow.postListPosts)
  let nextMsg = getNextMessage (MessagePostId <$> selId) posts
  case nextMsg of
    Nothing -> return ()
    Just m -> do
      let pId = m^.mMessageId >>= messageIdPostId
      csTeam(tId).tsPostListWindow.postListSelected .= pId
      case (m^.mChannelId, pId) of
        (Just c, Just p) -> asyncFetchMessagesSurrounding c p
        o -> mhLog LogError
             (T.pack $ "postListSelectDown" <>
              " unable to get channel or post ID: " <> show o)

-- | Move the selection down in the PostListWindow, which corresponds
-- to finding a chronologically /old/ message.
postListSelectUp :: TeamId -> MH ()
postListSelectUp tId = do
  selId <- use (csTeam(tId).tsPostListWindow.postListSelected)
  posts <- use (csTeam(tId).tsPostListWindow.postListPosts)
  let prevMsg = getPrevMessage (MessagePostId <$> selId) posts
  case prevMsg of
    Nothing -> return ()
    Just m -> do
      let pId = m^.mMessageId >>= messageIdPostId
      csTeam(tId).tsPostListWindow.postListSelected .= pId
      case (m^.mChannelId, pId) of
        (Just c, Just p) -> asyncFetchMessagesSurrounding c p
        o -> mhLog LogError
             (T.pack $ "postListSelectUp" <>
              " unable to get channel or post ID: " <> show o)

-- | Unflag the post currently selected in the PostListWindow, if any
postListUnflagSelected :: TeamId -> MH ()
postListUnflagSelected tId = do
  msgId <- use (csTeam(tId).tsPostListWindow.postListSelected)
  case msgId of
    Nothing  -> return ()
    Just pId -> flagMessage pId False


-- | Jumps to the specified message in the message's main channel
-- display and changes to MessageSelectState.
postListJumpToCurrent :: TeamId -> MH ()
postListJumpToCurrent tId = do
  msgId <- use (csTeam(tId).tsPostListWindow.postListSelected)
  case msgId of
    Nothing  -> return ()
    Just pId -> jumpToPost pId