2021-06-25 18:18:24 +01:00
|
|
|
{-# LANGUAGE ConstraintKinds #-}
|
2021-07-12 19:00:03 +01:00
|
|
|
{-# LANGUAGE DuplicateRecordFields #-}
|
2021-06-25 18:18:24 +01:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
|
|
|
{-# LANGUAGE LambdaCase #-}
|
2021-07-12 19:00:03 +01:00
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
2021-06-25 18:18:24 +01:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
|
|
2021-07-05 20:05:07 +01:00
|
|
|
module Simplex.Chat.View
|
2021-06-25 18:18:24 +01:00
|
|
|
( printToView,
|
|
|
|
|
showInvitation,
|
2021-07-04 18:42:24 +01:00
|
|
|
showChatError,
|
2021-06-25 18:18:24 +01:00
|
|
|
showContactDeleted,
|
2021-08-02 20:10:24 +01:00
|
|
|
showContactGroups,
|
2021-06-25 18:18:24 +01:00
|
|
|
showContactConnected,
|
|
|
|
|
showContactDisconnected,
|
2021-07-25 20:23:52 +01:00
|
|
|
showContactSubscribed,
|
|
|
|
|
showContactSubError,
|
|
|
|
|
showGroupSubscribed,
|
2021-08-02 20:10:24 +01:00
|
|
|
showGroupEmpty,
|
|
|
|
|
showGroupRemoved,
|
2021-07-25 20:23:52 +01:00
|
|
|
showMemberSubError,
|
2021-06-25 18:18:24 +01:00
|
|
|
showReceivedMessage,
|
2021-07-24 10:26:28 +01:00
|
|
|
showReceivedGroupMessage,
|
2021-06-25 18:18:24 +01:00
|
|
|
showSentMessage,
|
2021-07-24 10:26:28 +01:00
|
|
|
showSentGroupMessage,
|
2021-07-12 19:00:03 +01:00
|
|
|
showGroupCreated,
|
2021-08-02 20:10:24 +01:00
|
|
|
showGroupDeletedUser,
|
|
|
|
|
showGroupDeleted,
|
2021-07-16 07:40:55 +01:00
|
|
|
showSentGroupInvitation,
|
|
|
|
|
showReceivedGroupInvitation,
|
2021-07-24 10:26:28 +01:00
|
|
|
showJoinedGroupMember,
|
|
|
|
|
showUserJoinedGroup,
|
|
|
|
|
showJoinedGroupMemberConnecting,
|
|
|
|
|
showConnectedToGroupMember,
|
2021-08-02 20:10:24 +01:00
|
|
|
showDeletedMember,
|
|
|
|
|
showDeletedMemberUser,
|
|
|
|
|
showLeftMemberUser,
|
|
|
|
|
showLeftMember,
|
2021-07-27 08:08:05 +01:00
|
|
|
showGroupMembers,
|
|
|
|
|
showContactsMerged,
|
2021-06-26 20:20:33 +01:00
|
|
|
safeDecodeUtf8,
|
2021-06-25 18:18:24 +01:00
|
|
|
)
|
|
|
|
|
where
|
|
|
|
|
|
|
|
|
|
import Control.Monad.IO.Unlift
|
|
|
|
|
import Control.Monad.Reader
|
|
|
|
|
import Data.ByteString.Char8 (ByteString)
|
2021-07-24 10:26:28 +01:00
|
|
|
import Data.Composition ((.:), (.:.))
|
2021-07-04 18:42:24 +01:00
|
|
|
import Data.Text (Text)
|
2021-06-25 18:18:24 +01:00
|
|
|
import qualified Data.Text as T
|
|
|
|
|
import Data.Time.Clock (DiffTime, UTCTime)
|
|
|
|
|
import Data.Time.Format (defaultTimeLocale, formatTime)
|
|
|
|
|
import Data.Time.LocalTime (TimeZone, ZonedTime, getCurrentTimeZone, getZonedTime, localDay, localTimeOfDay, timeOfDayToTime, utcToLocalTime, zonedTimeToLocalTime)
|
|
|
|
|
import Simplex.Chat.Controller
|
|
|
|
|
import Simplex.Chat.Markdown
|
2021-07-12 19:00:03 +01:00
|
|
|
import Simplex.Chat.Store (StoreError (..))
|
2021-06-25 18:18:24 +01:00
|
|
|
import Simplex.Chat.Styled
|
2021-07-05 20:05:07 +01:00
|
|
|
import Simplex.Chat.Terminal (printToTerminal)
|
2021-07-04 18:42:24 +01:00
|
|
|
import Simplex.Chat.Types
|
2021-07-05 20:05:07 +01:00
|
|
|
import Simplex.Chat.Util (safeDecodeUtf8)
|
2021-06-25 18:18:24 +01:00
|
|
|
import Simplex.Messaging.Agent.Protocol
|
|
|
|
|
import System.Console.ANSI.Types
|
|
|
|
|
|
|
|
|
|
type ChatReader m = (MonadUnliftIO m, MonadReader ChatController m)
|
|
|
|
|
|
2021-07-05 19:54:44 +01:00
|
|
|
showInvitation :: ChatReader m => SMPQueueInfo -> m ()
|
|
|
|
|
showInvitation = printToView . invitation
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2021-07-04 18:42:24 +01:00
|
|
|
showChatError :: ChatReader m => ChatError -> m ()
|
|
|
|
|
showChatError = printToView . chatError
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2021-07-14 20:11:41 +01:00
|
|
|
showContactDeleted :: ChatReader m => ContactName -> m ()
|
2021-06-25 18:18:24 +01:00
|
|
|
showContactDeleted = printToView . contactDeleted
|
|
|
|
|
|
2021-08-02 20:10:24 +01:00
|
|
|
showContactGroups :: ChatReader m => ContactName -> [GroupName] -> m ()
|
|
|
|
|
showContactGroups = printToView .: contactGroups
|
|
|
|
|
|
2021-07-16 07:40:55 +01:00
|
|
|
showContactConnected :: ChatReader m => Contact -> m ()
|
2021-06-25 18:18:24 +01:00
|
|
|
showContactConnected = printToView . contactConnected
|
|
|
|
|
|
2021-07-14 20:11:41 +01:00
|
|
|
showContactDisconnected :: ChatReader m => ContactName -> m ()
|
2021-06-25 18:18:24 +01:00
|
|
|
showContactDisconnected = printToView . contactDisconnected
|
|
|
|
|
|
2021-07-25 20:23:52 +01:00
|
|
|
showContactSubscribed :: ChatReader m => ContactName -> m ()
|
|
|
|
|
showContactSubscribed = printToView . contactSubscribed
|
|
|
|
|
|
|
|
|
|
showContactSubError :: ChatReader m => ContactName -> ChatError -> m ()
|
|
|
|
|
showContactSubError = printToView .: contactSubError
|
|
|
|
|
|
|
|
|
|
showGroupSubscribed :: ChatReader m => GroupName -> m ()
|
|
|
|
|
showGroupSubscribed = printToView . groupSubscribed
|
|
|
|
|
|
2021-08-02 20:10:24 +01:00
|
|
|
showGroupEmpty :: ChatReader m => GroupName -> m ()
|
|
|
|
|
showGroupEmpty = printToView . groupEmpty
|
|
|
|
|
|
|
|
|
|
showGroupRemoved :: ChatReader m => GroupName -> m ()
|
|
|
|
|
showGroupRemoved = printToView . groupRemoved
|
|
|
|
|
|
2021-07-25 20:23:52 +01:00
|
|
|
showMemberSubError :: ChatReader m => GroupName -> ContactName -> ChatError -> m ()
|
|
|
|
|
showMemberSubError = printToView .:. memberSubError
|
|
|
|
|
|
2021-07-14 20:11:41 +01:00
|
|
|
showReceivedMessage :: ChatReader m => ContactName -> UTCTime -> Text -> MsgIntegrity -> m ()
|
2021-07-24 10:26:28 +01:00
|
|
|
showReceivedMessage = showReceivedMessage_ . ttyFromContact
|
|
|
|
|
|
|
|
|
|
showReceivedGroupMessage :: ChatReader m => GroupName -> ContactName -> UTCTime -> Text -> MsgIntegrity -> m ()
|
|
|
|
|
showReceivedGroupMessage = showReceivedMessage_ .: ttyFromGroup
|
|
|
|
|
|
|
|
|
|
showReceivedMessage_ :: ChatReader m => StyledString -> UTCTime -> Text -> MsgIntegrity -> m ()
|
|
|
|
|
showReceivedMessage_ from utcTime msg mOk = printToView =<< liftIO (receivedMessage from utcTime msg mOk)
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2021-07-14 20:11:41 +01:00
|
|
|
showSentMessage :: ChatReader m => ContactName -> ByteString -> m ()
|
2021-07-24 10:26:28 +01:00
|
|
|
showSentMessage = showSentMessage_ . ttyToContact
|
|
|
|
|
|
|
|
|
|
showSentGroupMessage :: ChatReader m => GroupName -> ByteString -> m ()
|
|
|
|
|
showSentGroupMessage = showSentMessage_ . ttyToGroup
|
|
|
|
|
|
|
|
|
|
showSentMessage_ :: ChatReader m => StyledString -> ByteString -> m ()
|
|
|
|
|
showSentMessage_ to msg = printToView =<< liftIO (sentMessage to msg)
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2021-07-16 07:40:55 +01:00
|
|
|
showGroupCreated :: ChatReader m => Group -> m ()
|
2021-07-12 19:00:03 +01:00
|
|
|
showGroupCreated = printToView . groupCreated
|
|
|
|
|
|
2021-08-02 20:10:24 +01:00
|
|
|
showGroupDeletedUser :: ChatReader m => GroupName -> m ()
|
|
|
|
|
showGroupDeletedUser = printToView . groupDeletedUser
|
|
|
|
|
|
|
|
|
|
showGroupDeleted :: ChatReader m => GroupName -> GroupMember -> m ()
|
|
|
|
|
showGroupDeleted = printToView .: groupDeleted
|
|
|
|
|
|
|
|
|
|
showSentGroupInvitation :: ChatReader m => GroupName -> ContactName -> m ()
|
2021-07-16 07:40:55 +01:00
|
|
|
showSentGroupInvitation = printToView .: sentGroupInvitation
|
|
|
|
|
|
2021-07-24 10:26:28 +01:00
|
|
|
showReceivedGroupInvitation :: ChatReader m => Group -> ContactName -> GroupMemberRole -> m ()
|
|
|
|
|
showReceivedGroupInvitation = printToView .:. receivedGroupInvitation
|
2021-07-16 07:40:55 +01:00
|
|
|
|
2021-07-24 10:26:28 +01:00
|
|
|
showJoinedGroupMember :: ChatReader m => GroupName -> GroupMember -> m ()
|
|
|
|
|
showJoinedGroupMember = printToView .: joinedGroupMember
|
2021-07-16 07:40:55 +01:00
|
|
|
|
2021-07-24 10:26:28 +01:00
|
|
|
showUserJoinedGroup :: ChatReader m => GroupName -> m ()
|
|
|
|
|
showUserJoinedGroup = printToView . userJoinedGroup
|
|
|
|
|
|
|
|
|
|
showJoinedGroupMemberConnecting :: ChatReader m => GroupName -> GroupMember -> GroupMember -> m ()
|
|
|
|
|
showJoinedGroupMemberConnecting = printToView .:. joinedGroupMemberConnecting
|
|
|
|
|
|
|
|
|
|
showConnectedToGroupMember :: ChatReader m => GroupName -> GroupMember -> m ()
|
|
|
|
|
showConnectedToGroupMember = printToView .: connectedToGroupMember
|
2021-07-16 07:40:55 +01:00
|
|
|
|
2021-08-02 20:10:24 +01:00
|
|
|
showDeletedMember :: ChatReader m => GroupName -> Maybe GroupMember -> Maybe GroupMember -> m ()
|
|
|
|
|
showDeletedMember = printToView .:. deletedMember
|
|
|
|
|
|
|
|
|
|
showDeletedMemberUser :: ChatReader m => GroupName -> GroupMember -> m ()
|
|
|
|
|
showDeletedMemberUser = printToView .: deletedMemberUser
|
|
|
|
|
|
|
|
|
|
showLeftMemberUser :: ChatReader m => GroupName -> m ()
|
|
|
|
|
showLeftMemberUser = printToView . leftMemberUser
|
|
|
|
|
|
|
|
|
|
showLeftMember :: ChatReader m => GroupName -> GroupMember -> m ()
|
|
|
|
|
showLeftMember = printToView .: leftMember
|
|
|
|
|
|
2021-07-27 08:08:05 +01:00
|
|
|
showGroupMembers :: ChatReader m => Group -> m ()
|
|
|
|
|
showGroupMembers = printToView . groupMembers
|
|
|
|
|
|
|
|
|
|
showContactsMerged :: ChatReader m => Contact -> Contact -> m ()
|
|
|
|
|
showContactsMerged = printToView .: contactsMerged
|
|
|
|
|
|
2021-07-05 19:54:44 +01:00
|
|
|
invitation :: SMPQueueInfo -> [StyledString]
|
|
|
|
|
invitation qInfo =
|
|
|
|
|
[ "pass this invitation to your contact (via another channel): ",
|
2021-06-25 18:18:24 +01:00
|
|
|
"",
|
2021-07-12 19:00:03 +01:00
|
|
|
(plain . serializeSmpQueueInfo) qInfo,
|
2021-06-25 18:18:24 +01:00
|
|
|
"",
|
2021-07-16 07:40:55 +01:00
|
|
|
"and ask them to connect: " <> highlight' "/c <invitation_above>"
|
2021-06-25 18:18:24 +01:00
|
|
|
]
|
|
|
|
|
|
2021-07-14 20:11:41 +01:00
|
|
|
contactDeleted :: ContactName -> [StyledString]
|
2021-08-02 20:10:24 +01:00
|
|
|
contactDeleted c = [ttyContact c <> ": contact is deleted"]
|
|
|
|
|
|
|
|
|
|
contactGroups :: ContactName -> [GroupName] -> [StyledString]
|
|
|
|
|
contactGroups c gNames = [ttyContact c <> ": contact cannot be deleted, it is a member of the group(s) " <> ttyGroups gNames]
|
|
|
|
|
where
|
|
|
|
|
ttyGroups :: [GroupName] -> StyledString
|
|
|
|
|
ttyGroups [] = ""
|
|
|
|
|
ttyGroups [g] = ttyGroup g
|
|
|
|
|
ttyGroups (g : gs) = ttyGroup g <> ", " <> ttyGroups gs
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2021-07-16 07:40:55 +01:00
|
|
|
contactConnected :: Contact -> [StyledString]
|
2021-08-02 20:10:24 +01:00
|
|
|
contactConnected ct = [ttyFullContact ct <> ": contact is connected"]
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2021-07-14 20:11:41 +01:00
|
|
|
contactDisconnected :: ContactName -> [StyledString]
|
2021-08-02 20:10:24 +01:00
|
|
|
contactDisconnected c = [ttyContact c <> ": contact is disconnected - restart chat"]
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2021-07-25 20:23:52 +01:00
|
|
|
contactSubscribed :: ContactName -> [StyledString]
|
2021-08-02 20:10:24 +01:00
|
|
|
contactSubscribed c = [ttyContact c <> ": contact is active"]
|
2021-07-25 20:23:52 +01:00
|
|
|
|
|
|
|
|
contactSubError :: ContactName -> ChatError -> [StyledString]
|
2021-08-02 20:10:24 +01:00
|
|
|
contactSubError c e = [ttyContact c <> ": contact error " <> plain (show e)]
|
2021-07-25 20:23:52 +01:00
|
|
|
|
|
|
|
|
groupSubscribed :: GroupName -> [StyledString]
|
2021-08-02 20:10:24 +01:00
|
|
|
groupSubscribed g = [ttyGroup g <> ": group is active"]
|
|
|
|
|
|
|
|
|
|
groupEmpty :: GroupName -> [StyledString]
|
|
|
|
|
groupEmpty g = [ttyGroup g <> ": group is empty"]
|
|
|
|
|
|
|
|
|
|
groupRemoved :: GroupName -> [StyledString]
|
|
|
|
|
groupRemoved g = [ttyGroup g <> ": you are no longer a member or group deleted"]
|
2021-07-25 20:23:52 +01:00
|
|
|
|
|
|
|
|
memberSubError :: GroupName -> ContactName -> ChatError -> [StyledString]
|
|
|
|
|
memberSubError g c e = [ttyGroup g <> " member " <> ttyContact c <> " error: " <> plain (show e)]
|
|
|
|
|
|
2021-07-16 07:40:55 +01:00
|
|
|
groupCreated :: Group -> [StyledString]
|
|
|
|
|
groupCreated g@Group {localDisplayName} =
|
|
|
|
|
[ "group " <> ttyFullGroup g <> " is created",
|
2021-07-24 10:26:28 +01:00
|
|
|
"use " <> highlight ("/a " <> localDisplayName <> " <name>") <> " to add members"
|
2021-07-16 07:40:55 +01:00
|
|
|
]
|
|
|
|
|
|
2021-08-02 20:10:24 +01:00
|
|
|
groupDeletedUser :: GroupName -> [StyledString]
|
|
|
|
|
groupDeletedUser g = groupDeleted_ g Nothing
|
|
|
|
|
|
|
|
|
|
groupDeleted :: GroupName -> GroupMember -> [StyledString]
|
|
|
|
|
groupDeleted g m = groupDeleted_ g (Just m) <> ["use " <> highlight ("/d #" <> g) <> " to delete the local copy of the group"]
|
|
|
|
|
|
|
|
|
|
groupDeleted_ :: GroupName -> Maybe GroupMember -> [StyledString]
|
|
|
|
|
groupDeleted_ g m = [ttyGroup g <> ": " <> memberOrUser m <> " deleted the group"]
|
|
|
|
|
|
|
|
|
|
sentGroupInvitation :: GroupName -> ContactName -> [StyledString]
|
|
|
|
|
sentGroupInvitation g c = ["invitation to join the group " <> ttyGroup g <> " sent to " <> ttyContact c]
|
2021-07-16 07:40:55 +01:00
|
|
|
|
2021-07-24 10:26:28 +01:00
|
|
|
receivedGroupInvitation :: Group -> ContactName -> GroupMemberRole -> [StyledString]
|
|
|
|
|
receivedGroupInvitation g@Group {localDisplayName} c role =
|
|
|
|
|
[ ttyFullGroup g <> ": " <> ttyContact c <> " invites you to join the group as " <> plain (serializeMemberRole role),
|
|
|
|
|
"use " <> highlight ("/j " <> localDisplayName) <> " to accept"
|
2021-07-16 07:40:55 +01:00
|
|
|
]
|
|
|
|
|
|
2021-07-24 10:26:28 +01:00
|
|
|
joinedGroupMember :: GroupName -> GroupMember -> [StyledString]
|
|
|
|
|
joinedGroupMember g m = [ttyGroup g <> ": " <> ttyMember m <> " joined the group "]
|
|
|
|
|
|
|
|
|
|
userJoinedGroup :: GroupName -> [StyledString]
|
|
|
|
|
userJoinedGroup g = [ttyGroup g <> ": you joined the group"]
|
|
|
|
|
|
|
|
|
|
joinedGroupMemberConnecting :: GroupName -> GroupMember -> GroupMember -> [StyledString]
|
|
|
|
|
joinedGroupMemberConnecting g host m = [ttyGroup g <> ": " <> ttyMember host <> " added " <> ttyFullMember m <> " to the group (connecting...)"]
|
2021-07-16 07:40:55 +01:00
|
|
|
|
2021-07-24 10:26:28 +01:00
|
|
|
connectedToGroupMember :: GroupName -> GroupMember -> [StyledString]
|
|
|
|
|
connectedToGroupMember g m = [ttyGroup g <> ": " <> connectedMember m <> " is connected"]
|
2021-07-12 19:00:03 +01:00
|
|
|
|
2021-08-02 20:10:24 +01:00
|
|
|
deletedMember :: GroupName -> Maybe GroupMember -> Maybe GroupMember -> [StyledString]
|
|
|
|
|
deletedMember g by m = [ttyGroup g <> ": " <> memberOrUser by <> " removed " <> memberOrUser m <> " from the group"]
|
|
|
|
|
|
|
|
|
|
deletedMemberUser :: GroupName -> GroupMember -> [StyledString]
|
|
|
|
|
deletedMemberUser g by = deletedMember g (Just by) Nothing <> groupPreserved g
|
|
|
|
|
|
|
|
|
|
leftMemberUser :: GroupName -> [StyledString]
|
|
|
|
|
leftMemberUser g = leftMember_ g Nothing <> groupPreserved g
|
|
|
|
|
|
|
|
|
|
leftMember :: GroupName -> GroupMember -> [StyledString]
|
|
|
|
|
leftMember g m = leftMember_ g (Just m)
|
|
|
|
|
|
|
|
|
|
leftMember_ :: GroupName -> Maybe GroupMember -> [StyledString]
|
|
|
|
|
leftMember_ g m = [ttyGroup g <> ": " <> memberOrUser m <> " left the group"]
|
|
|
|
|
|
|
|
|
|
groupPreserved :: GroupName -> [StyledString]
|
|
|
|
|
groupPreserved g = ["use " <> highlight ("/d #" <> g) <> " to delete the group"]
|
|
|
|
|
|
|
|
|
|
memberOrUser :: Maybe GroupMember -> StyledString
|
|
|
|
|
memberOrUser = maybe "you" ttyMember
|
|
|
|
|
|
2021-07-24 10:26:28 +01:00
|
|
|
connectedMember :: GroupMember -> StyledString
|
|
|
|
|
connectedMember m = case memberCategory m of
|
|
|
|
|
GCPreMember -> "member " <> ttyFullMember m
|
|
|
|
|
GCPostMember -> "new member " <> ttyMember m -- without fullName as as it was shown in joinedGroupMemberConnecting
|
|
|
|
|
_ -> "member " <> ttyMember m -- these case is not used
|
|
|
|
|
|
2021-07-27 08:08:05 +01:00
|
|
|
groupMembers :: Group -> [StyledString]
|
|
|
|
|
groupMembers Group {membership, members} = map groupMember . filter (not . removedOrLeft) $ membership : members
|
|
|
|
|
where
|
|
|
|
|
removedOrLeft m = let s = memberStatus m in s == GSMemRemoved || s == GSMemLeft
|
|
|
|
|
groupMember m = ttyFullMember m <> ": " <> role m <> ", " <> category m <> status m
|
|
|
|
|
role = plain . serializeMemberRole . memberRole
|
|
|
|
|
category m = case memberCategory m of
|
|
|
|
|
GCUserMember -> "you, "
|
|
|
|
|
GCInviteeMember -> "invited, "
|
|
|
|
|
GCHostMember -> "host, "
|
|
|
|
|
_ -> ""
|
|
|
|
|
status m = case memberStatus m of
|
|
|
|
|
GSMemRemoved -> "removed"
|
|
|
|
|
GSMemLeft -> "left"
|
|
|
|
|
GSMemInvited -> "not yet joined"
|
|
|
|
|
GSMemConnected -> "connected"
|
|
|
|
|
GSMemComplete -> "connected"
|
|
|
|
|
GSMemCreator -> "created group"
|
|
|
|
|
_ -> ""
|
|
|
|
|
|
|
|
|
|
contactsMerged :: Contact -> Contact -> [StyledString]
|
|
|
|
|
contactsMerged _to@Contact {localDisplayName = c1} _from@Contact {localDisplayName = c2} =
|
|
|
|
|
[ "contact " <> ttyContact c2 <> " is merged into " <> ttyContact c1,
|
|
|
|
|
"use " <> ttyToContact c1 <> highlight' "<message>" <> " to send messages"
|
|
|
|
|
]
|
|
|
|
|
|
2021-07-24 10:26:28 +01:00
|
|
|
receivedMessage :: StyledString -> UTCTime -> Text -> MsgIntegrity -> IO [StyledString]
|
|
|
|
|
receivedMessage from utcTime msg mOk = do
|
2021-06-25 18:18:24 +01:00
|
|
|
t <- formatUTCTime <$> getCurrentTimeZone <*> getZonedTime
|
2021-07-24 10:26:28 +01:00
|
|
|
pure $ prependFirst (t <> " " <> from) (msgPlain msg) ++ showIntegrity mOk
|
2021-06-25 18:18:24 +01:00
|
|
|
where
|
|
|
|
|
formatUTCTime :: TimeZone -> ZonedTime -> StyledString
|
|
|
|
|
formatUTCTime localTz currentTime =
|
|
|
|
|
let localTime = utcToLocalTime localTz utcTime
|
|
|
|
|
format =
|
|
|
|
|
if (localDay localTime < localDay (zonedTimeToLocalTime currentTime))
|
|
|
|
|
&& (timeOfDayToTime (localTimeOfDay localTime) > (6 * 60 * 60 :: DiffTime))
|
|
|
|
|
then "%m-%d" -- if message is from yesterday or before and 6 hours has passed since midnight
|
|
|
|
|
else "%H:%M"
|
|
|
|
|
in styleTime $ formatTime defaultTimeLocale format localTime
|
|
|
|
|
showIntegrity :: MsgIntegrity -> [StyledString]
|
|
|
|
|
showIntegrity MsgOk = []
|
|
|
|
|
showIntegrity (MsgError err) = msgError $ case err of
|
|
|
|
|
MsgSkipped fromId toId ->
|
|
|
|
|
"skipped message ID " <> show fromId
|
|
|
|
|
<> if fromId == toId then "" else ".." <> show toId
|
|
|
|
|
MsgBadId msgId -> "unexpected message ID " <> show msgId
|
|
|
|
|
MsgBadHash -> "incorrect message hash"
|
|
|
|
|
MsgDuplicate -> "duplicate message ID"
|
|
|
|
|
msgError :: String -> [StyledString]
|
|
|
|
|
msgError s = [styled (Colored Red) s]
|
|
|
|
|
|
2021-07-24 10:26:28 +01:00
|
|
|
sentMessage :: StyledString -> ByteString -> IO [StyledString]
|
|
|
|
|
sentMessage to msg = do
|
2021-06-25 18:18:24 +01:00
|
|
|
time <- formatTime defaultTimeLocale "%H:%M" <$> getZonedTime
|
2021-07-24 10:26:28 +01:00
|
|
|
pure $ prependFirst (styleTime time <> " " <> to) (msgPlain $ safeDecodeUtf8 msg)
|
2021-06-25 18:18:24 +01:00
|
|
|
|
|
|
|
|
prependFirst :: StyledString -> [StyledString] -> [StyledString]
|
|
|
|
|
prependFirst s [] = [s]
|
|
|
|
|
prependFirst s (s' : ss) = (s <> s') : ss
|
|
|
|
|
|
2021-07-04 18:42:24 +01:00
|
|
|
msgPlain :: Text -> [StyledString]
|
|
|
|
|
msgPlain = map styleMarkdownText . T.lines
|
|
|
|
|
|
|
|
|
|
chatError :: ChatError -> [StyledString]
|
|
|
|
|
chatError = \case
|
2021-07-16 07:40:55 +01:00
|
|
|
ChatError err -> case err of
|
|
|
|
|
CEGroupDuplicateMember c -> ["contact " <> ttyContact c <> " is already in the group"]
|
|
|
|
|
CEGroupDuplicateMemberId -> ["cannot add member - duplicate member ID"]
|
2021-07-24 10:26:28 +01:00
|
|
|
CEGroupUserRole -> ["you have insufficient permissions for this group command"]
|
|
|
|
|
CEGroupContactRole c -> ["contact " <> ttyContact c <> " has insufficient permissions for this group action"]
|
2021-07-16 07:40:55 +01:00
|
|
|
CEGroupNotJoined g -> ["you did not join this group, use " <> highlight ("/join #" <> g)]
|
2021-07-24 10:26:28 +01:00
|
|
|
CEGroupMemberNotActive -> ["you cannot invite other members yet, try later"]
|
2021-08-02 20:10:24 +01:00
|
|
|
CEGroupMemberUserRemoved -> ["you are no longer the member of the group"]
|
|
|
|
|
CEGroupMemberNotFound c -> ["contact " <> ttyContact c <> " is not a group member"]
|
2021-07-16 07:40:55 +01:00
|
|
|
CEGroupInternal s -> ["chat group bug: " <> plain s]
|
|
|
|
|
-- e -> ["chat error: " <> plain (show e)]
|
2021-07-12 19:00:03 +01:00
|
|
|
ChatErrorStore err -> case err of
|
2021-07-14 20:11:41 +01:00
|
|
|
SEDuplicateName -> ["this display name is already used by user, contact or group"]
|
2021-07-12 19:00:03 +01:00
|
|
|
SEContactNotFound c -> ["no contact " <> ttyContact c]
|
|
|
|
|
SEContactNotReady c -> ["contact " <> ttyContact c <> " is not active yet"]
|
2021-07-16 07:40:55 +01:00
|
|
|
SEGroupNotFound g -> ["no group " <> ttyGroup g]
|
|
|
|
|
SEGroupAlreadyJoined -> ["you already joined this group"]
|
2021-07-12 19:00:03 +01:00
|
|
|
e -> ["chat db error: " <> plain (show e)]
|
2021-08-02 20:10:24 +01:00
|
|
|
ChatErrorAgent e -> ["smp agent error: " <> plain (show e)]
|
2021-07-16 07:40:55 +01:00
|
|
|
ChatErrorMessage e -> ["chat message error: " <> plain (show e)]
|
2021-06-25 18:18:24 +01:00
|
|
|
|
|
|
|
|
printToView :: (MonadUnliftIO m, MonadReader ChatController m) => [StyledString] -> m ()
|
|
|
|
|
printToView s = asks chatTerminal >>= liftIO . (`printToTerminal` s)
|
|
|
|
|
|
2021-07-14 20:11:41 +01:00
|
|
|
ttyContact :: ContactName -> StyledString
|
2021-07-04 18:42:24 +01:00
|
|
|
ttyContact = styled (Colored Green)
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2021-07-16 07:40:55 +01:00
|
|
|
ttyFullContact :: Contact -> StyledString
|
|
|
|
|
ttyFullContact Contact {localDisplayName, profile = Profile {fullName}} =
|
2021-07-24 10:26:28 +01:00
|
|
|
ttyFullName localDisplayName fullName
|
|
|
|
|
|
|
|
|
|
ttyMember :: GroupMember -> StyledString
|
|
|
|
|
ttyMember GroupMember {localDisplayName} = ttyContact localDisplayName
|
|
|
|
|
|
|
|
|
|
ttyFullMember :: GroupMember -> StyledString
|
|
|
|
|
ttyFullMember GroupMember {localDisplayName, memberProfile = Profile {fullName}} =
|
|
|
|
|
ttyFullName localDisplayName fullName
|
|
|
|
|
|
|
|
|
|
ttyFullName :: ContactName -> Text -> StyledString
|
|
|
|
|
ttyFullName c fullName = ttyContact c <> optFullName c fullName
|
2021-07-16 07:40:55 +01:00
|
|
|
|
2021-07-14 20:11:41 +01:00
|
|
|
ttyToContact :: ContactName -> StyledString
|
2021-07-07 22:46:38 +01:00
|
|
|
ttyToContact c = styled (Colored Cyan) $ "@" <> c <> " "
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2021-07-14 20:11:41 +01:00
|
|
|
ttyFromContact :: ContactName -> StyledString
|
2021-07-04 18:42:24 +01:00
|
|
|
ttyFromContact c = styled (Colored Yellow) $ c <> "> "
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2021-07-14 20:11:41 +01:00
|
|
|
ttyGroup :: GroupName -> StyledString
|
2021-07-12 19:00:03 +01:00
|
|
|
ttyGroup g = styled (Colored Blue) $ "#" <> g
|
2021-06-25 18:18:24 +01:00
|
|
|
|
2021-07-16 07:40:55 +01:00
|
|
|
ttyFullGroup :: Group -> StyledString
|
|
|
|
|
ttyFullGroup Group {localDisplayName, groupProfile = GroupProfile {fullName}} =
|
|
|
|
|
ttyGroup localDisplayName <> optFullName localDisplayName fullName
|
|
|
|
|
|
2021-07-24 10:26:28 +01:00
|
|
|
ttyFromGroup :: GroupName -> ContactName -> StyledString
|
|
|
|
|
ttyFromGroup g c = styled (Colored Yellow) $ "#" <> g <> " " <> c <> "> "
|
|
|
|
|
|
|
|
|
|
ttyToGroup :: GroupName -> StyledString
|
|
|
|
|
ttyToGroup g = styled (Colored Cyan) $ "#" <> g <> " "
|
|
|
|
|
|
|
|
|
|
optFullName :: ContactName -> Text -> StyledString
|
2021-07-16 07:40:55 +01:00
|
|
|
optFullName localDisplayName fullName
|
2021-07-24 10:26:28 +01:00
|
|
|
| T.null fullName || localDisplayName == fullName = ""
|
2021-07-16 07:40:55 +01:00
|
|
|
| otherwise = plain (" (" <> fullName <> ")")
|
|
|
|
|
|
|
|
|
|
highlight :: StyledFormat a => a -> StyledString
|
|
|
|
|
highlight = styled (Colored Cyan)
|
|
|
|
|
|
|
|
|
|
highlight' :: String -> StyledString
|
|
|
|
|
highlight' = highlight
|
|
|
|
|
|
2021-06-25 18:18:24 +01:00
|
|
|
styleTime :: String -> StyledString
|
|
|
|
|
styleTime = Styled [SetColor Foreground Vivid Black]
|