mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
core: move CLI notifications and active chat to view layer (for remote CLI) (#3196)
* core: move CLI notifications to view layer (to allow notifications in remote CLI) * remove unused * refactor activeTo * move activeTo to ChatTerminal * refactor * move back * remove extension
This commit is contained in:
committed by
GitHub
parent
a67b79952b
commit
4ecf94dfad
@@ -34,8 +34,7 @@ import Data.List.NonEmpty (NonEmpty)
|
||||
import Data.Map.Strict (Map)
|
||||
import Data.String
|
||||
import Data.Text (Text)
|
||||
import Data.Time (NominalDiffTime)
|
||||
import Data.Time.Clock (UTCTime)
|
||||
import Data.Time (NominalDiffTime, UTCTime)
|
||||
import Data.Version (showVersion)
|
||||
import GHC.Generics (Generic)
|
||||
import Language.Haskell.TH (Exp, Q, runIO)
|
||||
@@ -153,20 +152,10 @@ defaultInlineFilesConfig =
|
||||
receiveInstant = True -- allow receiving instant files, within receiveChunks limit
|
||||
}
|
||||
|
||||
data ActiveTo = ActiveNone | ActiveC ContactName | ActiveG GroupName
|
||||
deriving (Eq)
|
||||
|
||||
chatActiveTo :: ChatName -> ActiveTo
|
||||
chatActiveTo (ChatName cType name) = case cType of
|
||||
CTDirect -> ActiveC name
|
||||
CTGroup -> ActiveG name
|
||||
_ -> ActiveNone
|
||||
|
||||
data ChatDatabase = ChatDatabase {chatStore :: SQLiteStore, agentStore :: SQLiteStore}
|
||||
|
||||
data ChatController = ChatController
|
||||
{ currentUser :: TVar (Maybe User),
|
||||
activeTo :: TVar ActiveTo,
|
||||
firstTime :: Bool,
|
||||
smpAgent :: AgentClient,
|
||||
agentAsync :: TVar (Maybe (Async (), Maybe (Async ()))),
|
||||
@@ -175,8 +164,6 @@ data ChatController = ChatController
|
||||
idsDrg :: TVar ChaChaDRG,
|
||||
inputQ :: TBQueue String,
|
||||
outputQ :: TBQueue (Maybe CorrId, ChatResponse),
|
||||
notifyQ :: TBQueue Notification,
|
||||
sendNotification :: Notification -> IO (),
|
||||
subscriptionMode :: TVar SubscriptionMode,
|
||||
chatLock :: Lock,
|
||||
sndFiles :: TVar (Map Int64 Handle),
|
||||
@@ -433,7 +420,7 @@ data ChatResponse
|
||||
| CRApiChats {user :: User, chats :: [AChat]}
|
||||
| CRChats {chats :: [AChat]}
|
||||
| CRApiChat {user :: User, chat :: AChat}
|
||||
| CRChatItems {user :: User, chatItems :: [AChatItem]}
|
||||
| CRChatItems {user :: User, chatName_ :: Maybe ChatName, chatItems :: [AChatItem]}
|
||||
| CRChatItemInfo {user :: User, chatItem :: AChatItem, chatItemInfo :: ChatItemInfo}
|
||||
| CRChatItemId User (Maybe ChatItemId)
|
||||
| CRApiParsedMarkdown {formattedText :: Maybe MarkdownList}
|
||||
@@ -1074,14 +1061,6 @@ mkChatError = ChatError . CEException . show
|
||||
chatCmdError :: Maybe User -> String -> ChatResponse
|
||||
chatCmdError user = CRChatCmdError user . ChatError . CECommandError
|
||||
|
||||
setActive :: (MonadUnliftIO m, MonadReader ChatController m) => ActiveTo -> m ()
|
||||
setActive to = asks activeTo >>= atomically . (`writeTVar` to)
|
||||
|
||||
unsetActive :: (MonadUnliftIO m, MonadReader ChatController m) => ActiveTo -> m ()
|
||||
unsetActive a = asks activeTo >>= atomically . (`modifyTVar` unset)
|
||||
where
|
||||
unset a' = if a == a' then ActiveNone else a'
|
||||
|
||||
toView :: ChatMonad' m => ChatResponse -> m ()
|
||||
toView event = do
|
||||
q <- asks outputQ
|
||||
|
||||
@@ -14,8 +14,8 @@ import Simplex.Chat.Types
|
||||
import System.Exit (exitFailure)
|
||||
import UnliftIO.Async
|
||||
|
||||
simplexChatCore :: ChatConfig -> ChatOpts -> Maybe (Notification -> IO ()) -> (User -> ChatController -> IO ()) -> IO ()
|
||||
simplexChatCore cfg@ChatConfig {confirmMigrations, testView} opts@ChatOpts {coreOptions = CoreChatOpts {dbFilePrefix, dbKey, logAgent}} sendToast chat =
|
||||
simplexChatCore :: ChatConfig -> ChatOpts -> (User -> ChatController -> IO ()) -> IO ()
|
||||
simplexChatCore cfg@ChatConfig {confirmMigrations, testView} opts@ChatOpts {coreOptions = CoreChatOpts {dbFilePrefix, dbKey, logAgent}} chat =
|
||||
case logAgent of
|
||||
Just level -> do
|
||||
setLogLevel level
|
||||
@@ -28,7 +28,7 @@ simplexChatCore cfg@ChatConfig {confirmMigrations, testView} opts@ChatOpts {core
|
||||
exitFailure
|
||||
run db@ChatDatabase {chatStore} = do
|
||||
u <- getCreateActiveUser chatStore testView
|
||||
cc <- newChatController db (Just u) cfg opts sendToast
|
||||
cc <- newChatController db (Just u) cfg opts
|
||||
runSimplexChat opts u cc chat
|
||||
|
||||
runSimplexChat :: ChatOpts -> User -> ChatController -> (User -> ChatController -> IO ()) -> IO ()
|
||||
|
||||
@@ -50,8 +50,10 @@ import Simplex.Messaging.Util (eitherToMaybe, safeDecodeUtf8, (<$?>))
|
||||
data ChatType = CTDirect | CTGroup | CTContactRequest | CTContactConnection
|
||||
deriving (Eq, Show, Ord, Generic)
|
||||
|
||||
data ChatName = ChatName ChatType Text
|
||||
deriving (Show)
|
||||
data ChatName = ChatName {chatType :: ChatType, chatName :: Text}
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance ToJSON ChatName where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
chatTypeStr :: ChatType -> String
|
||||
chatTypeStr = \case
|
||||
|
||||
@@ -196,7 +196,7 @@ chatMigrateInit dbFilePrefix dbKey confirm = runExceptT $ do
|
||||
where
|
||||
initialize st db = do
|
||||
user_ <- getActiveUser_ st
|
||||
newChatController db user_ defaultMobileConfig (mobileChatOpts dbFilePrefix dbKey) Nothing
|
||||
newChatController db user_ defaultMobileConfig (mobileChatOpts dbFilePrefix dbKey)
|
||||
migrate createStore dbFile confirmMigrations =
|
||||
ExceptT $
|
||||
(first (DBMErrorMigration dbFile) <$> createStore dbFile dbKey confirmMigrations)
|
||||
|
||||
@@ -87,7 +87,7 @@ import qualified Simplex.Messaging.Crypto as C
|
||||
import Simplex.Messaging.Encoding.String
|
||||
import Simplex.Messaging.Protocol (BasicAuth (..), ProtoServerWithAuth (..), ProtocolServer (..), ProtocolTypeI (..), SubscriptionMode)
|
||||
import Simplex.Messaging.Transport.Client (TransportHost)
|
||||
import Simplex.Messaging.Util (eitherToMaybe, safeDecodeUtf8)
|
||||
import Simplex.Messaging.Util (safeDecodeUtf8)
|
||||
|
||||
createUserRecord :: DB.Connection -> AgentUserId -> Profile -> Bool -> ExceptT StoreError IO User
|
||||
createUserRecord db auId p activeUser = createUserRecordAt db auId p activeUser =<< liftIO getCurrentTime
|
||||
|
||||
@@ -15,7 +15,6 @@ import Simplex.Chat.Core
|
||||
import Simplex.Chat.Help (chatWelcome)
|
||||
import Simplex.Chat.Options
|
||||
import Simplex.Chat.Terminal.Input
|
||||
import Simplex.Chat.Terminal.Notification
|
||||
import Simplex.Chat.Terminal.Output
|
||||
import Simplex.FileTransfer.Client.Presets (defaultXFTPServers)
|
||||
import Simplex.Messaging.Client (defaultNetworkConfig)
|
||||
@@ -40,10 +39,9 @@ terminalChatConfig =
|
||||
}
|
||||
|
||||
simplexChatTerminal :: WithTerminal t => ChatConfig -> ChatOpts -> t -> IO ()
|
||||
simplexChatTerminal cfg opts t = do
|
||||
sendToast <- if muteNotifications opts then pure Nothing else Just <$> initializeNotifications
|
||||
handle checkDBKeyError . simplexChatCore cfg opts sendToast $ \u cc -> do
|
||||
ct <- newChatTerminal t
|
||||
simplexChatTerminal cfg opts t =
|
||||
handle checkDBKeyError . simplexChatCore cfg opts $ \u cc -> do
|
||||
ct <- newChatTerminal t opts
|
||||
when (firstTime cc) . printToTerminal ct $ chatWelcome u
|
||||
runChatTerminal ct cc
|
||||
|
||||
|
||||
@@ -57,14 +57,26 @@ runInputLoop ct@ChatTerminal {termState, liveMessageState} cc = forever $ do
|
||||
cmd = parseChatCommand bs
|
||||
unless (isMessage cmd) $ echo s
|
||||
r <- runReaderT (execChatCommand bs) cc
|
||||
case r of
|
||||
CRChatCmdError _ _ -> when (isMessage cmd) $ echo s
|
||||
CRChatError _ _ -> when (isMessage cmd) $ echo s
|
||||
_ -> pure ()
|
||||
processResp s cmd r
|
||||
printRespToTerminal ct cc False r
|
||||
startLiveMessage cmd r
|
||||
where
|
||||
echo s = printToTerminal ct [plain s]
|
||||
processResp s cmd = \case
|
||||
CRActiveUser _ -> setActive ct ""
|
||||
CRChatItems u chatName_ _ -> whenCurrUser cc u $ mapM_ (setActive ct . chatActiveTo) chatName_
|
||||
CRNewChatItem u (AChatItem _ SMDSnd cInfo _) -> whenCurrUser cc u $ setActiveChat ct cInfo
|
||||
CRChatItemUpdated u (AChatItem _ SMDSnd cInfo _) -> whenCurrUser cc u $ setActiveChat ct cInfo
|
||||
CRChatItemDeleted u (AChatItem _ _ cInfo _) _ _ _ -> whenCurrUser cc u $ setActiveChat ct cInfo
|
||||
CRContactDeleted u c -> whenCurrUser cc u $ unsetActiveContact ct c
|
||||
CRGroupDeletedUser u g -> whenCurrUser cc u $ unsetActiveGroup ct g
|
||||
CRSentGroupInvitation u g _ _ -> whenCurrUser cc u $ setActiveGroup ct g
|
||||
CRChatCmdError _ _ -> when (isMessage cmd) $ echo s
|
||||
CRChatError _ _ -> when (isMessage cmd) $ echo s
|
||||
CRCmdOk _ -> case cmd of
|
||||
Right APIDeleteUser {} -> setActive ct ""
|
||||
_ -> pure ()
|
||||
_ -> pure ()
|
||||
isMessage = \case
|
||||
Right SendMessage {} -> True
|
||||
Right SendLiveMessage {} -> True
|
||||
@@ -134,7 +146,7 @@ runTerminalInput ct cc = withChatTerm ct $ do
|
||||
receiveFromTTY cc ct
|
||||
|
||||
receiveFromTTY :: forall m. MonadTerminal m => ChatController -> ChatTerminal -> m ()
|
||||
receiveFromTTY cc@ChatController {inputQ, activeTo, currentUser, chatStore} ct@ChatTerminal {termSize, termState, liveMessageState} =
|
||||
receiveFromTTY cc@ChatController {inputQ, currentUser, chatStore} ct@ChatTerminal {termSize, termState, liveMessageState, activeTo} =
|
||||
forever $ getKey >>= liftIO . processKey >> withTermLock ct (updateInput ct)
|
||||
where
|
||||
processKey :: (Key, Modifiers) -> IO ()
|
||||
@@ -153,11 +165,11 @@ receiveFromTTY cc@ChatController {inputQ, activeTo, currentUser, chatStore} ct@C
|
||||
when (inputString ts /= "" || isLive) $
|
||||
atomically (submitInput live ts) >>= mapM_ (uncurry endLiveMessage)
|
||||
update key = do
|
||||
ac <- readTVarIO activeTo
|
||||
chatPrefix <- readTVarIO activeTo
|
||||
live <- isJust <$> readTVarIO liveMessageState
|
||||
ts <- readTVarIO termState
|
||||
user_ <- readTVarIO currentUser
|
||||
ts' <- updateTermState user_ chatStore ac live (width termSize) key ts
|
||||
ts' <- updateTermState user_ chatStore chatPrefix live (width termSize) key ts
|
||||
atomically $ writeTVar termState $! ts'
|
||||
|
||||
endLiveMessage :: String -> LiveMessage -> IO ()
|
||||
@@ -203,8 +215,8 @@ data AutoComplete
|
||||
| ACCommand Text
|
||||
| ACNone
|
||||
|
||||
updateTermState :: Maybe User -> SQLiteStore -> ActiveTo -> Bool -> Int -> (Key, Modifiers) -> TerminalState -> IO TerminalState
|
||||
updateTermState user_ st ac live tw (key, ms) ts@TerminalState {inputString = s, inputPosition = p, autoComplete = acp} = case key of
|
||||
updateTermState :: Maybe User -> SQLiteStore -> String -> Bool -> Int -> (Key, Modifiers) -> TerminalState -> IO TerminalState
|
||||
updateTermState user_ st chatPrefix live tw (key, ms) ts@TerminalState {inputString = s, inputPosition = p, autoComplete = acp} = case key of
|
||||
CharKey c
|
||||
| ms == mempty || ms == shiftKey -> pure $ insertChars $ charsWithContact [c]
|
||||
| ms == altKey && c == 'b' -> pure $ setPosition prevWordPos
|
||||
@@ -326,17 +338,13 @@ updateTermState user_ st ac live tw (key, ms) ts@TerminalState {inputString = s,
|
||||
charsWithContact cs
|
||||
| live = cs
|
||||
| null s && cs /= "@" && cs /= "#" && cs /= "/" && cs /= ">" && cs /= "\\" && cs /= "!" && cs /= "+" && cs /= "-" =
|
||||
contactPrefix <> cs
|
||||
chatPrefix <> cs
|
||||
| (s == ">" || s == "\\" || s == "!") && cs == " " =
|
||||
cs <> contactPrefix
|
||||
cs <> chatPrefix
|
||||
| otherwise = cs
|
||||
insertChars = ts' . if p >= length s then append else insert
|
||||
append cs = let s' = s <> cs in (s', length s')
|
||||
insert cs = let (b, a) = splitAt p s in (b <> cs <> a, p + length cs)
|
||||
contactPrefix = case ac of
|
||||
ActiveNone -> ""
|
||||
ActiveC c -> "@" <> T.unpack c <> " "
|
||||
ActiveG g -> "#" <> T.unpack g <> " "
|
||||
backDeleteChar
|
||||
| p == 0 || null s = ts
|
||||
| p >= length s = ts' (init s, length s - 1)
|
||||
|
||||
@@ -13,13 +13,14 @@ import qualified Data.Map as M
|
||||
import Data.Maybe (fromMaybe, isJust)
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Simplex.Chat.Types
|
||||
import Simplex.Messaging.Util (catchAll_)
|
||||
import System.Directory (createDirectoryIfMissing, doesFileExist, findExecutable, getAppUserDataDirectory)
|
||||
import System.FilePath (combine)
|
||||
import System.Info (os)
|
||||
import System.Process (readCreateProcess, shell)
|
||||
|
||||
data Notification = Notification {title :: Text, text :: Text}
|
||||
|
||||
initializeNotifications :: IO (Notification -> IO ())
|
||||
initializeNotifications =
|
||||
hideException <$> case os of
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
{-# LANGUAGE GADTs #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
|
||||
@@ -14,13 +15,24 @@ import Control.Monad.Catch (MonadMask)
|
||||
import Control.Monad.Except
|
||||
import Control.Monad.Reader
|
||||
import Data.List (intercalate)
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Data.Time.Clock (getCurrentTime)
|
||||
import Data.Time.LocalTime (getCurrentTimeZone)
|
||||
import Simplex.Chat (processChatCommand)
|
||||
import Simplex.Chat (processChatCommand, chatNtf, contactNtf, groupNtf, userNtf)
|
||||
import Simplex.Chat.Controller
|
||||
import Simplex.Chat.Messages hiding (NewChatItem (..))
|
||||
import Simplex.Chat.Markdown
|
||||
import Simplex.Chat.Messages
|
||||
import Simplex.Chat.Messages.CIContent (CIContent(..), SMsgDirection (..))
|
||||
import Simplex.Chat.Options
|
||||
import Simplex.Chat.Protocol (MsgContent (..), msgContentText)
|
||||
import Simplex.Chat.Styled
|
||||
import Simplex.Chat.Terminal.Notification (Notification (..), initializeNotifications)
|
||||
import Simplex.Chat.Types (Contact, GroupInfo (..), User (..), UserContactRequest (..))
|
||||
import Simplex.Chat.View
|
||||
import Simplex.Messaging.Agent.Protocol
|
||||
import Simplex.Messaging.Encoding.String
|
||||
import Simplex.Messaging.Util (safeDecodeUtf8)
|
||||
import System.Console.ANSI.Types
|
||||
import System.IO (IOMode (..), hPutStrLn, withFile)
|
||||
import System.Mem.Weak (Weak)
|
||||
@@ -34,7 +46,9 @@ data ChatTerminal = ChatTerminal
|
||||
termSize :: Size,
|
||||
liveMessageState :: TVar (Maybe LiveMessage),
|
||||
nextMessageRow :: TVar Int,
|
||||
termLock :: TMVar ()
|
||||
termLock :: TMVar (),
|
||||
sendNotification :: Maybe (Notification -> IO ()),
|
||||
activeTo :: TVar String
|
||||
}
|
||||
|
||||
data TerminalState = TerminalState
|
||||
@@ -79,16 +93,28 @@ instance WithTerminal VirtualTerminal where
|
||||
withChatTerm :: (MonadIO m, MonadMask m) => ChatTerminal -> (forall t. WithTerminal t => TerminalT t m a) -> m a
|
||||
withChatTerm ChatTerminal {termDevice = TerminalDevice t} action = withTerm t $ runTerminalT action
|
||||
|
||||
newChatTerminal :: WithTerminal t => t -> IO ChatTerminal
|
||||
newChatTerminal t = do
|
||||
newChatTerminal :: WithTerminal t => t -> ChatOpts -> IO ChatTerminal
|
||||
newChatTerminal t opts = do
|
||||
termSize <- withTerm t . runTerminalT $ getWindowSize
|
||||
let lastRow = height termSize - 1
|
||||
termState <- newTVarIO mkTermState
|
||||
liveMessageState <- newTVarIO Nothing
|
||||
termLock <- newTMVarIO ()
|
||||
nextMessageRow <- newTVarIO lastRow
|
||||
sendNotification <- if muteNotifications opts then pure Nothing else Just <$> initializeNotifications
|
||||
activeTo <- newTVarIO ""
|
||||
-- threadDelay 500000 -- this delay is the same as timeout in getTerminalSize
|
||||
return ChatTerminal {termDevice = TerminalDevice t, termState, termSize, liveMessageState, nextMessageRow, termLock}
|
||||
pure
|
||||
ChatTerminal
|
||||
{ termDevice = TerminalDevice t,
|
||||
termState,
|
||||
termSize,
|
||||
liveMessageState,
|
||||
nextMessageRow,
|
||||
termLock,
|
||||
sendNotification,
|
||||
activeTo
|
||||
}
|
||||
|
||||
mkTermState :: TerminalState
|
||||
mkTermState =
|
||||
@@ -122,6 +148,7 @@ runTerminalOutput ct cc@ChatController {outputQ, showLiveItems, logFilePath} = d
|
||||
_ -> printToTerminal ct
|
||||
liveItems <- readTVarIO showLiveItems
|
||||
responseString cc liveItems r >>= printResp
|
||||
responseNotification ct cc r
|
||||
where
|
||||
markChatItemRead (AChatItem _ _ chat item@ChatItem {chatDir, meta = CIMeta {itemStatus}}) =
|
||||
case (muted chat chatDir, itemStatus) of
|
||||
@@ -132,6 +159,100 @@ runTerminalOutput ct cc@ChatController {outputQ, showLiveItems, logFilePath} = d
|
||||
_ -> pure ()
|
||||
logResponse path s = withFile path AppendMode $ \h -> mapM_ (hPutStrLn h . unStyle) s
|
||||
|
||||
responseNotification :: ChatTerminal -> ChatController -> ChatResponse -> IO ()
|
||||
responseNotification t@ChatTerminal {sendNotification} cc = \case
|
||||
CRNewChatItem u (AChatItem _ SMDRcv cInfo ChatItem {chatDir, content = CIRcvMsgContent mc, formattedText}) ->
|
||||
when (chatNtf u cInfo) $ do
|
||||
whenCurrUser cc u $ setActiveChat t cInfo
|
||||
case (cInfo, chatDir) of
|
||||
(DirectChat ct, _) -> sendNtf (viewContactName ct <> "> ", text)
|
||||
(GroupChat g, CIGroupRcv m) -> sendNtf (fromGroup_ g m, text)
|
||||
_ -> pure ()
|
||||
where
|
||||
text = msgText mc formattedText
|
||||
CRChatItemUpdated u (AChatItem _ SMDRcv cInfo ChatItem {content = CIRcvMsgContent _}) ->
|
||||
whenCurrUser cc u $ when (chatNtf u cInfo) $ setActiveChat t cInfo
|
||||
CRContactConnected u ct _ -> when (contactNtf u ct) $ do
|
||||
whenCurrUser cc u $ setActiveContact t ct
|
||||
sendNtf (viewContactName ct <> "> ", "connected")
|
||||
CRContactAnotherClient u ct -> do
|
||||
whenCurrUser cc u $ unsetActiveContact t ct
|
||||
when (contactNtf u ct) $ sendNtf (viewContactName ct <> "> ", "connected to another client")
|
||||
CRContactsDisconnected srv _ -> serverNtf srv "disconnected"
|
||||
CRContactsSubscribed srv _ -> serverNtf srv "connected"
|
||||
CRReceivedGroupInvitation u g ct _ _ ->
|
||||
when (contactNtf u ct) $
|
||||
sendNtf ("#" <> viewGroupName g <> " " <> viewContactName ct <> "> ", "invited you to join the group")
|
||||
CRUserJoinedGroup u g _ -> when (groupNtf u g) $ do
|
||||
whenCurrUser cc u $ setActiveGroup t g
|
||||
sendNtf ("#" <> viewGroupName g, "you are connected to group")
|
||||
CRJoinedGroupMember u g m ->
|
||||
when (groupNtf u g) $ sendNtf ("#" <> viewGroupName g, "member " <> viewMemberName m <> " is connected")
|
||||
CRConnectedToGroupMember u g m _ ->
|
||||
when (groupNtf u g) $ sendNtf ("#" <> viewGroupName g, "member " <> viewMemberName m <> " is connected")
|
||||
CRReceivedContactRequest u UserContactRequest {localDisplayName = n} ->
|
||||
when (userNtf u) $ sendNtf (viewName n <> ">", "wants to connect to you")
|
||||
_ -> pure ()
|
||||
where
|
||||
sendNtf = maybe (\_ -> pure ()) (. uncurry Notification) sendNotification
|
||||
serverNtf (SMPServer host _ _) str = sendNtf ("server " <> str, safeDecodeUtf8 $ strEncode host)
|
||||
|
||||
msgText :: MsgContent -> Maybe MarkdownList -> Text
|
||||
msgText (MCFile _) _ = "wants to send a file"
|
||||
msgText mc md_ = maybe (msgContentText mc) (mconcat . map hideSecret) md_
|
||||
where
|
||||
hideSecret :: FormattedText -> Text
|
||||
hideSecret FormattedText {format = Just Secret} = "..."
|
||||
hideSecret FormattedText {text} = text
|
||||
|
||||
chatActiveTo :: ChatName -> String
|
||||
chatActiveTo (ChatName cType name) = case cType of
|
||||
CTDirect -> T.unpack $ "@" <> viewName name <> " "
|
||||
CTGroup -> T.unpack $ "#" <> viewName name <> " "
|
||||
_ -> ""
|
||||
|
||||
chatInfoActiveTo :: ChatInfo c -> String
|
||||
chatInfoActiveTo = \case
|
||||
DirectChat c -> contactActiveTo c
|
||||
GroupChat g -> groupActiveTo g
|
||||
_ -> ""
|
||||
|
||||
contactActiveTo :: Contact -> String
|
||||
contactActiveTo c = T.unpack $ "@" <> viewContactName c <> " "
|
||||
|
||||
groupActiveTo :: GroupInfo -> String
|
||||
groupActiveTo g = T.unpack $ "#" <> viewGroupName g <> " "
|
||||
|
||||
setActiveChat :: ChatTerminal -> ChatInfo c -> IO ()
|
||||
setActiveChat t = setActive t . chatInfoActiveTo
|
||||
|
||||
setActiveContact :: ChatTerminal -> Contact -> IO ()
|
||||
setActiveContact t = setActive t . contactActiveTo
|
||||
|
||||
setActiveGroup :: ChatTerminal -> GroupInfo -> IO ()
|
||||
setActiveGroup t = setActive t . groupActiveTo
|
||||
|
||||
setActive :: ChatTerminal -> String -> IO ()
|
||||
setActive ChatTerminal {activeTo} to = atomically $ writeTVar activeTo to
|
||||
|
||||
unsetActiveContact :: ChatTerminal -> Contact -> IO ()
|
||||
unsetActiveContact t = unsetActive t . contactActiveTo
|
||||
|
||||
unsetActiveGroup :: ChatTerminal -> GroupInfo -> IO ()
|
||||
unsetActiveGroup t = unsetActive t . groupActiveTo
|
||||
|
||||
unsetActive :: ChatTerminal -> String -> IO ()
|
||||
unsetActive ChatTerminal {activeTo} to' = atomically $ modifyTVar activeTo unset
|
||||
where
|
||||
unset to = if to == to' then "" else to
|
||||
|
||||
whenCurrUser :: ChatController -> User -> IO () -> IO ()
|
||||
whenCurrUser cc u a = do
|
||||
u_ <- readTVarIO $ currentUser cc
|
||||
when (sameUser u u_) a
|
||||
where
|
||||
sameUser User {userId = uId} = maybe False $ \User {userId} -> userId == uId
|
||||
|
||||
printRespToTerminal :: ChatTerminal -> ChatController -> Bool -> ChatResponse -> IO ()
|
||||
printRespToTerminal ct cc liveItems r = responseString cc liveItems r >>= printToTerminal ct
|
||||
|
||||
|
||||
@@ -1424,8 +1424,6 @@ serializeIntroStatus = \case
|
||||
GMIntroToConnected -> "to-con"
|
||||
GMIntroConnected -> "con"
|
||||
|
||||
data Notification = Notification {title :: Text, text :: Text}
|
||||
|
||||
textParseJSON :: TextEncoding a => String -> J.Value -> JT.Parser a
|
||||
textParseJSON name = J.withText name $ maybe (fail $ "bad " <> name) pure . textDecode
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ responseToView user_ ChatConfig {logLevel, showReactions, showReceipts, testView
|
||||
CRContactCode u ct code -> ttyUser u $ viewContactCode ct code testView
|
||||
CRGroupMemberCode u g m code -> ttyUser u $ viewGroupMemberCode g m code testView
|
||||
CRNewChatItem u (AChatItem _ _ chat item) -> ttyUser u $ unmuted chat item $ viewChatItem chat item False ts tz <> viewItemReactions item
|
||||
CRChatItems u chatItems -> ttyUser u $ concatMap (\(AChatItem _ _ chat item) -> viewChatItem chat item True ts tz <> viewItemReactions item) chatItems
|
||||
CRChatItems u _ chatItems -> ttyUser u $ concatMap (\(AChatItem _ _ chat item) -> viewChatItem chat item True ts tz <> viewItemReactions item) chatItems
|
||||
CRChatItemInfo u ci ciInfo -> ttyUser u $ viewChatItemInfo ci ciInfo tz
|
||||
CRChatItemId u itemId -> ttyUser u [plain $ maybe "no item" show itemId]
|
||||
CRChatItemStatusUpdated u ci -> ttyUser u $ viewChatItemStatusUpdated ci ts tz testView showReceipts
|
||||
|
||||
Reference in New Issue
Block a user