From 3af2848275dc9eda910b59280dfd81c7e9525116 Mon Sep 17 00:00:00 2001
From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Date: Fri, 26 May 2023 15:19:20 +0400
Subject: [PATCH 1/3] ios: fix database view crashing when in Japanese (#2516)
---
.../SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff | 2 +-
apps/ios/ja.lproj/Localizable.strings | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff
index 39d331773a..18d8359928 100644
--- a/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff
+++ b/apps/ios/SimpleX Localizations/ja.xcloc/Localized Contents/ja.xliff
@@ -154,7 +154,7 @@
%lld file(s) with total size of %@
- 合計サイズ %@ の %lld 件のファイル
+ %lld 個のファイル(合計サイズ: %@)
No comment provided by engineer.
diff --git a/apps/ios/ja.lproj/Localizable.strings b/apps/ios/ja.lproj/Localizable.strings
index 0b0407856c..255d5f4654 100644
--- a/apps/ios/ja.lproj/Localizable.strings
+++ b/apps/ios/ja.lproj/Localizable.strings
@@ -152,7 +152,7 @@
"%lld contact(s) selected" = "%lld 件の連絡先が選択されました";
/* No comment provided by engineer. */
-"%lld file(s) with total size of %@" = "合計サイズ %@ の %lld 件のファイル";
+"%lld file(s) with total size of %@" = "%lld 個のファイル(合計サイズ: %@)";
/* No comment provided by engineer. */
"%lld members" = "%lld 人のメンバー";
From 42d4f94fecfc3f5222e6f79b2fb715cf98f54ab1 Mon Sep 17 00:00:00 2001
From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Date: Fri, 26 May 2023 15:49:26 +0400
Subject: [PATCH 2/3] mobile: always show chat list search (#2517)
---
.../app/views/chatlist/ChatListView.kt | 2 +-
.../Shared/Views/ChatList/ChatListView.swift | 40 +++++++++++--------
2 files changed, 24 insertions(+), 18 deletions(-)
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt
index 6104f7e6b0..07c859e508 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt
@@ -176,7 +176,7 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user
BackHandler(onBack = hideSearchOnBack)
}
val barButtons = arrayListOf<@Composable RowScope.() -> Unit>()
- if (chatModel.chats.size >= 8) {
+ if (chatModel.chats.size > 0) {
barButtons.add {
IconButton({ showSearch = true }) {
Icon(painterResource(R.drawable.ic_search_500), stringResource(android.R.string.search_go).capitalize(Locale.current), tint = MaterialTheme.colors.primary)
diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift
index 296bcced21..c372acdd24 100644
--- a/apps/ios/Shared/Views/ChatList/ChatListView.swift
+++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift
@@ -29,11 +29,7 @@ struct ChatListView: View {
if chatModel.chats.isEmpty {
onboardingButtons()
}
- if chatModel.chats.count > 8 {
- chatList.searchable(text: $searchText)
- } else {
- chatList
- }
+ chatListView
}
}
if userPickerVisible {
@@ -47,18 +43,12 @@ struct ChatListView: View {
}
}
- var chatList: some View {
- List {
- ForEach(filteredChats(), id: \.viewId) { chat in
- ChatListNavLink(chat: chat)
- .padding(.trailing, -16)
- .disabled(chatModel.chatRunning != true)
- }
- }
- .onChange(of: chatModel.chatId) { _ in
- if chatModel.chatId == nil, let chatId = chatModel.chatToTop {
- chatModel.chatToTop = nil
- chatModel.popChat(chatId)
+ private var chatListView: some View {
+ VStack {
+ if chatModel.chats.count > 0 {
+ chatList.searchable(text: $searchText)
+ } else {
+ chatList
}
}
.onChange(of: chatModel.appOpenUrl) { _ in connectViaUrl() }
@@ -116,6 +106,22 @@ struct ChatListView: View {
}
}
+ private var chatList: some View {
+ List {
+ ForEach(filteredChats(), id: \.viewId) { chat in
+ ChatListNavLink(chat: chat)
+ .padding(.trailing, -16)
+ .disabled(chatModel.chatRunning != true)
+ }
+ }
+ .onChange(of: chatModel.chatId) { _ in
+ if chatModel.chatId == nil, let chatId = chatModel.chatToTop {
+ chatModel.chatToTop = nil
+ chatModel.popChat(chatId)
+ }
+ }
+ }
+
private func unreadBadge(_ text: Text? = Text(" "), size: CGFloat = 18) -> some View {
Circle()
.frame(width: size, height: size)
From bd069aea499e729132a2e325600f4d5f88c11b56 Mon Sep 17 00:00:00 2001
From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Date: Fri, 26 May 2023 17:36:06 +0400
Subject: [PATCH 3/3] core: add debug info to CEInvalidChatMessage (#2518)
---
src/Simplex/Chat.hs | 34 ++++++++++++++++++----------------
src/Simplex/Chat/Controller.hs | 2 +-
src/Simplex/Chat/View.hs | 7 ++++++-
3 files changed, 25 insertions(+), 18 deletions(-)
diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs
index 16596b1073..74cf584a4f 100644
--- a/src/Simplex/Chat.hs
+++ b/src/Simplex/Chat.hs
@@ -2738,7 +2738,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
_ -> messageError $ "unsupported message: " <> T.pack (show event)
CONF confId _ connInfo -> do
-- confirming direct connection with a member
- ChatMessage {chatMsgEvent} <- parseChatMessage connInfo
+ ChatMessage {chatMsgEvent} <- parseChatMessage conn connInfo
case chatMsgEvent of
XGrpMemInfo _memId _memProfile -> do
-- TODO check member ID
@@ -2747,7 +2747,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
allowAgentConnectionAsync user conn confId XOk
_ -> messageError "CONF from member must have x.grp.mem.info"
INFO connInfo -> do
- ChatMessage {chatMsgEvent} <- parseChatMessage connInfo
+ ChatMessage {chatMsgEvent} <- parseChatMessage conn connInfo
case chatMsgEvent of
XGrpMemInfo _memId _memProfile -> do
-- TODO check member ID
@@ -2863,7 +2863,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
_ -> throwChatError $ CECommandError "unexpected cmdFunction"
CRContactUri _ -> throwChatError $ CECommandError "unexpected ConnectionRequestUri type"
CONF confId _ connInfo -> do
- ChatMessage {chatMsgEvent} <- parseChatMessage connInfo
+ ChatMessage {chatMsgEvent} <- parseChatMessage conn connInfo
case memberCategory m of
GCInviteeMember ->
case chatMsgEvent of
@@ -2884,7 +2884,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
| otherwise -> messageError "x.grp.mem.info: memberId is different from expected"
_ -> messageError "CONF from member must have x.grp.mem.info"
INFO connInfo -> do
- ChatMessage {chatMsgEvent} <- parseChatMessage connInfo
+ ChatMessage {chatMsgEvent} <- parseChatMessage conn connInfo
case chatMsgEvent of
XGrpMemInfo memId _memProfile
| sameMemberId memId m -> do
@@ -3028,7 +3028,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
-- SMP CONF for SndFileConnection happens for direct file protocol
-- when recipient of the file "joins" connection created by the sender
CONF confId _ connInfo -> do
- ChatMessage {chatMsgEvent} <- parseChatMessage connInfo
+ ChatMessage {chatMsgEvent} <- parseChatMessage conn connInfo
case chatMsgEvent of
-- TODO save XFileAcpt message
XFileAcpt name
@@ -3098,7 +3098,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
-- when sender of the file "joins" connection created by the recipient
-- (sender doesn't create connections for all group members)
CONF confId _ connInfo -> do
- ChatMessage {chatMsgEvent} <- parseChatMessage connInfo
+ ChatMessage {chatMsgEvent} <- parseChatMessage conn connInfo
case chatMsgEvent of
XOk -> allowAgentConnectionAsync user conn confId XOk -- [async agent commands] no continuation needed, but command should be asynchronous for stability
_ -> pure ()
@@ -3161,7 +3161,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
processUserContactRequest :: ACommand 'Agent e -> ConnectionEntity -> Connection -> UserContact -> m ()
processUserContactRequest agentMsg connEntity conn UserContact {userContactLinkId} = case agentMsg of
REQ invId _ connInfo -> do
- ChatMessage {chatMsgEvent} <- parseChatMessage connInfo
+ ChatMessage {chatMsgEvent} <- parseChatMessage conn connInfo
case chatMsgEvent of
XContact p xContactId_ -> profileContactRequest invId p xContactId_
XInfo p -> profileContactRequest invId p Nothing
@@ -3959,7 +3959,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
saveConnInfo :: Connection -> ConnInfo -> m ()
saveConnInfo activeConn connInfo = do
- ChatMessage {chatMsgEvent} <- parseChatMessage connInfo
+ ChatMessage {chatMsgEvent} <- parseChatMessage activeConn connInfo
case chatMsgEvent of
XInfo p -> do
ct <- withStore $ \db -> createDirectContact db user activeConn p
@@ -4153,16 +4153,18 @@ sendFileInline_ FileTransferMeta {filePath, chunkSize} sharedMsgId sendMsg =
else sendChunks (chunkNo + 1) rest
chSize = fromIntegral chunkSize
-parseChatMessage :: ChatMonad m => ByteString -> m (ChatMessage 'Json)
-parseChatMessage = parseChatMessage_
+parseChatMessage :: ChatMonad m => Connection -> ByteString -> m (ChatMessage 'Json)
+parseChatMessage conn = parseChatMessage_ conn Nothing
{-# INLINE parseChatMessage #-}
-parseAChatMessage :: ChatMonad m => ByteString -> m AChatMessage
-parseAChatMessage = parseChatMessage_
+parseAChatMessage :: ChatMonad m => Connection -> MsgMeta -> ByteString -> m AChatMessage
+parseAChatMessage conn msgMeta = parseChatMessage_ conn (Just msgMeta)
{-# INLINE parseAChatMessage #-}
-parseChatMessage_ :: (ChatMonad m, StrEncoding s) => ByteString -> m s
-parseChatMessage_ s = liftEither . first (ChatError . CEInvalidChatMessage (safeDecodeUtf8 s)) $ strDecode s
+parseChatMessage_ :: (ChatMonad m, StrEncoding s) => Connection -> Maybe MsgMeta -> ByteString -> m s
+parseChatMessage_ conn msgMeta s = liftEither . first (ChatError . errType) $ strDecode s
+ where
+ errType = CEInvalidChatMessage conn (msgMetaToJson <$> msgMeta) (safeDecodeUtf8 s)
sendFileChunk :: ChatMonad m => User -> SndFileTransfer -> m ()
sendFileChunk user ft@SndFileTransfer {fileId, fileStatus, agentConnId = AgentConnId acId} =
@@ -4376,8 +4378,8 @@ sendPendingGroupMessages user GroupMember {groupMemberId, localDisplayName} conn
_ -> pure ()
saveRcvMSG :: ChatMonad m => Connection -> ConnOrGroupId -> MsgMeta -> MsgBody -> CommandId -> m RcvMessage
-saveRcvMSG Connection {connId} connOrGroupId agentMsgMeta msgBody agentAckCmdId = do
- ACMsg _ ChatMessage {msgId = sharedMsgId_, chatMsgEvent} <- parseAChatMessage msgBody
+saveRcvMSG conn@Connection {connId} connOrGroupId agentMsgMeta msgBody agentAckCmdId = do
+ ACMsg _ ChatMessage {msgId = sharedMsgId_, chatMsgEvent} <- parseAChatMessage conn agentMsgMeta msgBody
let agentMsgId = fst $ recipient agentMsgMeta
newMsg = NewMessage {chatMsgEvent, msgBody}
rcvMsgDelivery = RcvMsgDelivery {connId, agentMsgId, agentMsgMeta, agentAckCmdId}
diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs
index f78ce7e0e6..cd2916c83b 100644
--- a/src/Simplex/Chat/Controller.hs
+++ b/src/Simplex/Chat/Controller.hs
@@ -779,7 +779,7 @@ data ChatErrorType
| CEChatNotStopped
| CEChatStoreChanged
| CEInvalidConnReq
- | CEInvalidChatMessage {messageData :: Text, message :: String}
+ | CEInvalidChatMessage {connection :: Connection, msgMeta :: Maybe MsgMetaJSON, messageData :: Text, message :: String}
| CEContactNotReady {contact :: Contact}
| CEContactDisabled {contact :: Contact}
| CEConnectionDisabled {connection :: Connection}
diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs
index c13318250e..8978772236 100644
--- a/src/Simplex/Chat/View.hs
+++ b/src/Simplex/Chat/View.hs
@@ -1384,7 +1384,12 @@ viewChatError logLevel = \case
CEChatNotStopped -> ["error: chat not stopped"]
CEChatStoreChanged -> ["error: chat store changed, please restart chat"]
CEInvalidConnReq -> viewInvalidConnReq
- CEInvalidChatMessage msg e -> [plain $ "chat message error: " <> e <> " (" <> T.unpack (T.take 120 msg) <> ")"]
+ CEInvalidChatMessage Connection {connId} msgMeta_ msg e ->
+ [ plain $
+ ("chat message error: " <> e <> " (" <> T.unpack (T.take 120 msg) <> ")")
+ <> (", connection id: " <> show connId)
+ <> maybe "" (\MsgMetaJSON {rcvId} -> ", agent msg rcv id: " <> show rcvId) msgMeta_
+ ]
CEContactNotReady c -> [ttyContact' c <> ": not ready"]
CEContactDisabled Contact {localDisplayName = c} -> [ttyContact c <> ": disabled, to enable: " <> highlight ("/enable " <> c) <> ", to delete: " <> highlight ("/d " <> c)]
CEConnectionDisabled Connection {connId, connType} -> [plain $ "connection " <> textEncode connType <> " (" <> tshow connId <> ") is disabled" | logLevel <= CLLWarning]