{-# LANGUAGE RankNTypes #-}
module Matterhorn.State.Teams
  ( nextTeam
  , prevTeam
  , handleJoinTeam
  , handleLeaveTeam
  , handleUpdateTeam
  , buildTeamState
  , moveCurrentTeamLeft
  , moveCurrentTeamRight
  , setTeam
  , newSaveAttachmentDialog
  , newChannelTopicDialog
  , newThreadInterface
  , makeClientChannel
  , cycleTeamMessageInterfaceFocus
  )
where

import           Prelude ()
import           Matterhorn.Prelude

import           Brick ( getName )
import qualified Brick.BChan as BCH
import           Brick.Main ( invalidateCache, hScrollToBeginning, viewportScroll, makeVisible )
import           Brick.Widgets.List ( list )
import           Brick.Widgets.Edit ( editor, applyEdit )
import           Brick.Focus ( focusRing )
import qualified Data.Sequence as Seq
import qualified Data.Text as T
import           Data.Time.Clock ( getCurrentTime )
import qualified Data.Text.Zipper as Z2
import qualified Data.HashMap.Strict as HM
import           Lens.Micro.Platform ( (%=), (.=), at )
import           Text.Aspell ( Aspell )

import           Network.Mattermost.Lenses ( userIdL, channelTypeL, channelPurposeL
                                           , channelHeaderL, channelTeamIdL, channelIdL
                                           , channelLastPostAtL
                                           )
import           Network.Mattermost.Types ( TeamId, Team, Channel, User, userId
                                          , getId, channelId, teamId, UserParam(..)
                                          , teamOrderPref, Post, ChannelId, postId
                                          , emptyChannelNotifyProps, UserId
                                          , channelName, Type(..), channelDisplayName
                                          )
import qualified Network.Mattermost.Endpoints as MM

import           Matterhorn.Types
import           Matterhorn.Types.Common
import           Matterhorn.Types.DirectionalSeq ( emptyDirSeq )
import           Matterhorn.Types.NonemptyStack
import           Matterhorn.LastRunState
import           Matterhorn.State.Async
import           Matterhorn.State.ChannelList
import           Matterhorn.State.Channels
import {-# SOURCE #-} Matterhorn.State.ThreadWindow
import {-# SOURCE #-} Matterhorn.State.Messages
import           Matterhorn.State.Setup.Threads ( newSpellCheckTimer )
import qualified Matterhorn.Zipper as Z


-- | Move right in the channel list to select the next team.
nextTeam :: MH ()
nextTeam :: MH ()
nextTeam = (Zipper () TeamId -> Zipper () TeamId) -> MH ()
setTeamFocusWith Zipper () TeamId -> Zipper () TeamId
forall a b. Zipper a b -> Zipper a b
Z.right

-- | Move left in the channel list to select the previous team.
prevTeam :: MH ()
prevTeam :: MH ()
prevTeam = (Zipper () TeamId -> Zipper () TeamId) -> MH ()
setTeamFocusWith Zipper () TeamId -> Zipper () TeamId
forall a b. Zipper a b -> Zipper a b
Z.left

-- | Set the current team directly
setTeam :: TeamId -> MH ()
setTeam :: TeamId -> MH ()
setTeam TeamId
tId = (Zipper () TeamId -> Zipper () TeamId) -> MH ()
setTeamFocusWith ((Zipper () TeamId -> Zipper () TeamId) -> MH ())
-> (Zipper () TeamId -> Zipper () TeamId) -> MH ()
forall a b. (a -> b) -> a -> b
$ (TeamId -> Bool) -> Zipper () TeamId -> Zipper () TeamId
forall b a. (b -> Bool) -> Zipper a b -> Zipper a b
Z.findRight (TeamId -> TeamId -> Bool
forall a. Eq a => a -> a -> Bool
== TeamId
tId)

-- | Change the selected team with the specified team zipper
-- transformation. This function also takes care of book-keeping
-- necessary during team switching.
setTeamFocusWith :: (Z.Zipper () TeamId -> Z.Zipper () TeamId) -> MH ()
setTeamFocusWith :: (Zipper () TeamId -> Zipper () TeamId) -> MH ()
setTeamFocusWith Zipper () TeamId -> Zipper () TeamId
f = do
    -- Before we leave this team to view another one, indicate that
    -- we've viewed the current team's currently-selected channel so
    -- that this team doesn't get left with an unread indicator once we
    -- are looking at the other team. We do this when switching channels
    -- within a team in the same way.
    Bool -> MH ()
updateViewed Bool
True

    (Zipper () TeamId -> Identity (Zipper () TeamId))
-> ChatState -> Identity ChatState
Lens' ChatState (Zipper () TeamId)
csTeamZipper ((Zipper () TeamId -> Identity (Zipper () TeamId))
 -> ChatState -> Identity ChatState)
-> (Zipper () TeamId -> Zipper () TeamId) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Zipper () TeamId -> Zipper () TeamId
f
    (TeamId -> MH ()) -> MH ()
withCurrentTeam TeamId -> MH ()
postChangeTeamCommon

-- | Book-keeping common to all team selection changes.
postChangeTeamCommon :: TeamId -> MH ()
postChangeTeamCommon :: TeamId -> MH ()
postChangeTeamCommon TeamId
tId = do
    Bool -> MH ()
updateViewed Bool
False
    TeamId -> MH ()
fetchVisibleIfNeeded TeamId
tId
    EventM Name () -> MH ()
forall a. EventM Name a -> MH a
mh (EventM Name () -> MH ()) -> EventM Name () -> MH ()
forall a b. (a -> b) -> a -> b
$ do
        ViewportScroll Name -> EventM Name ()
forall n. ViewportScroll n -> EventM n ()
hScrollToBeginning (Name -> ViewportScroll Name
forall n. n -> ViewportScroll n
viewportScroll Name
TeamList)
        Name -> EventM Name ()
forall n. Ord n => n -> EventM n ()
makeVisible (Name -> EventM Name ()) -> Name -> EventM Name ()
forall a b. (a -> b) -> a -> b
$ TeamId -> Name
SelectedChannelListEntry TeamId
tId

-- | Fetch the specified team and add it to the application state.
--
-- This is called in response to a server event indicating that the
-- current user was added to the team.
handleJoinTeam :: TeamId -> MH ()
handleJoinTeam :: TeamId -> MH ()
handleJoinTeam TeamId
tId = do
    Session
session <- MH Session
getSession
    ChatResources
cr <- Getting ChatResources ChatState ChatResources -> MH ChatResources
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting ChatResources ChatState ChatResources
Lens' ChatState ChatResources
csResources
    User
me <- Getting User ChatState User -> MH User
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting User ChatState User
Lens' ChatState User
csMe
    HashMap TeamId TeamState
curTs <- Getting
  (HashMap TeamId TeamState) ChatState (HashMap TeamId TeamState)
-> MH (HashMap TeamId TeamState)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting
  (HashMap TeamId TeamState) ChatState (HashMap TeamId TeamState)
Lens' ChatState (HashMap TeamId TeamState)
csTeams
    let myTIds :: [TeamId]
myTIds = HashMap TeamId TeamState -> [TeamId]
forall k v. HashMap k v -> [k]
HM.keys HashMap TeamId TeamState
curTs

    Bool -> MH () -> MH ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ TeamId
tId TeamId -> [TeamId] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [TeamId]
myTIds) (MH () -> MH ()) -> MH () -> MH ()
forall a b. (a -> b) -> a -> b
$ do
        LogCategory -> Text -> MH ()
mhLog LogCategory
LogGeneral (Text -> MH ()) -> Text -> MH ()
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String
"Joining team " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> TeamId -> String
forall a. Show a => a -> String
show TeamId
tId
        AsyncPriority -> IO (Maybe (MH ())) -> MH ()
doAsyncWith AsyncPriority
Normal (IO (Maybe (MH ())) -> MH ()) -> IO (Maybe (MH ())) -> MH ()
forall a b. (a -> b) -> a -> b
$ do
            Team
t <- TeamId -> Session -> IO Team
MM.mmGetTeam TeamId
tId Session
session
            (TeamState
ts, ClientChannels
chans) <- ChatResources -> User -> Team -> IO (TeamState, ClientChannels)
buildTeamState ChatResources
cr User
me Team
t
            Maybe (MH ()) -> IO (Maybe (MH ()))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (MH ()) -> IO (Maybe (MH ())))
-> Maybe (MH ()) -> IO (Maybe (MH ()))
forall a b. (a -> b) -> a -> b
$ MH () -> Maybe (MH ())
forall a. a -> Maybe a
Just (MH () -> Maybe (MH ())) -> MH () -> Maybe (MH ())
forall a b. (a -> b) -> a -> b
$ do
                    TeamState -> ClientChannels -> MH ()
addTeamState TeamState
ts ClientChannels
chans
                    Maybe TeamId -> MH ()
updateSidebar (Maybe TeamId -> MH ()) -> Maybe TeamId -> MH ()
forall a b. (a -> b) -> a -> b
$ TeamId -> Maybe TeamId
forall a. a -> Maybe a
Just TeamId
tId
                    MH ()
updateWindowTitle
                    MH ()
refreshTeamZipper

-- | Remove the specified team to the application state.
--
-- This is called in response to a server event indicating that the
-- current user was removed from the team.
handleLeaveTeam :: TeamId -> MH ()
handleLeaveTeam :: TeamId -> MH ()
handleLeaveTeam TeamId
tId =
    AsyncPriority -> IO (Maybe (MH ())) -> MH ()
doAsyncWith AsyncPriority
Normal (IO (Maybe (MH ())) -> MH ()) -> IO (Maybe (MH ())) -> MH ()
forall a b. (a -> b) -> a -> b
$ Maybe (MH ()) -> IO (Maybe (MH ()))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (MH ()) -> IO (Maybe (MH ())))
-> Maybe (MH ()) -> IO (Maybe (MH ()))
forall a b. (a -> b) -> a -> b
$ MH () -> Maybe (MH ())
forall a. a -> Maybe a
Just (MH () -> Maybe (MH ())) -> MH () -> Maybe (MH ())
forall a b. (a -> b) -> a -> b
$ do
        LogCategory -> Text -> MH ()
mhLog LogCategory
LogGeneral (Text -> MH ()) -> Text -> MH ()
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String
"Leaving team " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> TeamId -> String
forall a. Show a => a -> String
show TeamId
tId
        TeamId -> MH ()
removeTeam TeamId
tId
        MH ()
updateWindowTitle
        -- Invalidating the cache here expunges any cached message
        -- renderings from the team we are leaving.
        EventM Name () -> MH ()
forall a. EventM Name a -> MH a
mh EventM Name ()
forall n. Ord n => EventM n ()
invalidateCache

-- | Fetch the specified team's metadata and update it in the
-- application state.
--
-- This is called in response to a server event indicating that the
-- specified team was updated in some way.
handleUpdateTeam :: TeamId -> MH ()
handleUpdateTeam :: TeamId -> MH ()
handleUpdateTeam TeamId
tId = do
    Session
session <- MH Session
getSession
    LogCategory -> Text -> MH ()
mhLog LogCategory
LogGeneral (Text -> MH ()) -> Text -> MH ()
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String
"Updating team " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> TeamId -> String
forall a. Show a => a -> String
show TeamId
tId
    AsyncPriority -> IO (Maybe (MH ())) -> MH ()
doAsyncWith AsyncPriority
Normal (IO (Maybe (MH ())) -> MH ()) -> IO (Maybe (MH ())) -> MH ()
forall a b. (a -> b) -> a -> b
$ do
        Team
t <- TeamId -> Session -> IO Team
MM.mmGetTeam TeamId
tId Session
session
        Maybe (MH ()) -> IO (Maybe (MH ()))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (MH ()) -> IO (Maybe (MH ())))
-> Maybe (MH ()) -> IO (Maybe (MH ()))
forall a b. (a -> b) -> a -> b
$ MH () -> Maybe (MH ())
forall a. a -> Maybe a
Just (MH () -> Maybe (MH ())) -> MH () -> Maybe (MH ())
forall a b. (a -> b) -> a -> b
$ do
            Team -> MH ()
updateTeam Team
t
            -- Invalidate the cache since we happen to know that the
            -- team name is in the cached sidebar.
            EventM Name () -> MH ()
forall a. EventM Name a -> MH a
mh EventM Name ()
forall n. Ord n => EventM n ()
invalidateCache

-- | Set the team zipper ordering with the specified transformation,
-- which is expected to be either 'moveLeft' or 'moveRight'.
setTeamOrderWith :: (TeamId -> [TeamId] -> [TeamId]) -> MH ()
setTeamOrderWith :: (TeamId -> [TeamId] -> [TeamId]) -> MH ()
setTeamOrderWith TeamId -> [TeamId] -> [TeamId]
transform = do
    Session
session <- MH Session
getSession
    User
me <- Getting User ChatState User -> MH User
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting User ChatState User
Lens' ChatState User
csMe

    Maybe TeamId
mtId <- Getting (Maybe TeamId) ChatState (Maybe TeamId)
-> MH (Maybe TeamId)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting (Maybe TeamId) ChatState (Maybe TeamId)
SimpleGetter ChatState (Maybe TeamId)
csCurrentTeamId
    Zipper () TeamId
z <- Getting (Zipper () TeamId) ChatState (Zipper () TeamId)
-> MH (Zipper () TeamId)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting (Zipper () TeamId) ChatState (Zipper () TeamId)
Lens' ChatState (Zipper () TeamId)
csTeamZipper
    let tIds :: [TeamId]
tIds = Zipper () TeamId -> [TeamId]
teamZipperIds Zipper () TeamId
z
        newList :: [TeamId]
newList = [TeamId] -> (TeamId -> [TeamId]) -> Maybe TeamId -> [TeamId]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [TeamId]
tIds (\TeamId
tId -> TeamId -> [TeamId] -> [TeamId]
transform TeamId
tId [TeamId]
tIds) Maybe TeamId
mtId

    AsyncPriority -> IO (Maybe (MH ())) -> MH ()
doAsyncWith AsyncPriority
Normal (IO (Maybe (MH ())) -> MH ()) -> IO (Maybe (MH ())) -> MH ()
forall a b. (a -> b) -> a -> b
$ do
        let pref :: Preference
pref = UserId -> [TeamId] -> Preference
teamOrderPref (User
meUser -> Getting UserId User UserId -> UserId
forall s a. s -> Getting a s a -> a
^.Getting UserId User UserId
Lens' User UserId
userIdL) [TeamId]
newList
        UserParam -> Seq Preference -> Session -> IO ()
MM.mmSaveUsersPreferences UserParam
UserMe (Preference -> Seq Preference
forall a. a -> Seq a
Seq.singleton Preference
pref) Session
session
        Maybe (MH ()) -> IO (Maybe (MH ()))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (MH ())
forall a. Maybe a
Nothing

-- | Move the selected team left in the team list.
moveCurrentTeamLeft :: MH ()
moveCurrentTeamLeft :: MH ()
moveCurrentTeamLeft = (TeamId -> [TeamId] -> [TeamId]) -> MH ()
setTeamOrderWith TeamId -> [TeamId] -> [TeamId]
forall a. Eq a => a -> [a] -> [a]
moveLeft

-- | Move the selected team right in the team list.
moveCurrentTeamRight :: MH ()
moveCurrentTeamRight :: MH ()
moveCurrentTeamRight = (TeamId -> [TeamId] -> [TeamId]) -> MH ()
setTeamOrderWith TeamId -> [TeamId] -> [TeamId]
forall a. Eq a => a -> [a] -> [a]
moveRight

-- | Build a new 'TeamState' for the specified team.
--
-- This function starts a new spell checker thread for the team's
-- message editor, loads the last-run state for the team (to ensure that
-- the initially-selected channel is honored), and fetches the channel
-- metadata for the team.
--
-- This returns the resulting team state as well as the channels
-- associated with the team. The caller is responsible for adding the
-- channels and the team state to the application state.
buildTeamState :: ChatResources -> User -> Team -> IO (TeamState, ClientChannels)
buildTeamState :: ChatResources -> User -> Team -> IO (TeamState, ClientChannels)
buildTeamState ChatResources
cr User
me Team
team = do
    let tId :: TeamId
tId = Team -> TeamId
teamId Team
team
        session :: Session
session = ChatResources -> Session
getResourceSession ChatResources
cr
        config :: Config
config = ChatResources
crChatResources -> Getting Config ChatResources Config -> Config
forall s a. s -> Getting a s a -> a
^.Getting Config ChatResources Config
Lens' ChatResources Config
crConfiguration
        eventQueue :: BChan MHEvent
eventQueue = ChatResources
crChatResources
-> Getting (BChan MHEvent) ChatResources (BChan MHEvent)
-> BChan MHEvent
forall s a. s -> Getting a s a -> a
^.Getting (BChan MHEvent) ChatResources (BChan MHEvent)
Lens' ChatResources (BChan MHEvent)
crEventQueue

    Either String LastRunState
lrsResult <- TeamId -> IO (Either String LastRunState)
readLastRunState TeamId
tId
    let mLrs :: Maybe LastRunState
mLrs = case Either String LastRunState
lrsResult of
            Right LastRunState
lrs | ChatResources -> User -> LastRunState -> Bool
isValidLastRunState ChatResources
cr User
me LastRunState
lrs -> LastRunState -> Maybe LastRunState
forall a. a -> Maybe a
Just LastRunState
lrs
            Either String LastRunState
_ -> Maybe LastRunState
forall a. Maybe a
Nothing

        -- Create a predicate to find the last selected channel by
        -- checking the last run state.
        isLastSelectedChannel :: Channel -> Bool
isLastSelectedChannel = (Channel -> Bool)
-> (LastRunState -> Channel -> Bool)
-> Maybe LastRunState
-> Channel
-> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Channel -> Bool
isTownSquare (\LastRunState
lrs Channel
c -> ChannelId -> Maybe ChannelId
forall a. a -> Maybe a
Just (Channel -> ChannelId
channelId Channel
c) Maybe ChannelId -> Maybe ChannelId -> Bool
forall a. Eq a => a -> a -> Bool
== LastRunState
lrsLastRunState
-> Getting (Maybe ChannelId) LastRunState (Maybe ChannelId)
-> Maybe ChannelId
forall s a. s -> Getting a s a -> a
^.Getting (Maybe ChannelId) LastRunState (Maybe ChannelId)
Lens' LastRunState (Maybe ChannelId)
lrsSelectedChannelId) Maybe LastRunState
mLrs

    -- Get all channels, but filter down to just the one we want
    -- to start in. We get all, rather than requesting by name or
    -- ID, because we don't know whether the server will give us a
    -- last-viewed preference. We first try to find a channel matching
    -- with the last selected channel ID, failing which we look for the
    -- Town Square channel by name.
    Seq Channel
userChans <- UserParam -> TeamId -> Session -> IO (Seq Channel)
MM.mmGetChannelsForUser UserParam
UserMe TeamId
tId Session
session
    let lastSelectedChans :: Seq Channel
lastSelectedChans = (Channel -> Bool) -> Seq Channel -> Seq Channel
forall a. (a -> Bool) -> Seq a -> Seq a
Seq.filter Channel -> Bool
isLastSelectedChannel Seq Channel
userChans
        chans :: Seq Channel
chans = if Seq Channel -> Bool
forall a. Seq a -> Bool
Seq.null Seq Channel
lastSelectedChans
                  then (Channel -> Bool) -> Seq Channel -> Seq Channel
forall a. (a -> Bool) -> Seq a -> Seq a
Seq.filter Channel -> Bool
isTownSquare Seq Channel
userChans
                  else Seq Channel
lastSelectedChans

    -- Since the only channel we are dealing with is by construction the
    -- last channel, we don't have to consider other cases here:
    [(ChannelId, ClientChannel)]
chanPairs <- [Channel]
-> (Channel -> IO (ChannelId, ClientChannel))
-> IO [(ChannelId, ClientChannel)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM (Seq Channel -> [Channel]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Seq Channel
chans) ((Channel -> IO (ChannelId, ClientChannel))
 -> IO [(ChannelId, ClientChannel)])
-> (Channel -> IO (ChannelId, ClientChannel))
-> IO [(ChannelId, ClientChannel)]
forall a b. (a -> b) -> a -> b
$ \Channel
c -> do
        ClientChannel
cChannel <- BChan MHEvent
-> Maybe Aspell
-> UserId
-> Maybe TeamId
-> Channel
-> IO ClientChannel
forall (m :: * -> *).
MonadIO m =>
BChan MHEvent
-> Maybe Aspell
-> UserId
-> Maybe TeamId
-> Channel
-> m ClientChannel
makeClientChannel BChan MHEvent
eventQueue (ChatResources
crChatResources
-> Getting (Maybe Aspell) ChatResources (Maybe Aspell)
-> Maybe Aspell
forall s a. s -> Getting a s a -> a
^.Getting (Maybe Aspell) ChatResources (Maybe Aspell)
Lens' ChatResources (Maybe Aspell)
crSpellChecker) (User -> UserId
userId User
me) (TeamId -> Maybe TeamId
forall a. a -> Maybe a
Just TeamId
tId) Channel
c
        (ChannelId, ClientChannel) -> IO (ChannelId, ClientChannel)
forall (m :: * -> *) a. Monad m => a -> m a
return (Channel -> ChannelId
forall x y. HasId x y => x -> y
getId Channel
c, ClientChannel
cChannel)

    UTCTime
now <- IO UTCTime
getCurrentTime
    let chanIds :: [(ChannelListGroup, [ChannelListEntry])]
chanIds = ChannelListSorting
-> UTCTime
-> Config
-> TeamId
-> Maybe ClientConfig
-> UserPreferences
-> HashMap TeamId (Set ChannelListGroupLabel)
-> ClientChannels
-> Users
-> [(ChannelListGroup, [ChannelListEntry])]
mkChannelZipperList (Config
configConfig
-> Getting ChannelListSorting Config ChannelListSorting
-> ChannelListSorting
forall s a. s -> Getting a s a -> a
^.Getting ChannelListSorting Config ChannelListSorting
Lens' Config ChannelListSorting
configChannelListSortingL) UTCTime
now Config
config TeamId
tId
                                          Maybe ClientConfig
forall a. Maybe a
Nothing (ChatResources
crChatResources
-> Getting UserPreferences ChatResources UserPreferences
-> UserPreferences
forall s a. s -> Getting a s a -> a
^.Getting UserPreferences ChatResources UserPreferences
Lens' ChatResources UserPreferences
crUserPreferences)
                                          HashMap TeamId (Set ChannelListGroupLabel)
forall a. Monoid a => a
mempty ClientChannels
clientChans Users
noUsers
        chanZip :: Zipper ChannelListGroup ChannelListEntry
chanZip = [(ChannelListGroup, [ChannelListEntry])]
-> Zipper ChannelListGroup ChannelListEntry
forall b a. Eq b => [(a, [b])] -> Zipper a b
Z.fromList [(ChannelListGroup, [ChannelListEntry])]
chanIds
        clientChans :: ClientChannels
clientChans = ((ChannelId, ClientChannel) -> ClientChannels -> ClientChannels)
-> ClientChannels -> [(ChannelId, ClientChannel)] -> ClientChannels
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ((ChannelId -> ClientChannel -> ClientChannels -> ClientChannels)
-> (ChannelId, ClientChannel) -> ClientChannels -> ClientChannels
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ChannelId -> ClientChannel -> ClientChannels -> ClientChannels
addChannel) ClientChannels
noChannels [(ChannelId, ClientChannel)]
chanPairs

    -- If the configuration says to open any last open thread, then
    -- schedule it to be opened.
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Config -> Bool
configShowLastOpenThread Config
config) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
        let maybeOpenThread :: Maybe (IO ())
maybeOpenThread = do
                LastRunState
lrs <- Maybe LastRunState
mLrs
                (ChannelId
cId, PostId
pId) <- LastRunState
lrsLastRunState
-> Getting
     (Maybe (ChannelId, PostId))
     LastRunState
     (Maybe (ChannelId, PostId))
-> Maybe (ChannelId, PostId)
forall s a. s -> Getting a s a -> a
^.Getting
  (Maybe (ChannelId, PostId))
  LastRunState
  (Maybe (ChannelId, PostId))
Lens' LastRunState (Maybe (ChannelId, PostId))
lrsOpenThread
                IO () -> Maybe (IO ())
forall (m :: * -> *) a. Monad m => a -> m a
return (IO () -> Maybe (IO ())) -> IO () -> Maybe (IO ())
forall a b. (a -> b) -> a -> b
$ ChatResources -> MH () -> IO ()
scheduleMH ChatResources
cr (TeamId -> ChannelId -> PostId -> MH ()
openThreadWindow TeamId
tId ChannelId
cId PostId
pId)
        IO () -> Maybe (IO ()) -> IO ()
forall a. a -> Maybe a -> a
fromMaybe (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) Maybe (IO ())
maybeOpenThread

    let ts :: TeamState
ts = Config
-> Team -> Zipper ChannelListGroup ChannelListEntry -> TeamState
newTeamState Config
config Team
team Zipper ChannelListGroup ChannelListEntry
chanZip
    (TeamState, ClientChannels) -> IO (TeamState, ClientChannels)
forall (m :: * -> *) a. Monad m => a -> m a
return (TeamState
ts, ClientChannels
clientChans)

-- | Add a new 'TeamState' and corresponding channels to the application
-- state.
addTeamState :: TeamState -> ClientChannels -> MH ()
addTeamState :: TeamState -> ClientChannels -> MH ()
addTeamState TeamState
ts ClientChannels
chans = do
    let tId :: TeamId
tId = Team -> TeamId
teamId (Team -> TeamId) -> Team -> TeamId
forall a b. (a -> b) -> a -> b
$ TeamState -> Team
_tsTeam TeamState
ts
    (HashMap TeamId TeamState -> Identity (HashMap TeamId TeamState))
-> ChatState -> Identity ChatState
Lens' ChatState (HashMap TeamId TeamState)
csTeams((HashMap TeamId TeamState -> Identity (HashMap TeamId TeamState))
 -> ChatState -> Identity ChatState)
-> ((Maybe TeamState -> Identity (Maybe TeamState))
    -> HashMap TeamId TeamState -> Identity (HashMap TeamId TeamState))
-> (Maybe TeamState -> Identity (Maybe TeamState))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Index (HashMap TeamId TeamState)
-> Lens'
     (HashMap TeamId TeamState)
     (Maybe (IxValue (HashMap TeamId TeamState)))
forall m. At m => Index m -> Lens' m (Maybe (IxValue m))
at TeamId
Index (HashMap TeamId TeamState)
tId ((Maybe TeamState -> Identity (Maybe TeamState))
 -> ChatState -> Identity ChatState)
-> Maybe TeamState -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= TeamState -> Maybe TeamState
forall a. a -> Maybe a
Just TeamState
ts
    (ClientChannels -> Identity ClientChannels)
-> ChatState -> Identity ChatState
Lens' ChatState ClientChannels
csChannels ((ClientChannels -> Identity ClientChannels)
 -> ChatState -> Identity ChatState)
-> (ClientChannels -> ClientChannels) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (ClientChannels
chans ClientChannels -> ClientChannels -> ClientChannels
forall a. Semigroup a => a -> a -> a
<>)

-- | Update the specified team metadata in the application state (only
-- if we are already a member of that team).
updateTeam :: Team -> MH ()
updateTeam :: Team -> MH ()
updateTeam Team
t = do
    let tId :: TeamId
tId = Team -> TeamId
teamId Team
t
    HashMap TeamId TeamState
ts <- Getting
  (HashMap TeamId TeamState) ChatState (HashMap TeamId TeamState)
-> MH (HashMap TeamId TeamState)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting
  (HashMap TeamId TeamState) ChatState (HashMap TeamId TeamState)
Lens' ChatState (HashMap TeamId TeamState)
csTeams
    Bool -> MH () -> MH ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (TeamId
tId TeamId -> [TeamId] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` HashMap TeamId TeamState -> [TeamId]
forall k v. HashMap k v -> [k]
HM.keys HashMap TeamId TeamState
ts) (MH () -> MH ()) -> MH () -> MH ()
forall a b. (a -> b) -> a -> b
$ do
        TeamId -> Lens' ChatState TeamState
csTeam(TeamId
tId)((TeamState -> Identity TeamState)
 -> ChatState -> Identity ChatState)
-> ((Team -> Identity Team) -> TeamState -> Identity TeamState)
-> (Team -> Identity Team)
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Team -> Identity Team) -> TeamState -> Identity TeamState
Lens' TeamState Team
tsTeam ((Team -> Identity Team) -> ChatState -> Identity ChatState)
-> Team -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Team
t

-- | Remove the specified team from the application state.
removeTeam :: TeamId -> MH ()
removeTeam :: TeamId -> MH ()
removeTeam TeamId
tId = do
    (HashMap TeamId TeamState -> Identity (HashMap TeamId TeamState))
-> ChatState -> Identity ChatState
Lens' ChatState (HashMap TeamId TeamState)
csTeams((HashMap TeamId TeamState -> Identity (HashMap TeamId TeamState))
 -> ChatState -> Identity ChatState)
-> ((Maybe TeamState -> Identity (Maybe TeamState))
    -> HashMap TeamId TeamState -> Identity (HashMap TeamId TeamState))
-> (Maybe TeamState -> Identity (Maybe TeamState))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Index (HashMap TeamId TeamState)
-> Lens'
     (HashMap TeamId TeamState)
     (Maybe (IxValue (HashMap TeamId TeamState)))
forall m. At m => Index m -> Lens' m (Maybe (IxValue m))
at TeamId
Index (HashMap TeamId TeamState)
tId ((Maybe TeamState -> Identity (Maybe TeamState))
 -> ChatState -> Identity ChatState)
-> Maybe TeamState -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Maybe TeamState
forall a. Maybe a
Nothing
    (Zipper () TeamId -> Zipper () TeamId) -> MH ()
setTeamFocusWith ((Zipper () TeamId -> Zipper () TeamId) -> MH ())
-> (Zipper () TeamId -> Zipper () TeamId) -> MH ()
forall a b. (a -> b) -> a -> b
$ (TeamId -> Bool) -> Zipper () TeamId -> Zipper () TeamId
forall b a. Eq b => (b -> Bool) -> Zipper a b -> Zipper a b
Z.filterZipper (TeamId -> TeamId -> Bool
forall a. Eq a => a -> a -> Bool
/= TeamId
tId)

cycleTeamMessageInterfaceFocus :: TeamId -> MH ()
cycleTeamMessageInterfaceFocus :: TeamId -> MH ()
cycleTeamMessageInterfaceFocus TeamId
tId =
    TeamId -> Lens' ChatState TeamState
csTeam(TeamId
tId) ((TeamState -> Identity TeamState)
 -> ChatState -> Identity ChatState)
-> (TeamState -> TeamState) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= TeamState -> TeamState
messageInterfaceFocusNext

emptyEditStateForChannel :: Maybe Aspell -> BCH.BChan MHEvent -> Maybe TeamId -> ChannelId -> IO (EditState Name)
emptyEditStateForChannel :: Maybe Aspell
-> BChan MHEvent
-> Maybe TeamId
-> ChannelId
-> IO (EditState Name)
emptyEditStateForChannel Maybe Aspell
checker BChan MHEvent
eventQueue Maybe TeamId
tId ChannelId
cId = do
    Maybe (IO ())
reset <- case Maybe Aspell
checker of
        Maybe Aspell
Nothing -> Maybe (IO ()) -> IO (Maybe (IO ()))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (IO ())
forall a. Maybe a
Nothing
        Just Aspell
as -> IO () -> Maybe (IO ())
forall a. a -> Maybe a
Just (IO () -> Maybe (IO ())) -> IO (IO ()) -> IO (Maybe (IO ()))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Aspell -> BChan MHEvent -> MessageInterfaceTarget -> IO (IO ())
newSpellCheckTimer Aspell
as BChan MHEvent
eventQueue (MessageInterfaceTarget -> IO (IO ()))
-> MessageInterfaceTarget -> IO (IO ())
forall a b. (a -> b) -> a -> b
$ ChannelId -> MessageInterfaceTarget
MIChannel ChannelId
cId)
    let editorName :: Name
editorName = ChannelId -> Name
MessageInput ChannelId
cId
        attachmentListName :: Name
attachmentListName = ChannelId -> Name
AttachmentList ChannelId
cId
    EditState Name -> IO (EditState Name)
forall (m :: * -> *) a. Monad m => a -> m a
return (EditState Name -> IO (EditState Name))
-> EditState Name -> IO (EditState Name)
forall a b. (a -> b) -> a -> b
$ Name
-> Name
-> Maybe TeamId
-> ChannelId
-> EditMode
-> Bool
-> Maybe (IO ())
-> EditState Name
forall n.
n
-> n
-> Maybe TeamId
-> ChannelId
-> EditMode
-> Bool
-> Maybe (IO ())
-> EditState n
newEditState Name
editorName Name
attachmentListName Maybe TeamId
tId ChannelId
cId EditMode
NewPost Bool
True Maybe (IO ())
reset

emptyEditStateForThread :: Maybe Aspell -> BCH.BChan MHEvent -> TeamId -> ChannelId -> EditMode -> IO (EditState Name)
emptyEditStateForThread :: Maybe Aspell
-> BChan MHEvent
-> TeamId
-> ChannelId
-> EditMode
-> IO (EditState Name)
emptyEditStateForThread Maybe Aspell
checker BChan MHEvent
eventQueue TeamId
tId ChannelId
cId EditMode
initialEditMode = do
    Maybe (IO ())
reset <- case Maybe Aspell
checker of
        Maybe Aspell
Nothing -> Maybe (IO ()) -> IO (Maybe (IO ()))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (IO ())
forall a. Maybe a
Nothing
        Just Aspell
as -> IO () -> Maybe (IO ())
forall a. a -> Maybe a
Just (IO () -> Maybe (IO ())) -> IO (IO ()) -> IO (Maybe (IO ()))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Aspell -> BChan MHEvent -> MessageInterfaceTarget -> IO (IO ())
newSpellCheckTimer Aspell
as BChan MHEvent
eventQueue (MessageInterfaceTarget -> IO (IO ()))
-> MessageInterfaceTarget -> IO (IO ())
forall a b. (a -> b) -> a -> b
$ TeamId -> MessageInterfaceTarget
MITeamThread TeamId
tId)
    let editorName :: Name
editorName = ChannelId -> Name
ThreadMessageInput ChannelId
cId
        attachmentListName :: Name
attachmentListName = ChannelId -> Name
ThreadEditorAttachmentList ChannelId
cId
    EditState Name -> IO (EditState Name)
forall (m :: * -> *) a. Monad m => a -> m a
return (EditState Name -> IO (EditState Name))
-> EditState Name -> IO (EditState Name)
forall a b. (a -> b) -> a -> b
$ Name
-> Name
-> Maybe TeamId
-> ChannelId
-> EditMode
-> Bool
-> Maybe (IO ())
-> EditState Name
forall n.
n
-> n
-> Maybe TeamId
-> ChannelId
-> EditMode
-> Bool
-> Maybe (IO ())
-> EditState n
newEditState Name
editorName Name
attachmentListName (TeamId -> Maybe TeamId
forall a. a -> Maybe a
Just TeamId
tId) ChannelId
cId EditMode
initialEditMode Bool
False Maybe (IO ())
reset

newThreadInterface :: Maybe Aspell
                   -> BCH.BChan MHEvent
                   -> TeamId
                   -> ChannelId
                   -> Message
                   -> Post
                   -> Messages
                   -> IO ThreadInterface
newThreadInterface :: Maybe Aspell
-> BChan MHEvent
-> TeamId
-> ChannelId
-> Message
-> Post
-> Messages
-> IO ThreadInterface
newThreadInterface Maybe Aspell
checker BChan MHEvent
eventQueue TeamId
tId ChannelId
cId Message
rootMsg Post
rootPost Messages
msgs = do
    EditState Name
es <- Maybe Aspell
-> BChan MHEvent
-> TeamId
-> ChannelId
-> EditMode
-> IO (EditState Name)
emptyEditStateForThread Maybe Aspell
checker BChan MHEvent
eventQueue TeamId
tId ChannelId
cId (Message -> Post -> EditMode
Replying Message
rootMsg Post
rootPost)
    ThreadInterface -> IO ThreadInterface
forall (m :: * -> *) a. Monad m => a -> m a
return (ThreadInterface -> IO ThreadInterface)
-> ThreadInterface -> IO ThreadInterface
forall a b. (a -> b) -> a -> b
$ ChannelId
-> PostId
-> Messages
-> EditState Name
-> MessageInterfaceTarget
-> URLListSource
-> ThreadInterface
forall i.
ChannelId
-> i
-> Messages
-> EditState Name
-> MessageInterfaceTarget
-> URLListSource
-> MessageInterface Name i
newMessageInterface ChannelId
cId (Post -> PostId
postId Post
rootPost) Messages
msgs EditState Name
es (TeamId -> MessageInterfaceTarget
MITeamThread TeamId
tId) (ChannelId -> URLListSource
FromThreadIn ChannelId
cId)

newChannelMessageInterface :: Maybe Aspell
                           -> BCH.BChan MHEvent
                           -> Maybe TeamId
                           -> ChannelId
                           -> Messages
                           -> IO ChannelMessageInterface
newChannelMessageInterface :: Maybe Aspell
-> BChan MHEvent
-> Maybe TeamId
-> ChannelId
-> Messages
-> IO ChannelMessageInterface
newChannelMessageInterface Maybe Aspell
checker BChan MHEvent
eventQueue Maybe TeamId
tId ChannelId
cId Messages
msgs = do
    EditState Name
es <- Maybe Aspell
-> BChan MHEvent
-> Maybe TeamId
-> ChannelId
-> IO (EditState Name)
emptyEditStateForChannel Maybe Aspell
checker BChan MHEvent
eventQueue Maybe TeamId
tId ChannelId
cId
    ChannelMessageInterface -> IO ChannelMessageInterface
forall (m :: * -> *) a. Monad m => a -> m a
return (ChannelMessageInterface -> IO ChannelMessageInterface)
-> ChannelMessageInterface -> IO ChannelMessageInterface
forall a b. (a -> b) -> a -> b
$ ChannelId
-> ()
-> Messages
-> EditState Name
-> MessageInterfaceTarget
-> URLListSource
-> ChannelMessageInterface
forall i.
ChannelId
-> i
-> Messages
-> EditState Name
-> MessageInterfaceTarget
-> URLListSource
-> MessageInterface Name i
newMessageInterface ChannelId
cId () Messages
msgs EditState Name
es (ChannelId -> MessageInterfaceTarget
MIChannel ChannelId
cId) (ChannelId -> URLListSource
FromChannel ChannelId
cId)

newMessageInterface :: ChannelId
                    -> i
                    -> Messages
                    -> EditState Name
                    -> MessageInterfaceTarget
                    -> URLListSource
                    -> MessageInterface Name i
newMessageInterface :: ChannelId
-> i
-> Messages
-> EditState Name
-> MessageInterfaceTarget
-> URLListSource
-> MessageInterface Name i
newMessageInterface ChannelId
cId i
pId Messages
msgs EditState Name
es MessageInterfaceTarget
target URLListSource
src =
    let urlListName :: Name
urlListName = Name -> Name
UrlList Name
eName
        eName :: Name
eName = Editor Text Name -> Name
forall a n. Named a n => a -> n
getName (Editor Text Name -> Name) -> Editor Text Name -> Name
forall a b. (a -> b) -> a -> b
$ EditState Name
esEditState Name
-> Getting (Editor Text Name) (EditState Name) (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.Getting (Editor Text Name) (EditState Name) (Editor Text Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor
    in MessageInterface :: forall n i.
Messages
-> EditState n
-> MessageSelectState
-> i
-> ChannelId
-> MessageInterfaceMode
-> MessageInterfaceTarget
-> URLListSource
-> URLList n
-> SaveAttachmentDialogState n
-> MessageInterface n i
MessageInterface { _miMessages :: Messages
_miMessages = Messages
msgs
                        , _miRootPostId :: i
_miRootPostId = i
pId
                        , _miChannelId :: ChannelId
_miChannelId = ChannelId
cId
                        , _miMessageSelect :: MessageSelectState
_miMessageSelect = Maybe MessageId -> MessageSelectState
MessageSelectState Maybe MessageId
forall a. Maybe a
Nothing
                        , _miMode :: MessageInterfaceMode
_miMode = MessageInterfaceMode
Compose
                        , _miEditor :: EditState Name
_miEditor = EditState Name
es
                        , _miTarget :: MessageInterfaceTarget
_miTarget = MessageInterfaceTarget
target
                        , _miUrlListSource :: URLListSource
_miUrlListSource = URLListSource
src
                        , _miUrlList :: URLList Name
_miUrlList = URLList :: forall n.
List n (Int, LinkChoice) -> Maybe URLListSource -> URLList n
URLList { _ulList :: List Name (Int, LinkChoice)
_ulList = Name
-> Vector (Int, LinkChoice) -> Int -> List Name (Int, LinkChoice)
forall (t :: * -> *) n e.
Foldable t =>
n -> t e -> Int -> GenericList n t e
list Name
urlListName Vector (Int, LinkChoice)
forall a. Monoid a => a
mempty Int
2
                                               , _ulSource :: Maybe URLListSource
_ulSource = Maybe URLListSource
forall a. Maybe a
Nothing
                                               }
                        , _miSaveAttachmentDialog :: SaveAttachmentDialogState Name
_miSaveAttachmentDialog = Name -> Text -> SaveAttachmentDialogState Name
newSaveAttachmentDialog Name
eName Text
"(unused)"
                        }

newTeamState :: Config
             -> Team
             -> Z.Zipper ChannelListGroup ChannelListEntry
             -> TeamState
newTeamState :: Config
-> Team -> Zipper ChannelListGroup ChannelListEntry -> TeamState
newTeamState Config
config Team
team Zipper ChannelListGroup ChannelListEntry
chanList =
    let tId :: TeamId
tId = Team -> TeamId
teamId Team
team
    in TeamState :: Zipper ChannelListGroup ChannelListEntry
-> Team
-> Maybe ChannelId
-> Maybe ChannelId
-> NonemptyStack Mode
-> ChannelSelectState
-> Maybe PendingChannelChange
-> Maybe
     (Message, TabbedWindow ChatState MH Name ViewMessageWindowTab)
-> PostListWindowState
-> ListWindowState UserInfo UserSearchScope
-> ListWindowState Channel ChannelSearchScope
-> Maybe (Form ChannelNotifyProps MHEvent Name)
-> ChannelTopicDialogState
-> ListWindowState (Bool, Text) ()
-> ListWindowState InternalTheme ()
-> ChannelListSorting
-> Maybe ThreadInterface
-> MessageInterfaceFocus
-> TeamState
TeamState { _tsModeStack :: NonemptyStack Mode
_tsModeStack                = Mode -> NonemptyStack Mode
forall a. a -> NonemptyStack a
newStack Mode
Main
                 , _tsFocus :: Zipper ChannelListGroup ChannelListEntry
_tsFocus                    = Zipper ChannelListGroup ChannelListEntry
chanList
                 , _tsTeam :: Team
_tsTeam                     = Team
team
                 , _tsPostListWindow :: PostListWindowState
_tsPostListWindow           = Messages -> Maybe PostId -> PostListWindowState
PostListWindowState Messages
forall dir a. DirectionalSeq dir a
emptyDirSeq Maybe PostId
forall a. Maybe a
Nothing
                 , _tsUserListWindow :: ListWindowState UserInfo UserSearchScope
_tsUserListWindow           = TeamId -> ListWindowState UserInfo UserSearchScope
nullUserListWindowState TeamId
tId
                 , _tsChannelListWindow :: ListWindowState Channel ChannelSearchScope
_tsChannelListWindow        = TeamId -> ListWindowState Channel ChannelSearchScope
nullChannelListWindowState TeamId
tId
                 , _tsChannelSelectState :: ChannelSelectState
_tsChannelSelectState       = TeamId -> ChannelSelectState
emptyChannelSelectState TeamId
tId
                 , _tsChannelTopicDialog :: ChannelTopicDialogState
_tsChannelTopicDialog       = TeamId -> Text -> ChannelTopicDialogState
newChannelTopicDialog TeamId
tId Text
""
                 , _tsNotifyPrefs :: Maybe (Form ChannelNotifyProps MHEvent Name)
_tsNotifyPrefs              = Maybe (Form ChannelNotifyProps MHEvent Name)
forall a. Maybe a
Nothing
                 , _tsPendingChannelChange :: Maybe PendingChannelChange
_tsPendingChannelChange     = Maybe PendingChannelChange
forall a. Maybe a
Nothing
                 , _tsRecentChannel :: Maybe ChannelId
_tsRecentChannel            = Maybe ChannelId
forall a. Maybe a
Nothing
                 , _tsReturnChannel :: Maybe ChannelId
_tsReturnChannel            = Maybe ChannelId
forall a. Maybe a
Nothing
                 , _tsViewedMessage :: Maybe
  (Message, TabbedWindow ChatState MH Name ViewMessageWindowTab)
_tsViewedMessage            = Maybe
  (Message, TabbedWindow ChatState MH Name ViewMessageWindowTab)
forall a. Maybe a
Nothing
                 , _tsThemeListWindow :: ListWindowState InternalTheme ()
_tsThemeListWindow          = TeamId -> ListWindowState InternalTheme ()
nullThemeListWindowState TeamId
tId
                 , _tsReactionEmojiListWindow :: ListWindowState (Bool, Text) ()
_tsReactionEmojiListWindow  = TeamId -> ListWindowState (Bool, Text) ()
nullEmojiListWindowState TeamId
tId
                 , _tsChannelListSorting :: ChannelListSorting
_tsChannelListSorting       = Config -> ChannelListSorting
configChannelListSorting Config
config
                 , _tsThreadInterface :: Maybe ThreadInterface
_tsThreadInterface          = Maybe ThreadInterface
forall a. Maybe a
Nothing
                 , _tsMessageInterfaceFocus :: MessageInterfaceFocus
_tsMessageInterfaceFocus    = MessageInterfaceFocus
FocusCurrentChannel
                 }

nullChannelListWindowState :: TeamId -> ListWindowState Channel ChannelSearchScope
nullChannelListWindowState :: TeamId -> ListWindowState Channel ChannelSearchScope
nullChannelListWindowState TeamId
tId =
    let newList :: t e -> GenericList Name t e
newList t e
rs = Name -> t e -> Int -> GenericList Name t e
forall (t :: * -> *) n e.
Foldable t =>
n -> t e -> Int -> GenericList n t e
list (TeamId -> Name
JoinChannelList TeamId
tId) t e
rs Int
2
    in ListWindowState :: forall a b.
List Name a
-> Editor Text Name
-> b
-> Bool
-> (a -> MH Bool)
-> (Vector a -> List Name a)
-> (b -> Session -> Text -> IO (Vector a))
-> Maybe Int
-> ListWindowState a b
ListWindowState { _listWindowSearchResults :: List Name Channel
_listWindowSearchResults  = Vector Channel -> List Name Channel
forall (t :: * -> *) e. Foldable t => t e -> GenericList Name t e
newList Vector Channel
forall a. Monoid a => a
mempty
                       , _listWindowSearchInput :: Editor Text Name
_listWindowSearchInput    = Name -> Maybe Int -> Text -> Editor Text Name
forall a n.
GenericTextZipper a =>
n -> Maybe Int -> a -> Editor a n
editor (TeamId -> Name
JoinChannelListSearchInput TeamId
tId) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
1) Text
""
                       , _listWindowSearchScope :: ChannelSearchScope
_listWindowSearchScope    = ChannelSearchScope
AllChannels
                       , _listWindowSearching :: Bool
_listWindowSearching      = Bool
False
                       , _listWindowEnterHandler :: Channel -> MH Bool
_listWindowEnterHandler   = MH Bool -> Channel -> MH Bool
forall a b. a -> b -> a
const (MH Bool -> Channel -> MH Bool) -> MH Bool -> Channel -> MH Bool
forall a b. (a -> b) -> a -> b
$ Bool -> MH Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
                       , _listWindowNewList :: Vector Channel -> List Name Channel
_listWindowNewList        = Vector Channel -> List Name Channel
forall (t :: * -> *) e. Foldable t => t e -> GenericList Name t e
newList
                       , _listWindowFetchResults :: ChannelSearchScope -> Session -> Text -> IO (Vector Channel)
_listWindowFetchResults   = (Session -> Text -> IO (Vector Channel))
-> ChannelSearchScope -> Session -> Text -> IO (Vector Channel)
forall a b. a -> b -> a
const ((Session -> Text -> IO (Vector Channel))
 -> ChannelSearchScope -> Session -> Text -> IO (Vector Channel))
-> (Session -> Text -> IO (Vector Channel))
-> ChannelSearchScope
-> Session
-> Text
-> IO (Vector Channel)
forall a b. (a -> b) -> a -> b
$ (Text -> IO (Vector Channel))
-> Session -> Text -> IO (Vector Channel)
forall a b. a -> b -> a
const ((Text -> IO (Vector Channel))
 -> Session -> Text -> IO (Vector Channel))
-> (Text -> IO (Vector Channel))
-> Session
-> Text
-> IO (Vector Channel)
forall a b. (a -> b) -> a -> b
$ IO (Vector Channel) -> Text -> IO (Vector Channel)
forall a b. a -> b -> a
const (IO (Vector Channel) -> Text -> IO (Vector Channel))
-> IO (Vector Channel) -> Text -> IO (Vector Channel)
forall a b. (a -> b) -> a -> b
$ Vector Channel -> IO (Vector Channel)
forall (m :: * -> *) a. Monad m => a -> m a
return Vector Channel
forall a. Monoid a => a
mempty
                       , _listWindowRecordCount :: Maybe Int
_listWindowRecordCount    = Maybe Int
forall a. Maybe a
Nothing
                       }

nullThemeListWindowState :: TeamId -> ListWindowState InternalTheme ()
nullThemeListWindowState :: TeamId -> ListWindowState InternalTheme ()
nullThemeListWindowState TeamId
tId =
    let newList :: t e -> GenericList Name t e
newList t e
rs = Name -> t e -> Int -> GenericList Name t e
forall (t :: * -> *) n e.
Foldable t =>
n -> t e -> Int -> GenericList n t e
list (TeamId -> Name
ThemeListSearchResults TeamId
tId) t e
rs Int
3
    in ListWindowState :: forall a b.
List Name a
-> Editor Text Name
-> b
-> Bool
-> (a -> MH Bool)
-> (Vector a -> List Name a)
-> (b -> Session -> Text -> IO (Vector a))
-> Maybe Int
-> ListWindowState a b
ListWindowState { _listWindowSearchResults :: List Name InternalTheme
_listWindowSearchResults  = Vector InternalTheme -> List Name InternalTheme
forall (t :: * -> *) e. Foldable t => t e -> GenericList Name t e
newList Vector InternalTheme
forall a. Monoid a => a
mempty
                       , _listWindowSearchInput :: Editor Text Name
_listWindowSearchInput    = Name -> Maybe Int -> Text -> Editor Text Name
forall a n.
GenericTextZipper a =>
n -> Maybe Int -> a -> Editor a n
editor (TeamId -> Name
ThemeListSearchInput TeamId
tId) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
1) Text
""
                       , _listWindowSearchScope :: ()
_listWindowSearchScope    = ()
                       , _listWindowSearching :: Bool
_listWindowSearching      = Bool
False
                       , _listWindowEnterHandler :: InternalTheme -> MH Bool
_listWindowEnterHandler   = MH Bool -> InternalTheme -> MH Bool
forall a b. a -> b -> a
const (MH Bool -> InternalTheme -> MH Bool)
-> MH Bool -> InternalTheme -> MH Bool
forall a b. (a -> b) -> a -> b
$ Bool -> MH Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
                       , _listWindowNewList :: Vector InternalTheme -> List Name InternalTheme
_listWindowNewList        = Vector InternalTheme -> List Name InternalTheme
forall (t :: * -> *) e. Foldable t => t e -> GenericList Name t e
newList
                       , _listWindowFetchResults :: () -> Session -> Text -> IO (Vector InternalTheme)
_listWindowFetchResults   = (Session -> Text -> IO (Vector InternalTheme))
-> () -> Session -> Text -> IO (Vector InternalTheme)
forall a b. a -> b -> a
const ((Session -> Text -> IO (Vector InternalTheme))
 -> () -> Session -> Text -> IO (Vector InternalTheme))
-> (Session -> Text -> IO (Vector InternalTheme))
-> ()
-> Session
-> Text
-> IO (Vector InternalTheme)
forall a b. (a -> b) -> a -> b
$ (Text -> IO (Vector InternalTheme))
-> Session -> Text -> IO (Vector InternalTheme)
forall a b. a -> b -> a
const ((Text -> IO (Vector InternalTheme))
 -> Session -> Text -> IO (Vector InternalTheme))
-> (Text -> IO (Vector InternalTheme))
-> Session
-> Text
-> IO (Vector InternalTheme)
forall a b. (a -> b) -> a -> b
$ IO (Vector InternalTheme) -> Text -> IO (Vector InternalTheme)
forall a b. a -> b -> a
const (IO (Vector InternalTheme) -> Text -> IO (Vector InternalTheme))
-> IO (Vector InternalTheme) -> Text -> IO (Vector InternalTheme)
forall a b. (a -> b) -> a -> b
$ Vector InternalTheme -> IO (Vector InternalTheme)
forall (m :: * -> *) a. Monad m => a -> m a
return Vector InternalTheme
forall a. Monoid a => a
mempty
                       , _listWindowRecordCount :: Maybe Int
_listWindowRecordCount    = Maybe Int
forall a. Maybe a
Nothing
                       }

nullUserListWindowState :: TeamId -> ListWindowState UserInfo UserSearchScope
nullUserListWindowState :: TeamId -> ListWindowState UserInfo UserSearchScope
nullUserListWindowState TeamId
tId =
    let newList :: t e -> GenericList Name t e
newList t e
rs = Name -> t e -> Int -> GenericList Name t e
forall (t :: * -> *) n e.
Foldable t =>
n -> t e -> Int -> GenericList n t e
list (TeamId -> Name
UserListSearchResults TeamId
tId) t e
rs Int
1
    in ListWindowState :: forall a b.
List Name a
-> Editor Text Name
-> b
-> Bool
-> (a -> MH Bool)
-> (Vector a -> List Name a)
-> (b -> Session -> Text -> IO (Vector a))
-> Maybe Int
-> ListWindowState a b
ListWindowState { _listWindowSearchResults :: List Name UserInfo
_listWindowSearchResults  = Vector UserInfo -> List Name UserInfo
forall (t :: * -> *) e. Foldable t => t e -> GenericList Name t e
newList Vector UserInfo
forall a. Monoid a => a
mempty
                       , _listWindowSearchInput :: Editor Text Name
_listWindowSearchInput    = Name -> Maybe Int -> Text -> Editor Text Name
forall a n.
GenericTextZipper a =>
n -> Maybe Int -> a -> Editor a n
editor (TeamId -> Name
UserListSearchInput TeamId
tId) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
1) Text
""
                       , _listWindowSearchScope :: UserSearchScope
_listWindowSearchScope    = Maybe TeamId -> UserSearchScope
AllUsers Maybe TeamId
forall a. Maybe a
Nothing
                       , _listWindowSearching :: Bool
_listWindowSearching      = Bool
False
                       , _listWindowEnterHandler :: UserInfo -> MH Bool
_listWindowEnterHandler   = MH Bool -> UserInfo -> MH Bool
forall a b. a -> b -> a
const (MH Bool -> UserInfo -> MH Bool) -> MH Bool -> UserInfo -> MH Bool
forall a b. (a -> b) -> a -> b
$ Bool -> MH Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
                       , _listWindowNewList :: Vector UserInfo -> List Name UserInfo
_listWindowNewList        = Vector UserInfo -> List Name UserInfo
forall (t :: * -> *) e. Foldable t => t e -> GenericList Name t e
newList
                       , _listWindowFetchResults :: UserSearchScope -> Session -> Text -> IO (Vector UserInfo)
_listWindowFetchResults   = (Session -> Text -> IO (Vector UserInfo))
-> UserSearchScope -> Session -> Text -> IO (Vector UserInfo)
forall a b. a -> b -> a
const ((Session -> Text -> IO (Vector UserInfo))
 -> UserSearchScope -> Session -> Text -> IO (Vector UserInfo))
-> (Session -> Text -> IO (Vector UserInfo))
-> UserSearchScope
-> Session
-> Text
-> IO (Vector UserInfo)
forall a b. (a -> b) -> a -> b
$ (Text -> IO (Vector UserInfo))
-> Session -> Text -> IO (Vector UserInfo)
forall a b. a -> b -> a
const ((Text -> IO (Vector UserInfo))
 -> Session -> Text -> IO (Vector UserInfo))
-> (Text -> IO (Vector UserInfo))
-> Session
-> Text
-> IO (Vector UserInfo)
forall a b. (a -> b) -> a -> b
$ IO (Vector UserInfo) -> Text -> IO (Vector UserInfo)
forall a b. a -> b -> a
const (IO (Vector UserInfo) -> Text -> IO (Vector UserInfo))
-> IO (Vector UserInfo) -> Text -> IO (Vector UserInfo)
forall a b. (a -> b) -> a -> b
$ Vector UserInfo -> IO (Vector UserInfo)
forall (m :: * -> *) a. Monad m => a -> m a
return Vector UserInfo
forall a. Monoid a => a
mempty
                       , _listWindowRecordCount :: Maybe Int
_listWindowRecordCount    = Maybe Int
forall a. Maybe a
Nothing
                       }

nullEmojiListWindowState :: TeamId -> ListWindowState (Bool, T.Text) ()
nullEmojiListWindowState :: TeamId -> ListWindowState (Bool, Text) ()
nullEmojiListWindowState TeamId
tId =
    let newList :: t e -> GenericList Name t e
newList t e
rs = Name -> t e -> Int -> GenericList Name t e
forall (t :: * -> *) n e.
Foldable t =>
n -> t e -> Int -> GenericList n t e
list (TeamId -> Name
ReactionEmojiList TeamId
tId) t e
rs Int
1
    in ListWindowState :: forall a b.
List Name a
-> Editor Text Name
-> b
-> Bool
-> (a -> MH Bool)
-> (Vector a -> List Name a)
-> (b -> Session -> Text -> IO (Vector a))
-> Maybe Int
-> ListWindowState a b
ListWindowState { _listWindowSearchResults :: List Name (Bool, Text)
_listWindowSearchResults  = Vector (Bool, Text) -> List Name (Bool, Text)
forall (t :: * -> *) e. Foldable t => t e -> GenericList Name t e
newList Vector (Bool, Text)
forall a. Monoid a => a
mempty
                       , _listWindowSearchInput :: Editor Text Name
_listWindowSearchInput    = Name -> Maybe Int -> Text -> Editor Text Name
forall a n.
GenericTextZipper a =>
n -> Maybe Int -> a -> Editor a n
editor (TeamId -> Name
ReactionEmojiListInput TeamId
tId) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
1) Text
""
                       , _listWindowSearchScope :: ()
_listWindowSearchScope    = ()
                       , _listWindowSearching :: Bool
_listWindowSearching      = Bool
False
                       , _listWindowEnterHandler :: (Bool, Text) -> MH Bool
_listWindowEnterHandler   = MH Bool -> (Bool, Text) -> MH Bool
forall a b. a -> b -> a
const (MH Bool -> (Bool, Text) -> MH Bool)
-> MH Bool -> (Bool, Text) -> MH Bool
forall a b. (a -> b) -> a -> b
$ Bool -> MH Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
                       , _listWindowNewList :: Vector (Bool, Text) -> List Name (Bool, Text)
_listWindowNewList        = Vector (Bool, Text) -> List Name (Bool, Text)
forall (t :: * -> *) e. Foldable t => t e -> GenericList Name t e
newList
                       , _listWindowFetchResults :: () -> Session -> Text -> IO (Vector (Bool, Text))
_listWindowFetchResults   = (Session -> Text -> IO (Vector (Bool, Text)))
-> () -> Session -> Text -> IO (Vector (Bool, Text))
forall a b. a -> b -> a
const ((Session -> Text -> IO (Vector (Bool, Text)))
 -> () -> Session -> Text -> IO (Vector (Bool, Text)))
-> (Session -> Text -> IO (Vector (Bool, Text)))
-> ()
-> Session
-> Text
-> IO (Vector (Bool, Text))
forall a b. (a -> b) -> a -> b
$ (Text -> IO (Vector (Bool, Text)))
-> Session -> Text -> IO (Vector (Bool, Text))
forall a b. a -> b -> a
const ((Text -> IO (Vector (Bool, Text)))
 -> Session -> Text -> IO (Vector (Bool, Text)))
-> (Text -> IO (Vector (Bool, Text)))
-> Session
-> Text
-> IO (Vector (Bool, Text))
forall a b. (a -> b) -> a -> b
$ IO (Vector (Bool, Text)) -> Text -> IO (Vector (Bool, Text))
forall a b. a -> b -> a
const (IO (Vector (Bool, Text)) -> Text -> IO (Vector (Bool, Text)))
-> IO (Vector (Bool, Text)) -> Text -> IO (Vector (Bool, Text))
forall a b. (a -> b) -> a -> b
$ Vector (Bool, Text) -> IO (Vector (Bool, Text))
forall (m :: * -> *) a. Monad m => a -> m a
return Vector (Bool, Text)
forall a. Monoid a => a
mempty
                       , _listWindowRecordCount :: Maybe Int
_listWindowRecordCount    = Maybe Int
forall a. Maybe a
Nothing
                       }

-- | Make a new channel topic editor window state.
newChannelTopicDialog :: TeamId -> T.Text -> ChannelTopicDialogState
newChannelTopicDialog :: TeamId -> Text -> ChannelTopicDialogState
newChannelTopicDialog TeamId
tId Text
t =
    ChannelTopicDialogState :: Editor Text Name -> FocusRing Name -> ChannelTopicDialogState
ChannelTopicDialogState { _channelTopicDialogEditor :: Editor Text Name
_channelTopicDialogEditor = Name -> Maybe Int -> Text -> Editor Text Name
forall a n.
GenericTextZipper a =>
n -> Maybe Int -> a -> Editor a n
editor (TeamId -> Name
ChannelTopicEditor TeamId
tId) Maybe Int
forall a. Maybe a
Nothing Text
t
                            , _channelTopicDialogFocus :: FocusRing Name
_channelTopicDialogFocus = [Name] -> FocusRing Name
forall n. [n] -> FocusRing n
focusRing [ TeamId -> Name
ChannelTopicEditor TeamId
tId
                                                                   , TeamId -> Name
ChannelTopicSaveButton TeamId
tId
                                                                   , TeamId -> Name
ChannelTopicCancelButton TeamId
tId
                                                                   ]
                            }

-- | Make a new attachment-saving editor window state.
newSaveAttachmentDialog :: Name -> T.Text -> SaveAttachmentDialogState Name
newSaveAttachmentDialog :: Name -> Text -> SaveAttachmentDialogState Name
newSaveAttachmentDialog Name
n Text
t =
    SaveAttachmentDialogState :: forall n.
Editor Text n -> FocusRing n -> SaveAttachmentDialogState n
SaveAttachmentDialogState { _attachmentPathEditor :: Editor Text Name
_attachmentPathEditor = (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z2.gotoEOL (Editor Text Name -> Editor Text Name)
-> Editor Text Name -> Editor Text Name
forall a b. (a -> b) -> a -> b
$
                                                        Name -> Maybe Int -> Text -> Editor Text Name
forall a n.
GenericTextZipper a =>
n -> Maybe Int -> a -> Editor a n
editor (Name -> Name
AttachmentPathEditor Name
n) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
1) Text
t
                              , _attachmentPathDialogFocus :: FocusRing Name
_attachmentPathDialogFocus = [Name] -> FocusRing Name
forall n. [n] -> FocusRing n
focusRing [ Name -> Name
AttachmentPathEditor Name
n
                                                                       , Name -> Name
AttachmentPathSaveButton Name
n
                                                                       , Name -> Name
AttachmentPathCancelButton Name
n
                                                                       ]
                              }

makeClientChannel :: (MonadIO m)
                  => BCH.BChan MHEvent
                  -> Maybe Aspell
                  -> UserId
                  -> Maybe TeamId
                  -> Channel
                  -> m ClientChannel
makeClientChannel :: BChan MHEvent
-> Maybe Aspell
-> UserId
-> Maybe TeamId
-> Channel
-> m ClientChannel
makeClientChannel BChan MHEvent
eventQueue Maybe Aspell
spellChecker UserId
myId Maybe TeamId
tId Channel
nc = do
    Messages
msgs <- m Messages
forall (m :: * -> *). MonadIO m => m Messages
emptyChannelMessages
    ChannelMessageInterface
mi <- IO ChannelMessageInterface -> m ChannelMessageInterface
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ChannelMessageInterface -> m ChannelMessageInterface)
-> IO ChannelMessageInterface -> m ChannelMessageInterface
forall a b. (a -> b) -> a -> b
$ Maybe Aspell
-> BChan MHEvent
-> Maybe TeamId
-> ChannelId
-> Messages
-> IO ChannelMessageInterface
newChannelMessageInterface Maybe Aspell
spellChecker BChan MHEvent
eventQueue Maybe TeamId
tId (Channel -> ChannelId
forall x y. HasId x y => x -> y
getId Channel
nc) Messages
msgs
    ClientChannel -> m ClientChannel
forall (m :: * -> *) a. Monad m => a -> m a
return ClientChannel :: ChannelInfo -> ChannelMessageInterface -> ClientChannel
ClientChannel { _ccInfo :: ChannelInfo
_ccInfo = UserId -> Channel -> ChannelInfo
initialChannelInfo UserId
myId Channel
nc
                         , _ccMessageInterface :: ChannelMessageInterface
_ccMessageInterface = ChannelMessageInterface
mi
                         }

initialChannelInfo :: UserId -> Channel -> ChannelInfo
initialChannelInfo :: UserId -> Channel -> ChannelInfo
initialChannelInfo UserId
myId Channel
chan =
    let updated :: ServerTime
updated  = Channel
chan Channel -> Getting ServerTime Channel ServerTime -> ServerTime
forall s a. s -> Getting a s a -> a
^. Getting ServerTime Channel ServerTime
Lens' Channel ServerTime
channelLastPostAtL
    in ChannelInfo :: ChannelId
-> Maybe TeamId
-> Maybe ServerTime
-> NewMessageIndicator
-> Maybe ServerTime
-> Int
-> ServerTime
-> Text
-> Text
-> Text
-> Text
-> Type
-> ChannelNotifyProps
-> Maybe UserId
-> Maybe UTCTime
-> Bool
-> ChannelInfo
ChannelInfo { _cdChannelId :: ChannelId
_cdChannelId              = Channel
chanChannel -> Getting ChannelId Channel ChannelId -> ChannelId
forall s a. s -> Getting a s a -> a
^.Getting ChannelId Channel ChannelId
Lens' Channel ChannelId
channelIdL
                   , _cdTeamId :: Maybe TeamId
_cdTeamId                 = Channel
chanChannel
-> Getting (Maybe TeamId) Channel (Maybe TeamId) -> Maybe TeamId
forall s a. s -> Getting a s a -> a
^.Getting (Maybe TeamId) Channel (Maybe TeamId)
Lens' Channel (Maybe TeamId)
channelTeamIdL
                   , _cdViewed :: Maybe ServerTime
_cdViewed                 = Maybe ServerTime
forall a. Maybe a
Nothing
                   , _cdNewMessageIndicator :: NewMessageIndicator
_cdNewMessageIndicator    = NewMessageIndicator
Hide
                   , _cdEditedMessageThreshold :: Maybe ServerTime
_cdEditedMessageThreshold = Maybe ServerTime
forall a. Maybe a
Nothing
                   , _cdMentionCount :: Int
_cdMentionCount           = Int
0
                   , _cdUpdated :: ServerTime
_cdUpdated                = ServerTime
updated
                   , _cdName :: Text
_cdName                   = Channel -> Text
preferredChannelName Channel
chan
                   , _cdDisplayName :: Text
_cdDisplayName            = UserText -> Text
sanitizeUserText (UserText -> Text) -> UserText -> Text
forall a b. (a -> b) -> a -> b
$ Channel -> UserText
channelDisplayName Channel
chan
                   , _cdHeader :: Text
_cdHeader                 = UserText -> Text
sanitizeUserText (UserText -> Text) -> UserText -> Text
forall a b. (a -> b) -> a -> b
$ Channel
chanChannel -> Getting UserText Channel UserText -> UserText
forall s a. s -> Getting a s a -> a
^.Getting UserText Channel UserText
Lens' Channel UserText
channelHeaderL
                   , _cdPurpose :: Text
_cdPurpose                = UserText -> Text
sanitizeUserText (UserText -> Text) -> UserText -> Text
forall a b. (a -> b) -> a -> b
$ Channel
chanChannel -> Getting UserText Channel UserText -> UserText
forall s a. s -> Getting a s a -> a
^.Getting UserText Channel UserText
Lens' Channel UserText
channelPurposeL
                   , _cdType :: Type
_cdType                   = Channel
chanChannel -> Getting Type Channel Type -> Type
forall s a. s -> Getting a s a -> a
^.Getting Type Channel Type
Lens' Channel Type
channelTypeL
                   , _cdNotifyProps :: ChannelNotifyProps
_cdNotifyProps            = ChannelNotifyProps
emptyChannelNotifyProps
                   , _cdDMUserId :: Maybe UserId
_cdDMUserId               = if Channel
chanChannel -> Getting Type Channel Type -> Type
forall s a. s -> Getting a s a -> a
^.Getting Type Channel Type
Lens' Channel Type
channelTypeL Type -> Type -> Bool
forall a. Eq a => a -> a -> Bool
== Type
Direct
                                                 then UserId -> Text -> Maybe UserId
userIdForDMChannel UserId
myId (Text -> Maybe UserId) -> Text -> Maybe UserId
forall a b. (a -> b) -> a -> b
$
                                                      UserText -> Text
sanitizeUserText (UserText -> Text) -> UserText -> Text
forall a b. (a -> b) -> a -> b
$ Channel -> UserText
channelName Channel
chan
                                                 else Maybe UserId
forall a. Maybe a
Nothing
                   , _cdSidebarShowOverride :: Maybe UTCTime
_cdSidebarShowOverride    = Maybe UTCTime
forall a. Maybe a
Nothing
                   , _cdFetchPending :: Bool
_cdFetchPending           = Bool
False
                   }