From 08dd92b72673ff44591b2977900d85cc20f88018 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Thu, 3 Feb 2022 18:22:05 +0000 Subject: [PATCH 1/3] configure build for device/simulator --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 68 +++++++++------------- 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 3396c6b04..d76ca10e7 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -11,14 +11,13 @@ 5C063D2827A4564100AEC577 /* ChatPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */; }; 5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; }; 5C116CDD27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; }; + 5C116CF027ABC81C00E66D01 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C116CEB27ABC81C00E66D01 /* libgmp.a */; }; + 5C116CF127ABC81C00E66D01 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C116CEC27ABC81C00E66D01 /* libgmpxx.a */; }; + 5C116CF227ABC81C00E66D01 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C116CED27ABC81C00E66D01 /* libffi.a */; }; + 5C116CF327ABC81C00E66D01 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C116CEE27ABC81C00E66D01 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a */; }; + 5C116CF427ABC81C00E66D01 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C116CEF27ABC81C00E66D01 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a */; }; 5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; }; 5C1A4C1F27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; }; - 5C1AEB86279F4A6400247F08 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7F279F4A6400247F08 /* libffi.a */; }; - 5C1AEB87279F4A6400247F08 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7F279F4A6400247F08 /* libffi.a */; }; - 5C1AEB88279F4A6400247F08 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB80279F4A6400247F08 /* libgmp.a */; }; - 5C1AEB89279F4A6400247F08 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB80279F4A6400247F08 /* libgmp.a */; }; - 5C1AEB8A279F4A6400247F08 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB81279F4A6400247F08 /* libgmpxx.a */; }; - 5C1AEB8B279F4A6400247F08 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB81279F4A6400247F08 /* libgmpxx.a */; }; 5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; }; 5C2E260827A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; }; 5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; }; @@ -27,10 +26,6 @@ 5C2E261027A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; }; 5C2E261227A30FEA00F70299 /* TerminalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E261127A30FEA00F70299 /* TerminalView.swift */; }; 5C2E261327A30FEA00F70299 /* TerminalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E261127A30FEA00F70299 /* TerminalView.swift */; }; - 5C44B6A027A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C44B69E27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a */; }; - 5C44B6A127A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C44B69E27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a */; }; - 5C44B6A227A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C44B69F27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a */; }; - 5C44B6A327A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C44B69F27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a */; }; 5C6AD81327A834E300348BD7 /* NewChatButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6AD81227A834E300348BD7 /* NewChatButton.swift */; }; 5C6AD81427A834E300348BD7 /* NewChatButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6AD81227A834E300348BD7 /* NewChatButton.swift */; }; 5C764E80279C7276000C6508 /* dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C764E7F279C7276000C6508 /* dummy.m */; }; @@ -100,18 +95,18 @@ /* Begin PBXFileReference section */ 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatPreviewView.swift; sourceTree = ""; }; 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestView.swift; sourceTree = ""; }; + 5C116CEB27ABC81C00E66D01 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + 5C116CEC27ABC81C00E66D01 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + 5C116CED27ABC81C00E66D01 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; + 5C116CEE27ABC81C00E66D01 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a"; sourceTree = ""; }; + 5C116CEF27ABC81C00E66D01 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a"; sourceTree = ""; }; 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemView.swift; sourceTree = ""; }; - 5C1AEB7F279F4A6400247F08 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - 5C1AEB80279F4A6400247F08 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - 5C1AEB81279F4A6400247F08 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXAPI.swift; sourceTree = ""; }; 5C2E260927A2C63500F70299 /* MyPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = MyPlayground.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 5C2E260A27A30CFA00F70299 /* ChatListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListView.swift; sourceTree = ""; }; 5C2E260E27A30FDC00F70299 /* ChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = ""; }; 5C2E261127A30FEA00F70299 /* TerminalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalView.swift; sourceTree = ""; }; 5C422A7C27A9A6FA0097A1E1 /* SimpleX (iOS).entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SimpleX (iOS).entitlements"; sourceTree = ""; }; - 5C44B69E27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a"; sourceTree = ""; }; - 5C44B69F27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a"; sourceTree = ""; }; 5C6AD81227A834E300348BD7 /* NewChatButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewChatButton.swift; sourceTree = ""; }; 5C764E7B279C71D4000C6508 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/usr/lib/libiconv.tbd; sourceTree = DEVELOPER_DIR; }; 5C764E7C279C71DB000C6508 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; }; @@ -151,13 +146,13 @@ buildActionMask = 2147483647; files = ( 5C8F01CD27A6F0D8007D2C8D /* CodeScanner in Frameworks */, + 5C116CF227ABC81C00E66D01 /* libffi.a in Frameworks */, + 5C116CF427ABC81C00E66D01 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a in Frameworks */, + 5C116CF127ABC81C00E66D01 /* libgmpxx.a in Frameworks */, + 5C116CF327ABC81C00E66D01 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a in Frameworks */, 5C764E83279C748B000C6508 /* libz.tbd in Frameworks */, + 5C116CF027ABC81C00E66D01 /* libgmp.a in Frameworks */, 5C764E82279C748B000C6508 /* libiconv.tbd in Frameworks */, - 5C1AEB86279F4A6400247F08 /* libffi.a in Frameworks */, - 5C44B6A227A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a in Frameworks */, - 5C1AEB88279F4A6400247F08 /* libgmp.a in Frameworks */, - 5C44B6A027A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a in Frameworks */, - 5C1AEB8A279F4A6400247F08 /* libgmpxx.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -167,11 +162,6 @@ files = ( 5C764E85279C748C000C6508 /* libz.tbd in Frameworks */, 5C764E84279C748C000C6508 /* libiconv.tbd in Frameworks */, - 5C1AEB87279F4A6400247F08 /* libffi.a in Frameworks */, - 5C44B6A327A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a in Frameworks */, - 5C1AEB89279F4A6400247F08 /* libgmp.a in Frameworks */, - 5C44B6A127A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a in Frameworks */, - 5C1AEB8B279F4A6400247F08 /* libgmpxx.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -218,11 +208,11 @@ 5C764E5C279C70B7000C6508 /* Libraries */ = { isa = PBXGroup; children = ( - 5C1AEB7F279F4A6400247F08 /* libffi.a */, - 5C1AEB80279F4A6400247F08 /* libgmp.a */, - 5C1AEB81279F4A6400247F08 /* libgmpxx.a */, - 5C44B69F27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a */, - 5C44B69E27A5FF22001C3154 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a */, + 5C116CED27ABC81C00E66D01 /* libffi.a */, + 5C116CEB27ABC81C00E66D01 /* libgmp.a */, + 5C116CEC27ABC81C00E66D01 /* libgmpxx.a */, + 5C116CEE27ABC81C00E66D01 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w-ghc8.10.7.a */, + 5C116CEF27ABC81C00E66D01 /* libHSsimplex-chat-1.0.2-5okwuQXOXC78H7u8DMgS6w.a */, ); path = Libraries; sourceTree = ""; @@ -744,12 +734,9 @@ "$(inherited)", "@executable_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Libraries", - "$(PROJECT_DIR)/Libraries/ios", - "$(PROJECT_DIR)/Libraries/sim", - ); + LIBRARY_SEARCH_PATHS = ""; + "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = "$(PROJECT_DIR)/Libraries/ios"; + "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = "$(PROJECT_DIR)/Libraries/sim"; MARKETING_VERSION = 1.0.1; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; PRODUCT_NAME = SimpleX; @@ -787,12 +774,9 @@ "$(inherited)", "@executable_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Libraries", - "$(PROJECT_DIR)/Libraries/ios", - "$(PROJECT_DIR)/Libraries/sim", - ); + LIBRARY_SEARCH_PATHS = ""; + "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = "$(PROJECT_DIR)/Libraries/ios"; + "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = "$(PROJECT_DIR)/Libraries/sim"; MARKETING_VERSION = 1.0.1; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; PRODUCT_NAME = SimpleX; From 565bc708437f575a9621928dc1502b2cd40919f3 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Fri, 4 Feb 2022 08:02:48 +0000 Subject: [PATCH 2/3] sync commands --- src/Simplex/Chat.hs | 24 ++++++++++++------------ src/Simplex/Chat/View.hs | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index 8b8e867d0..58b4e2807 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -357,19 +357,19 @@ processChatCommand user@User {userId, profile} = \case QuitChat -> liftIO exitSuccess ShowVersion -> pure CRVersionInfo where - procCmd :: m ChatResponse -> m ChatResponse - procCmd action = do - -- below code would make command responses asynchronous where they can be slow - -- in View.hs `r'` should be defined as `id` in this case - ChatController {chatLock = l, smpAgent = a, outputQ = q, idsDrg = gVar} <- ask - corrId <- liftIO $ SMP.CorrId <$> randomBytes gVar 8 - void . forkIO $ - withAgentLock a . withLock l $ - (atomically . writeTBQueue q) . (Just corrId,) =<< (action `catchError` (pure . CRChatError)) - pure $ CRCmdAccepted corrId - -- use function below to make commands "synchronous" + -- below code would make command responses asynchronous where they can be slow + -- in View.hs `r'` should be defined as `id` in this case -- procCmd :: m ChatResponse -> m ChatResponse - -- procCmd action = action + -- procCmd action = do + -- ChatController {chatLock = l, smpAgent = a, outputQ = q, idsDrg = gVar} <- ask + -- corrId <- liftIO $ SMP.CorrId <$> randomBytes gVar 8 + -- void . forkIO $ + -- withAgentLock a . withLock l $ + -- (atomically . writeTBQueue q) . (Just corrId,) =<< (action `catchError` (pure . CRChatError)) + -- pure $ CRCmdAccepted corrId + -- use function below to make commands "synchronous" + procCmd :: m ChatResponse -> m ChatResponse + procCmd = id connect :: ConnectionRequestUri c -> ChatMsgEvent -> m () connect cReq msg = do connId <- withAgent $ \a -> joinConnection a cReq $ directMessage msg diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs index 527ce3bac..69dc24282 100644 --- a/src/Simplex/Chat/View.hs +++ b/src/Simplex/Chat/View.hs @@ -118,8 +118,8 @@ responseToView cmd = \case api = (highlight cmd :) r = (plain cmd :) -- this function should be `r` for "synchronous", `id` for "asynchronous" command responses - -- r' = r - r' = id + -- r' = id + r' = r viewChatItem :: ChatInfo c -> ChatItem c d -> [StyledString] viewChatItem chat (ChatItem cd meta content) = case (chat, cd) of From d07ce0b8f494f5df23287e96309615294920d4d9 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Fri, 4 Feb 2022 08:15:25 +0000 Subject: [PATCH 3/3] use 8 byte characters, as encoding is handled elsewhere --- src/Simplex/Chat/Mobile.hs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Simplex/Chat/Mobile.hs b/src/Simplex/Chat/Mobile.hs index cdcf40cdd..e5bf539ae 100644 --- a/src/Simplex/Chat/Mobile.hs +++ b/src/Simplex/Chat/Mobile.hs @@ -40,18 +40,18 @@ foreign export ccall "chat_recv_msg" cChatRecvMsg :: StablePtr ChatController -> -- | creates or connects to chat store cChatInitStore :: CString -> IO (StablePtr ChatStore) -cChatInitStore fp = peekCString fp >>= chatInitStore >>= newStablePtr +cChatInitStore fp = peekCAString fp >>= chatInitStore >>= newStablePtr -- | returns JSON in the form `{"user": }` or `{}` in case there is no active user (to show dialog to enter displayName/fullName) cChatGetUser :: StablePtr ChatStore -> IO CJSONString -cChatGetUser cc = deRefStablePtr cc >>= chatGetUser >>= newCString +cChatGetUser cc = deRefStablePtr cc >>= chatGetUser >>= newCAString -- | accepts Profile JSON, returns JSON `{"user": }` or `{"error": ""}` cChatCreateUser :: StablePtr ChatStore -> CJSONString -> IO CJSONString cChatCreateUser cPtr profileCJson = do c <- deRefStablePtr cPtr - p <- peekCString profileCJson - newCString =<< chatCreateUser c p + p <- peekCAString profileCJson + newCAString =<< chatCreateUser c p -- | this function starts chat - it cannot be started during initialization right now, as it cannot work without user (to be fixed later) cChatStart :: StablePtr ChatStore -> IO (StablePtr ChatController) @@ -61,12 +61,12 @@ cChatStart st = deRefStablePtr st >>= chatStart >>= newStablePtr cChatSendCmd :: StablePtr ChatController -> CString -> IO CJSONString cChatSendCmd cPtr cCmd = do c <- deRefStablePtr cPtr - cmd <- peekCString cCmd - newCString =<< chatSendCmd c cmd + cmd <- peekCAString cCmd + newCAString =<< chatSendCmd c cmd -- | receive message from chat (blocking) cChatRecvMsg :: StablePtr ChatController -> IO CJSONString -cChatRecvMsg cc = deRefStablePtr cc >>= chatRecvMsg >>= newCString +cChatRecvMsg cc = deRefStablePtr cc >>= chatRecvMsg >>= newCAString mobileChatOpts :: ChatOpts mobileChatOpts =