Merge branch 'master' into master-ios

This commit is contained in:
spaced4ndy
2023-05-17 16:14:18 +04:00
13 changed files with 60 additions and 58 deletions
+4 -4
View File
@@ -345,9 +345,9 @@ func apiUpdateChatItem(type: ChatType, id: Int64, itemId: Int64, msg: MsgContent
throw r
}
func apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, reaction: MsgReaction, add: Bool) async throws -> ChatItem {
let r = await chatSendCmd(.apiChatItemReaction(type: type, id: id, itemId: itemId, reaction: reaction, add: add), bgDelay: msgDelay)
if case let .chatItemReaction(_, reaction, _) = r { return reaction.chatReaction.chatItem }
func apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, add: Bool, reaction: MsgReaction) async throws -> ChatItem {
let r = await chatSendCmd(.apiChatItemReaction(type: type, id: id, itemId: itemId, add: add, reaction: reaction), bgDelay: msgDelay)
if case let .chatItemReaction(_, _, reaction) = r { return reaction.chatReaction.chatItem }
throw r
}
@@ -1285,7 +1285,7 @@ func processReceivedMsg(_ res: ChatResponse) async {
}
case let .chatItemUpdated(user, aChatItem):
chatItemSimpleUpdate(user, aChatItem)
case let .chatItemReaction(user, r, _):
case let .chatItemReaction(user, _, r):
if active(user) {
m.updateChatItem(r.chatInfo, r.chatReaction.chatItem)
}
+6 -6
View File
@@ -526,7 +526,7 @@ struct ChatView: View {
if chat.chatInfo.featureEnabled(.reactions) && (ci.allowAddReaction || r.userReacted) {
v.onTapGesture {
setReaction(r.reaction, add: !r.userReacted)
setReaction(add: !r.userReacted, reaction: r.reaction)
}
} else {
v
@@ -606,27 +606,27 @@ struct ChatView: View {
let rs = MsgReaction.values.compactMap { r in
ci.reactions.contains(where: { $0.userReacted && $0.reaction == r })
? nil
: UIAction(title: r.text) { _ in setReaction(r, add: true) }
: UIAction(title: r.text) { _ in setReaction(add: true, reaction: r) }
}
if rs.count > 0 {
return UIMenu(
title: NSLocalizedString("React...", comment: "chat item menu"),
image: UIImage(systemName: "hand.thumbsup"),
image: UIImage(systemName: "face.smiling"),
children: rs
)
}
return nil
}
private func setReaction(_ r: MsgReaction, add: Bool) {
private func setReaction(add: Bool, reaction: MsgReaction) {
Task {
do {
let chatItem = try await apiChatItemReaction(
type: chat.chatInfo.chatType,
id: chat.chatInfo.apiId,
itemId: ci.id,
reaction: r,
add: add
add: add,
reaction: reaction
)
await MainActor.run {
ChatModel.shared.updateChatItem(chat.chatInfo, chatItem)
@@ -82,7 +82,7 @@ struct GroupPreferencesView: View {
DropdownCustomTimePicker(
selection: $preferences.timedMessages.ttl,
label: "Delete after",
dropdownValues: TimedMessagesPreference.ttlValues,
dropdownValues: TimedMessagesPreference.ttlValues.filter { $0 != nil }, // TODO in 5.2 - allow "off"
customPickerConfirmButtonText: "Select",
customPickerDescription: "Delete after"
)
+4 -4
View File
@@ -41,7 +41,7 @@ public enum ChatCommand {
case apiUpdateChatItem(type: ChatType, id: Int64, itemId: Int64, msg: MsgContent, live: Bool)
case apiDeleteChatItem(type: ChatType, id: Int64, itemId: Int64, mode: CIDeleteMode)
case apiDeleteMemberChatItem(groupId: Int64, groupMemberId: Int64, itemId: Int64)
case apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, reaction: MsgReaction, add: Bool)
case apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, add: Bool, reaction: MsgReaction)
case apiGetNtfToken
case apiRegisterToken(token: DeviceToken, notificationMode: NotificationsMode)
case apiVerifyToken(token: DeviceToken, nonce: String, code: String)
@@ -149,7 +149,7 @@ public enum ChatCommand {
case let .apiUpdateChatItem(type, id, itemId, mc, live): return "/_update item \(ref(type, id)) \(itemId) live=\(onOff(live)) \(mc.cmdString)"
case let .apiDeleteChatItem(type, id, itemId, mode): return "/_delete item \(ref(type, id)) \(itemId) \(mode.rawValue)"
case let .apiDeleteMemberChatItem(groupId, groupMemberId, itemId): return "/_delete member item #\(groupId) \(groupMemberId) \(itemId)"
case let .apiChatItemReaction(type, id, itemId, reaction, add): return "/_reaction \(ref(type, id)) \(itemId) \(reaction.cmdString) \(onOff(add))"
case let .apiChatItemReaction(type, id, itemId, add, reaction): return "/_reaction \(ref(type, id)) \(itemId) \(onOff(add)) \(encodeJSON(reaction))"
case .apiGetNtfToken: return "/_ntf get "
case let .apiRegisterToken(token, notificationMode): return "/_ntf register \(token.cmdString) \(notificationMode.rawValue)"
case let .apiVerifyToken(token, nonce, code): return "/_ntf verify \(token.cmdString) \(nonce) \(code)"
@@ -433,7 +433,7 @@ public enum ChatResponse: Decodable, Error {
case newChatItem(user: User, chatItem: AChatItem)
case chatItemStatusUpdated(user: User, chatItem: AChatItem)
case chatItemUpdated(user: User, chatItem: AChatItem)
case chatItemReaction(user: User, reaction: ACIReaction, added: Bool)
case chatItemReaction(user: User, added: Bool, reaction: ACIReaction)
case chatItemDeleted(user: User, deletedChatItem: AChatItem, toChatItem: AChatItem?, byUser: Bool)
case contactsList(user: User, contacts: [Contact])
// group events
@@ -668,7 +668,7 @@ public enum ChatResponse: Decodable, Error {
case let .newChatItem(u, chatItem): return withUser(u, String(describing: chatItem))
case let .chatItemStatusUpdated(u, chatItem): return withUser(u, String(describing: chatItem))
case let .chatItemUpdated(u, chatItem): return withUser(u, String(describing: chatItem))
case let .chatItemReaction(u, reaction, added): return withUser(u, "added: \(added)\n\(String(describing: reaction))")
case let .chatItemReaction(u, added, reaction): return withUser(u, "added: \(added)\n\(String(describing: reaction))")
case let .chatItemDeleted(u, deletedChatItem, toChatItem, byUser): return withUser(u, "deletedChatItem:\n\(String(describing: deletedChatItem))\ntoChatItem:\n\(String(describing: toChatItem))\nbyUser: \(byUser)")
case let .contactsList(u, contacts): return withUser(u, String(describing: contacts))
case let .groupCreated(u, groupInfo): return withUser(u, String(describing: groupInfo))
+25 -19
View File
@@ -561,7 +561,7 @@ public enum ChatFeature: String, Decodable, Feature {
switch self {
case .timedMessages: return "stopwatch"
case .fullDelete: return "trash.slash"
case .reactions: return "hand.thumbsup"
case .reactions: return "face.smiling"
case .voice: return "mic"
case .calls: return "phone"
}
@@ -571,7 +571,7 @@ public enum ChatFeature: String, Decodable, Feature {
switch self {
case .timedMessages: return "stopwatch.fill"
case .fullDelete: return "trash.slash.fill"
case .reactions: return "hand.thumbsup.fill"
case .reactions: return "face.smiling.fill"
case .voice: return "mic.fill"
case .calls: return "phone.fill"
}
@@ -696,7 +696,7 @@ public enum GroupFeature: String, Decodable, Feature {
case .timedMessages: return "stopwatch"
case .directMessages: return "arrow.left.and.right.circle"
case .fullDelete: return "trash.slash"
case .reactions: return "hand.thumbsup"
case .reactions: return "face.smiling"
case .voice: return "mic"
}
}
@@ -706,7 +706,7 @@ public enum GroupFeature: String, Decodable, Feature {
case .timedMessages: return "stopwatch.fill"
case .directMessages: return "arrow.left.and.right.circle.fill"
case .fullDelete: return "trash.slash.fill"
case .reactions: return "hand.thumbsup.fill"
case .reactions: return "face.smiling.fill"
case .voice: return "mic.fill"
}
}
@@ -2469,25 +2469,17 @@ public struct CIReactionCount: Decodable {
}
public enum MsgReaction: Hashable {
case emoji(MREmojiChar)
case unknown
case emoji(emoji: MREmojiChar)
case unknown(type: String)
public var text: String {
switch self {
case let .emoji(emoji): return emoji.rawValue
case .unknown: return ""
case .unknown: return "?"
}
}
public var cmdString: String {
switch self {
case let .emoji(emoji): return emoji.cmdString
case .unknown: return ""
}
}
public static var values: [MsgReaction] =
MREmojiChar.allCases.map { .emoji($0) }
public static var values: [MsgReaction] = MREmojiChar.allCases.map { .emoji(emoji: $0) }
enum CodingKeys: String, CodingKey {
case type
@@ -2527,12 +2519,26 @@ extension MsgReaction: Decodable {
switch type {
case "emoji":
let emoji = try container.decode(MREmojiChar.self, forKey: CodingKeys.emoji)
self = .emoji(emoji)
self = .emoji(emoji: emoji)
default:
self = .unknown
self = .unknown(type: type)
}
} catch {
self = .unknown
self = .unknown(type: "")
}
}
}
extension MsgReaction: Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case let .emoji(emoji):
try container.encode("emoji", forKey: .type)
try container.encode(emoji, forKey: .emoji)
// TODO use original JSON and type
case let .unknown(type):
try container.encode(type, forKey: .type)
}
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
tag: d693868bc0ce0926f5b890dfced56960c8bcf2ab
tag: 6c6f22051d693e00aaa4c4e6c5b6bff7e9a40b36
source-repository-package
type: git
+1 -1
View File
@@ -1,5 +1,5 @@
{
"https://github.com/simplex-chat/simplexmq.git"."d693868bc0ce0926f5b890dfced56960c8bcf2ab" = "1g9p7b7da90ac3zrr0hwk6bjn3x3zrl0yq314f5w4a54zlg785zx";
"https://github.com/simplex-chat/simplexmq.git"."6c6f22051d693e00aaa4c4e6c5b6bff7e9a40b36" = "0mi4p2s5klm2w6za8xljl3yaiva814phhm5n5q36f04a016i6llm";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/kazu-yamamoto/http2.git"."b5a1b7200cf5bc7044af34ba325284271f6dff25" = "0dqb50j57an64nf4qcf5vcz4xkd1vzvghvf8bk529c1k30r9nfzb";
"https://github.com/simplex-chat/direct-sqlcipher.git"."34309410eb2069b029b8fc1872deb1e0db123294" = "0kwkmhyfsn2lixdlgl15smgr1h5gjk7fky6abzh8rng2h5ymnffd";
+11 -15
View File
@@ -1605,7 +1605,7 @@ processChatCommand = \case
prefs' = setPreference' SCFTimedMessages pref_ $ Just userPreferences
updateContactPrefs user ct prefs'
SetGroupTimedMessages gName ttl_ -> do
let pref = uncurry TimedMessagesGroupPreference $ maybe (FEOff, 86400) (FEOn,) ttl_
let pref = uncurry TimedMessagesGroupPreference $ maybe (FEOff, Just 86400) (\ttl -> (FEOn, Just ttl)) ttl_
updateGroupProfileByName gName $ \p ->
p {groupPreferences = Just . setGroupPreference' SGFTimedMessages pref $ groupPreferences p}
QuitChat -> liftIO exitSuccess
@@ -2993,21 +2993,17 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
-- TODO add debugging output
_ -> pure ()
-- TODO revert to commented function to enable creation of decryption errors chat items
agentMsgDecryptError :: AgentErrorType -> Maybe (MsgDecryptError, Word32)
agentMsgDecryptError _ = Nothing
-- agentMsgDecryptError :: AgentErrorType -> Maybe (MsgDecryptError, Word32)
-- agentMsgDecryptError = \case
-- AGENT (A_CRYPTO RATCHET_HEADER) -> Just (MDERatchetHeader, 1)
-- AGENT (A_CRYPTO (RATCHET_SKIPPED n)) -> Just (MDETooManySkipped, n)
-- -- we are not treating this as decryption error, as in many cases it happens as the result of duplicate or redundant delivery,
-- -- and we don't have a way to differentiate.
-- -- we could store the hashes of past messages in the agent, or delaying message deletion after ACK
-- -- A_DUPLICATE -> Nothing
-- -- earlier messages may be received in case of redundant delivery, and do not necessarily indicate an error
-- -- AGENT (A_CRYPTO (RATCHET_EARLIER n)) -> Nothing
-- _ -> Nothing
agentMsgDecryptError = \case
AGENT (A_CRYPTO RATCHET_HEADER) -> Just (MDERatchetHeader, 1)
AGENT (A_CRYPTO (RATCHET_SKIPPED n)) -> Just (MDETooManySkipped, n)
-- we are not treating this as decryption error, as in many cases it happens as the result of duplicate or redundant delivery,
-- and we don't have a way to differentiate.
-- we could store the hashes of past messages in the agent, or delaying message deletion after ACK
-- A_DUPLICATE -> Nothing
-- earlier messages may be received in case of redundant delivery, and do not necessarily indicate an error
-- AGENT (A_CRYPTO (RATCHET_EARLIER n)) -> Nothing
_ -> Nothing
mdeUpdatedCI :: (MsgDecryptError, Word32) -> CChatItem c -> Maybe (ChatItem c 'MDRcv, CIContent 'MDRcv)
mdeUpdatedCI (mde', n') (CChatItem _ ci@ChatItem {content = CIRcvDecryptionError mde n})
+1 -1
View File
@@ -376,7 +376,7 @@ contactTimedTTL Contact {mergedPreferences = ContactUserPreferences {timedMessag
groupTimedTTL :: GroupInfo -> Maybe (Maybe Int)
groupTimedTTL GroupInfo {fullGroupPreferences = FullGroupPreferences {timedMessages = TimedMessagesGroupPreference {enable, ttl}}}
| enable == FEOn = Just $ Just ttl
| enable == FEOn = Just ttl
| otherwise = Nothing
rcvContactCITimed :: Contact -> Maybe Int -> Maybe CITimed
+3 -3
View File
@@ -704,7 +704,7 @@ emptyChatPrefs = Preferences Nothing Nothing Nothing Nothing Nothing
defaultGroupPrefs :: FullGroupPreferences
defaultGroupPrefs =
FullGroupPreferences
{ timedMessages = TimedMessagesGroupPreference {enable = FEOff, ttl = 86400},
{ timedMessages = TimedMessagesGroupPreference {enable = FEOff, ttl = Just 86400},
directMessages = DirectMessagesGroupPreference {enable = FEOff},
fullDelete = FullDeleteGroupPreference {enable = FEOff},
-- receipts = GroupPreference {enable = FEOff},
@@ -796,7 +796,7 @@ data GroupPreference = GroupPreference
data TimedMessagesGroupPreference = TimedMessagesGroupPreference
{ enable :: GroupFeatureEnabled,
ttl :: Int
ttl :: Maybe Int
}
deriving (Eq, Show, Generic, FromJSON)
@@ -854,7 +854,7 @@ instance HasField "enable" VoiceGroupPreference GroupFeatureEnabled where
instance GroupFeatureI 'GFTimedMessages where
type GroupFeaturePreference 'GFTimedMessages = TimedMessagesGroupPreference
sGroupFeature = SGFTimedMessages
groupPrefParam TimedMessagesGroupPreference {ttl} = Just ttl
groupPrefParam TimedMessagesGroupPreference {ttl} = ttl
instance GroupFeatureI 'GFDirectMessages where
type GroupFeaturePreference 'GFDirectMessages = DirectMessagesGroupPreference
+1 -1
View File
@@ -49,7 +49,7 @@ extra-deps:
# - simplexmq-1.0.0@sha256:34b2004728ae396e3ae449cd090ba7410781e2b3cefc59259915f4ca5daa9ea8,8561
# - ../simplexmq
- github: simplex-chat/simplexmq
commit: d693868bc0ce0926f5b890dfced56960c8bcf2ab
commit: 6c6f22051d693e00aaa4c4e6c5b6bff7e9a40b36
- github: kazu-yamamoto/http2
commit: b5a1b7200cf5bc7044af34ba325284271f6dff25
# - ../direct-sqlcipher
+1 -1
View File
@@ -84,7 +84,7 @@ chatDirectTests = do
it "mark contact verified" testMarkContactVerified
it "mark group member verified" testMarkGroupMemberVerified
describe "message errors" $ do
xit "show message decryption error and update count" testMsgDecryptError
it "show message decryption error and update count" testMsgDecryptError
describe "message reactions" $ do
it "set message reactions" testSetMessageReactions
+1 -1
View File
@@ -53,7 +53,7 @@ chatGroupTests = do
it "group link member role" testGroupLinkMemberRole
it "leaving and deleting the group joined via link should NOT delete previously existing direct contacts" testGroupLinkLeaveDelete
describe "group message errors" $ do
xit "show message decryption error and update count" testGroupMsgDecryptError
it "show message decryption error and update count" testGroupMsgDecryptError
describe "message reactions" $ do
it "set group message reactions" testSetGroupMessageReactions