packages feed

matterhorn-40700.0.0: src/Draw/UserListOverlay.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

module Draw.UserListOverlay where

import           Prelude ()
import           Prelude.Compat

import           Control.Monad.Trans.Reader (withReaderT)
import qualified Data.Foldable as F
import qualified Data.Text as T
import           Data.Maybe (catMaybes)
import           Data.Monoid ((<>))
import qualified Graphics.Vty as V
import           Lens.Micro.Platform

import Brick
import Brick.Widgets.Border
import Brick.Widgets.Edit
import qualified Brick.Widgets.List as L
import Brick.Widgets.Center

import Themes
import Types
import Types.Users
import Draw.Main
import Draw.Util (userSigilFromInfo)

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
  }

drawUserListOverlay :: ChatState -> [Widget Name]
drawUserListOverlay st =
  drawUsersBox (st^.csUserListOverlay) :
  (forceAttr "invalid" <$> drawMain st)

-- | Draw a PostListOverlay as a floating overlay on top of whatever
-- is rendered beneath it
drawUsersBox :: UserListOverlayState -> Widget Name
drawUsersBox st =
  centerLayer $ hLimitWithPadding 10 $ vLimit 25 $
  borderWithLabel contentHeader body
  where
      body = vBox [ (padRight (Pad 1) $ str promptMsg) <+>
                    renderEditor (txt . T.unlines) True (st^.userListSearchInput)
                  , cursorPositionBorder
                  , userResultList
                  ]
      plural 1 = ""
      plural _ = "s"
      cursorPositionBorder = case st^.userListSearchResults.L.listSelectedL of
          Nothing -> hBorder
          Just _ ->
              let msg = case st^.userListRequestingMore of
                          True -> "Fetching more results..."
                          False -> "Showing " <> show numSearchResults <> " result" <> plural numSearchResults
                          -- NOTE: one day when we resume doing
                          -- pagination, we want to reinstate the
                          -- following logic instead of the False case
                          -- above. Please see State.UserListOverlay for
                          -- details.
                          --
                          -- False -> case st^.userListHasAllResults of
                          --     True -> "Showing all results (" <> show numSearchResults <> ")"
                          --     False -> "Showing first " <>
                          --              show numSearchResults <>
                          --              " result" <> plural numSearchResults
              in hBorderWithLabel $ str $ "[" <> msg <> "]"

      scope = st^.userListSearchScope
      promptMsg = case scope of
          ChannelMembers _    -> "Search channel members:"
          ChannelNonMembers _ -> "Search users:"
          AllUsers            -> "Search users:"

      userResultList =
          if st^.userListSearching
          then showMessage "Searching..."
          else showResults

      showMessage = center . withDefAttr clientEmphAttr . str

      showResults
        | numSearchResults == 0 =
            showMessage $ case scope of
              ChannelMembers _    -> "No users in channel."
              ChannelNonMembers _ -> "All users in your team are already in this channel."
              AllUsers            -> "No users found."
        | otherwise = renderedUserList

      contentHeader = str $ case scope of
          ChannelMembers _    -> "Channel Members"
          ChannelNonMembers _ -> "Invite Users to Channel"
          AllUsers            -> "Users On This Server"

      renderedUserList = L.renderList renderUser True (st^.userListSearchResults)
      numSearchResults = F.length $ st^.userListSearchResults.L.listElementsL

      sanitize = T.strip . T.replace "\t" " "
      usernameWidth = 20
      renderUser foc ui =
          (if foc then forceAttr L.listSelectedFocusedAttr else id) $
          vLimit 2 $
          padRight Max $
          hBox $ (padRight (Pad 1) $ colorUsername (ui^.uiName) (T.singleton $ userSigilFromInfo ui))
                 : (hLimit usernameWidth $ padRight Max $ colorUsername (ui^.uiName) (ui^.uiName))
                 : extras
          where
              extras = padRight (Pad 1) <$> catMaybes [mFullname, mNickname, mEmail]
              mFullname = if (not (T.null (ui^.uiFirstName)) || not (T.null (ui^.uiLastName)))
                          then Just $ txt $ (sanitize $ ui^.uiFirstName) <> " " <> (sanitize $ ui^.uiLastName)
                          else Nothing
              mNickname = case ui^.uiNickName of
                            Just n | n /= (ui^.uiName) -> Just $ txt $ "(" <> n <> ")"
                            _ -> Nothing
              mEmail = if (T.null $ ui^.uiEmail)
                       then Nothing
                       else Just $ modifyDefAttr (`V.withURL` ("mailto:" <> ui^.uiEmail)) $
                                   withDefAttr urlAttr (txt ("<" <> ui^.uiEmail <> ">"))