mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-06-06 19:52:26 +00:00
core, ios: chat tags (#5367)
* types and db * migration module * chat tag * store method proposal * profiles build * update type * update return type * building * working api * update * refactor * attach tags to contact * simplify * attach chat tags to group info * get chat tags with supplied user id * get tags fix * ios: chat tags poc (#5370) * ios: chat tags poc * updates to sheet * temporary display for other option on swipe * sheet height * only show preset when it has matches * changes * worst emoji picker ever * simplify tag casts and collapse * open on create tag if no tags * simple emoji text field * nice emoji picker * dismiss sheets on tag/untag * semibold selection * all preset tag and change collapsed icon on selection * default selected tag (all) * only apply tag filters on empty search * + button when no custom lists * reset selection of tag filter on profile changes * edit tag (broken menu inside swiftui list) * create list to end of list * swipe changes * remove context menu * delete and edit on swipe actions * tap unread filter deselects other filters * remove delete tag if empty * show tag creation sheet when + button pressed * in memory tag edit * color, size * frame * layout * refactor * remove code * add unread to same unit * fraction on long press * nav fixes * in memory list * emoji picker improvements * remove diff * secondary plus * stop flickering on chat tags load * reuse string * fix reset glitches * delete destructive * simplify? * changes * api updates * fix styles on list via swipe * fixed untag * update schema * move user tags loading to get users chat data * move presets to model * update preset tags when chats are updated * style fixes and locate getPresetTags near tags model --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com> * deleted contacts and card should not match contact preset * fix update presets on chat remove * update migration indices * fix migration * not used chat model * disable button on repeated list name or emoji * no chats message for search fix * fix edits and trim * error in footer, not in alert * styling fixes due to wrong place to attach sheet * update library * remove log * idea for dynamic sheet height * max fraction 62% * minor fixes * disable save button when no changes and while saving * disable preset filter if it is no longer shown * remove comments from schema * fix emoji * remove apiChatTagsResponse * always read chat tags * fix --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com> Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
This commit is contained in:
@@ -100,6 +100,34 @@ class ItemsModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
class ChatTagsModel: ObservableObject {
|
||||
static let shared = ChatTagsModel()
|
||||
|
||||
@Published var userTags: [ChatTag] = []
|
||||
@Published var activeFilter: ActiveFilter? = nil
|
||||
@Published var presetTags: [PresetTag] = []
|
||||
}
|
||||
|
||||
func updatePresetTags(_ chats: [Chat]) {
|
||||
var matches: Set<PresetTag> = []
|
||||
for chat in chats {
|
||||
for tag in PresetTag.allCases {
|
||||
if presetTagMatchesChat(tag, chat) {
|
||||
matches.insert(tag)
|
||||
}
|
||||
}
|
||||
if matches.count == PresetTag.allCases.count {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let tm = ChatTagsModel.shared
|
||||
if case let .presetTag(tag) = tm.activeFilter, !matches.contains(tag) {
|
||||
tm.activeFilter = nil
|
||||
}
|
||||
tm.presetTags = Array(matches).sorted(by: { $0.rawValue < $1.rawValue })
|
||||
}
|
||||
|
||||
class NetworkModel: ObservableObject {
|
||||
// map of connections network statuses, key is agent connection id
|
||||
@Published var networkStatuses: Dictionary<String, NetworkStatus> = [:]
|
||||
@@ -342,8 +370,10 @@ final class ChatModel: ObservableObject {
|
||||
private func updateChat(_ cInfo: ChatInfo, addMissing: Bool = true) {
|
||||
if hasChat(cInfo.id) {
|
||||
updateChatInfo(cInfo)
|
||||
updatePresetTags(self.chats)
|
||||
} else if addMissing {
|
||||
addChat(Chat(chatInfo: cInfo, chatItems: []))
|
||||
updatePresetTags(self.chats)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -858,6 +888,7 @@ final class ChatModel: ObservableObject {
|
||||
func removeChat(_ id: String) {
|
||||
withAnimation {
|
||||
chats.removeAll(where: { $0.id == id })
|
||||
updatePresetTags(chats)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -318,6 +318,20 @@ private func apiChatsResponse(_ r: ChatResponse) throws -> [ChatData] {
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiGetChatTags() throws -> [ChatTag] {
|
||||
let userId = try currentUserId("apiGetChatTags")
|
||||
let r = chatSendCmdSync(.apiGetChatTags(userId: userId))
|
||||
if case let .chatTags(_, tags) = r { return tags }
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiGetChatTagsAsync() async throws -> [ChatTag] {
|
||||
let userId = try currentUserId("apiGetChatTags")
|
||||
let r = await chatSendCmd(.apiGetChatTags(userId: userId))
|
||||
if case let .chatTags(_, tags) = r { return tags }
|
||||
throw r
|
||||
}
|
||||
|
||||
let loadItemsPerPage = 50
|
||||
|
||||
func apiGetChat(type: ChatType, id: Int64, search: String = "") async throws -> Chat {
|
||||
@@ -368,6 +382,34 @@ func apiForwardChatItems(toChatType: ChatType, toChatId: Int64, fromChatType: Ch
|
||||
return await processSendMessageCmd(toChatType: toChatType, cmd: cmd)
|
||||
}
|
||||
|
||||
func apiCreateChatTag(tag: ChatTagData) async throws -> [ChatTag] {
|
||||
let r = await chatSendCmd(.apiCreateChatTag(tag: tag))
|
||||
if case let .chatTags(_, userTags) = r {
|
||||
return userTags
|
||||
}
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiSetChatTags(type: ChatType, id: Int64, tagIds: [Int64]) async throws -> ([ChatTag], [Int64]) {
|
||||
let r = await chatSendCmd(.apiSetChatTags(type: type, id: id, tagIds: tagIds))
|
||||
if case let .tagsUpdated(_, userTags, chatTags) = r {
|
||||
return (userTags, chatTags)
|
||||
}
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiDeleteChatTag(tagId: Int64) async throws {
|
||||
try await sendCommandOkResp(.apiDeleteChatTag(tagId: tagId))
|
||||
}
|
||||
|
||||
func apiUpdateChatTag(tagId: Int64, tag: ChatTagData) async throws {
|
||||
try await sendCommandOkResp(.apiUpdateChatTag(tagId: tagId, tagData: tag))
|
||||
}
|
||||
|
||||
func apiReorderChatTags(tagIds: [Int64]) async throws {
|
||||
try await sendCommandOkResp(.apiReorderChatTags(tagIds: tagIds))
|
||||
}
|
||||
|
||||
func apiSendMessages(type: ChatType, id: Int64, live: Bool = false, ttl: Int? = nil, composedMessages: [ComposedMessage]) async -> [ChatItem]? {
|
||||
let cmd: ChatCommand = .apiSendMessages(type: type, id: id, live: live, ttl: ttl, composedMessages: composedMessages)
|
||||
return await processSendMessageCmd(toChatType: type, cmd: cmd)
|
||||
@@ -1746,24 +1788,37 @@ func getUserChatData() throws {
|
||||
m.userAddress = try apiGetUserAddress()
|
||||
m.chatItemTTL = try getChatItemTTL()
|
||||
let chats = try apiGetChats()
|
||||
let tags = try apiGetChatTags()
|
||||
m.updateChats(chats)
|
||||
let tm = ChatTagsModel.shared
|
||||
tm.activeFilter = nil
|
||||
tm.userTags = tags
|
||||
updatePresetTags(m.chats)
|
||||
}
|
||||
|
||||
private func getUserChatDataAsync() async throws {
|
||||
let m = ChatModel.shared
|
||||
let tm = ChatTagsModel.shared
|
||||
if m.currentUser != nil {
|
||||
let userAddress = try await apiGetUserAddressAsync()
|
||||
let chatItemTTL = try await getChatItemTTLAsync()
|
||||
let chats = try await apiGetChatsAsync()
|
||||
let tags = try await apiGetChatTagsAsync()
|
||||
await MainActor.run {
|
||||
m.userAddress = userAddress
|
||||
m.chatItemTTL = chatItemTTL
|
||||
m.updateChats(chats)
|
||||
tm.activeFilter = nil
|
||||
tm.userTags = tags
|
||||
updatePresetTags(m.chats)
|
||||
}
|
||||
} else {
|
||||
await MainActor.run {
|
||||
m.userAddress = nil
|
||||
m.updateChats([])
|
||||
tm.activeFilter = nil
|
||||
tm.userTags = []
|
||||
tm.presetTags = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user