diff --git a/apps/simplex-broadcast-bot/src/Broadcast/Options.hs b/apps/simplex-broadcast-bot/src/Broadcast/Options.hs index 5bc4ffef25..932a6919d3 100644 --- a/apps/simplex-broadcast-bot/src/Broadcast/Options.hs +++ b/apps/simplex-broadcast-bot/src/Broadcast/Options.hs @@ -76,6 +76,7 @@ mkChatOpts BroadcastBotOpts {coreOptions} = ChatOpts { coreOptions, deviceName = Nothing, + displayName = Nothing, chatCmd = "", chatCmdDelay = 3, chatCmdLog = CCLNone, diff --git a/apps/simplex-directory-service/src/Directory/Options.hs b/apps/simplex-directory-service/src/Directory/Options.hs index 7f02a580e6..41e6402fcd 100644 --- a/apps/simplex-directory-service/src/Directory/Options.hs +++ b/apps/simplex-directory-service/src/Directory/Options.hs @@ -85,6 +85,7 @@ mkChatOpts DirectoryOpts {coreOptions} = ChatOpts { coreOptions, deviceName = Nothing, + displayName = Nothing, chatCmd = "", chatCmdDelay = 3, chatCmdLog = CCLNone, diff --git a/src/Simplex/Chat/Core.hs b/src/Simplex/Chat/Core.hs index ad2f1367da..b3ee163c79 100644 --- a/src/Simplex/Chat/Core.hs +++ b/src/Simplex/Chat/Core.hs @@ -23,7 +23,7 @@ import Simplex.Chat import Simplex.Chat.Controller import Simplex.Chat.Options (ChatOpts (..), CoreChatOpts (..)) import Simplex.Chat.Store.Profiles -import Simplex.Chat.Types +import Simplex.Chat.Types (User (..), ContactName, Profile (..), NewUser (..), LocalProfile (..)) import Simplex.Chat.View (serializeChatResponse) import Simplex.Messaging.Agent.Store.SQLite (SQLiteStore, withTransaction) import System.Exit (exitFailure) @@ -32,7 +32,7 @@ import Text.Read (readMaybe) import UnliftIO.Async simplexChatCore :: ChatConfig -> ChatOpts -> (User -> ChatController -> IO ()) -> IO () -simplexChatCore cfg@ChatConfig {confirmMigrations, testView} opts@ChatOpts {coreOptions = CoreChatOpts {dbFilePrefix, dbKey, logAgent}} chat = +simplexChatCore cfg@ChatConfig {confirmMigrations, testView} opts@ChatOpts {coreOptions = CoreChatOpts {dbFilePrefix, dbKey, logAgent}, displayName} chat = case logAgent of Just level -> do setLogLevel level @@ -44,9 +44,9 @@ simplexChatCore cfg@ChatConfig {confirmMigrations, testView} opts@ChatOpts {core putStrLn $ "Error opening database: " <> show e exitFailure run db@ChatDatabase {chatStore} = do - u_ <- getSelectActiveUser chatStore + u_ <- getSelectActiveUser chatStore displayName cc <- newChatController db u_ cfg opts False - u <- maybe (createActiveUser cc) pure u_ + u <- maybe (createActiveUser cc displayName) pure u_ unless testView $ putStrLn $ "Current user: " <> userStr u runSimplexChat opts u cc chat @@ -64,12 +64,16 @@ sendChatCmdStr cc s = runReaderT (execChatCommand Nothing . encodeUtf8 $ T.pack sendChatCmd :: ChatController -> ChatCommand -> IO ChatResponse sendChatCmd cc cmd = runReaderT (execChatCommand' cmd) cc -getSelectActiveUser :: SQLiteStore -> IO (Maybe User) -getSelectActiveUser st = do +getSelectActiveUser :: SQLiteStore -> Maybe ContactName -> IO (Maybe User) +getSelectActiveUser st displayName = do users <- withTransaction st getUsers - case find activeUser users of - Just u -> pure $ Just u - Nothing -> selectUser users + case displayName of + Just name -> case find (\User {localDisplayName} -> localDisplayName == name) users of + Just u -> pure $ Just u + Nothing -> pure Nothing + Nothing -> case find activeUser users of + Just u -> pure $ Just u + Nothing -> selectUser users where selectUser :: [User] -> IO (Maybe User) selectUser = \case @@ -90,8 +94,8 @@ getSelectActiveUser st = do let user = users !! (n - 1) in Just <$> withTransaction st (`setActiveUser` user) -createActiveUser :: ChatController -> IO User -createActiveUser cc = do +createActiveUser :: ChatController -> Maybe ContactName -> IO User +createActiveUser cc name = do putStrLn "No user profiles found, it will be created now.\n\ \Please choose your display name.\n\ @@ -100,7 +104,9 @@ createActiveUser cc = do loop where loop = do - displayName <- T.pack <$> getWithPrompt "display name" + displayName <- case name of + Just n | not (T.null n) -> pure n + _ -> T.pack <$> getWithPrompt "display name" let profile = Just Profile {displayName, fullName = "", image = Nothing, contactLink = Nothing, preferences = Nothing} execChatCommand' (CreateActiveUser NewUser {profile, pastTimestamp = False}) `runReaderT` cc >>= \case CRActiveUser user -> pure user diff --git a/src/Simplex/Chat/Mobile.hs b/src/Simplex/Chat/Mobile.hs index 57b0ee6c17..68fffa0f7b 100644 --- a/src/Simplex/Chat/Mobile.hs +++ b/src/Simplex/Chat/Mobile.hs @@ -202,6 +202,7 @@ mobileChatOpts dbFilePrefix = yesToUpMigrations = False }, deviceName = Nothing, + displayName = Nothing, chatCmd = "", chatCmdDelay = 3, chatCmdLog = CCLNone, diff --git a/src/Simplex/Chat/Options.hs b/src/Simplex/Chat/Options.hs index f398831194..0f0ebcc1df 100644 --- a/src/Simplex/Chat/Options.hs +++ b/src/Simplex/Chat/Options.hs @@ -35,10 +35,12 @@ import Simplex.Messaging.Parsers (parseAll) import Simplex.Messaging.Protocol (ProtoServerWithAuth, ProtocolTypeI, SMPServerWithAuth, XFTPServerWithAuth) import Simplex.Messaging.Transport.Client (SocksProxyWithAuth (..), SocksAuth (..), defaultSocksProxyWithAuth) import System.FilePath (combine) +import Simplex.Chat.Types (ContactName) data ChatOpts = ChatOpts { coreOptions :: CoreChatOpts, deviceName :: Maybe Text, + displayName :: Maybe ContactName, chatCmd :: String, chatCmdDelay :: Int, chatCmdLog :: ChatCmdLog, @@ -286,6 +288,13 @@ chatOptsP appDir defaultDbFileName = do <> metavar "DEVICE" <> help "Device name to use in connections with remote hosts and controller" ) + displayName <- + optional $ + strOption + ( long "display-name" + <> metavar "DISPLAY_NAME" + <> help "Display name will be sent to your contacts when you connect and only stored on your device and you can change it later." + ) chatCmd <- strOption ( long "execute" @@ -375,6 +384,7 @@ chatOptsP appDir defaultDbFileName = do pure ChatOpts { coreOptions, + displayName, deviceName, chatCmd, chatCmdDelay, diff --git a/tests/ChatClient.hs b/tests/ChatClient.hs index 8b7e8fcd32..b11a5903bf 100644 --- a/tests/ChatClient.hs +++ b/tests/ChatClient.hs @@ -74,6 +74,7 @@ testOpts = ChatOpts { coreOptions = testCoreOpts, deviceName = Nothing, + displayName = Nothing, chatCmd = "", chatCmdDelay = 3, chatCmdLog = CCLNone, diff --git a/tests/ChatTests/Profiles.hs b/tests/ChatTests/Profiles.hs index 3ff8808541..6827061015 100644 --- a/tests/ChatTests/Profiles.hs +++ b/tests/ChatTests/Profiles.hs @@ -224,9 +224,9 @@ testMultiWordProfileNames = alice #> "@'Cath J' hi" cath <# "'Alice Jones'> hi" where - aliceProfile' = baseProfile {displayName = "Alice Jones"} - bobProfile' = baseProfile {displayName = "Bob James"} - cathProfile' = baseProfile {displayName = "Cath Johnson"} + aliceProfile' = (baseProfile :: Profile) {displayName = "Alice Jones"} + bobProfile' = (baseProfile :: Profile) {displayName = "Bob James"} + cathProfile' = (baseProfile :: Profile) {displayName = "Cath Johnson"} baseProfile = Profile {displayName = "", fullName = "", image = Nothing, contactLink = Nothing, preferences = defaultPrefs} testUserContactLink :: HasCallStack => FilePath -> IO ()