diff --git a/Telegram-Mac/Appearance.swift b/Telegram-Mac/Appearance.swift index 075d921c1..aa3ea7f7d 100644 --- a/Telegram-Mac/Appearance.swift +++ b/Telegram-Mac/Appearance.swift @@ -2107,6 +2107,7 @@ private func generateIcons(from palette: ColorPalette, bubbled: Bool) -> Telegra poll_selected_outgoing: { generatePollIcon(NSImage(named: "Icon_PollSelected")!, backgound: palette.webPreviewActivityBubble_outgoing) }, poll_selected_correct_outgoing: { generatePollIcon(NSImage(named: "Icon_PollSelected")!, backgound: palette.greenBubble_outgoing) }, poll_selected_incorrect_outgoing: { generatePollIcon(NSImage(named: "Icon_PollSelectedIncorrect")!, backgound: palette.redBubble_outgoing) }, + chat_filter_edit: { NSImage(named: "Icon_FilterEdit")!.precomposed(palette.accentIcon) }, chat_filter_add: { NSImage(named: "Icon_FilterAdd")!.precomposed(palette.accentIcon) }, chat_filter_bots: { NSImage(named: "Icon_FilterBots")!.precomposed(palette.accentIcon) }, chat_filter_channels: { NSImage(named: "Icon_FilterChannels")!.precomposed(palette.accentIcon) }, diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterEdit.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_FilterEdit.imageset/Contents.json new file mode 100644 index 000000000..15fc6bb37 --- /dev/null +++ b/Telegram-Mac/Assets.xcassets/Icon_FilterEdit.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_customlist.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_customlist@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterEdit.imageset/ic_customlist.png b/Telegram-Mac/Assets.xcassets/Icon_FilterEdit.imageset/ic_customlist.png new file mode 100644 index 000000000..635068a6a Binary files /dev/null and b/Telegram-Mac/Assets.xcassets/Icon_FilterEdit.imageset/ic_customlist.png differ diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterEdit.imageset/ic_customlist@2x.png b/Telegram-Mac/Assets.xcassets/Icon_FilterEdit.imageset/ic_customlist@2x.png new file mode 100644 index 000000000..430b2793e Binary files /dev/null and b/Telegram-Mac/Assets.xcassets/Icon_FilterEdit.imageset/ic_customlist@2x.png differ diff --git a/Telegram-Mac/ChatListController.swift b/Telegram-Mac/ChatListController.swift index e59dd4c0f..c8fda17f6 100644 --- a/Telegram-Mac/ChatListController.swift +++ b/Telegram-Mac/ChatListController.swift @@ -559,22 +559,24 @@ class ChatListController : PeersListController { })) items.append(.init(L10n.chatListFilterAddChats, handler: { showModal(with: ShareModalController(SelectCallbackObject(context, excludePeerIds: Set(filter.data.includePeers), additionTopItems: nil, limit: 100 - filter.data.includePeers.count, limitReachedText: L10n.chatListFilterIncludeLimitReached, callback: { peerIds in - return combineLatest(updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { state in - var state = state + return updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in + var filters = filters filter.data.includePeers = filter.data.includePeers + peerIds - state.withAddedFilter(filter, onlyReplace: true) - return state - }), replaceRemoteChatListFilters(account: context.account)) |> ignoreValues + if let index = filters.firstIndex(where: {$0.id == filter.id }) { + filters[index] = filter + } + return filters + }) |> ignoreValues })), for: context.window) })) items.append(.init(L10n.chatListFilterDelete, handler: { confirm(for: context.window, header: L10n.chatListFilterConfirmRemoveHeader, information: L10n.chatListFilterConfirmRemoveText, okTitle: L10n.chatListFilterConfirmRemoveOK, successHandler: { _ in - _ = combineLatest(updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { state in - var state = state - state.withRemovedFilter(filter) - return state - }), replaceRemoteChatListFilters(account: context.account)).start() + _ = updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in + var filters = filters + filters.removeAll(where: { $0.id == filter.id }) + return filters + }).start() }) })) @@ -670,11 +672,11 @@ class ChatListController : PeersListController { $0.withUpdatedTabs([]).withUpdatedFilter(nil) } ) case let .filter(filterId): - filterDisposable.set(filterView.start(next: { [weak self] settings in + filterDisposable.set(filterView.start(next: { [weak self] filters in var shouldBack: Bool = false self?.updateFilter { current in var current = current - if let updated = settings.filters.first(where: { $0.id == filterId }) { + if let updated = filters.first(where: { $0.id == filterId }) { current = current.withUpdatedFilter(updated) } else { shouldBack = true @@ -688,18 +690,18 @@ class ChatListController : PeersListController { } })) default: - filterDisposable.set(filterView.start(next: { [weak self] settings in + filterDisposable.set(filterView.start(next: { [weak self] filters in self?.updateFilter( { current in var current = current if let filter = current.filter { - if let updated = settings.filters.first(where: { $0.id == filter.id }) { + if let updated = filters.first(where: { $0.id == filter.id }) { current = current.withUpdatedFilter(updated) } else { current = current.withUpdatedFilter(nil) } } - current = current.withUpdatedTabs(settings.filters) + current = current.withUpdatedTabs(filters) return current } ) })) @@ -936,12 +938,12 @@ class ChatListController : PeersListController { return combineLatest(chatListFilterPreferences(postbox: context.account.postbox), isEnabled) |> take(1) |> deliverOnMainQueue - |> map { [weak self] settings, isEnabled -> [SPopoverItem] in + |> map { [weak self] filters, isEnabled -> [SPopoverItem] in var items:[SPopoverItem] = [] if isEnabled { - items.append(SPopoverItem(settings.filters.isEmpty ? L10n.chatListFilterSetupEmpty : L10n.chatListFilterSetup, { + items.append(SPopoverItem(filters.isEmpty ? L10n.chatListFilterSetupEmpty : L10n.chatListFilterSetup, { context.sharedContext.bindings.rootNavigation().push(ChatListFiltersListController(context: context)) - }, theme.icons.chat_filter_add)) + }, filters.isEmpty ? theme.icons.chat_filter_add : theme.icons.chat_filter_edit)) if self?.filterValue?.filter != nil { items.append(SPopoverItem(L10n.chatListFilterAll, { @@ -951,10 +953,10 @@ class ChatListController : PeersListController { })) } - if !settings.filters.isEmpty { + if !filters.isEmpty { items.append(SPopoverItem(false)) } - for filter in settings.filters { + for filter in filters { let badge = GlobalBadgeNode(context.account, sharedContext: context.sharedContext, view: View(), layoutChanged: { }, getColor: { isSelected in @@ -1220,15 +1222,15 @@ class ChatListController : PeersListController { } else { let prefs = chatListFilterPreferences(postbox: context.account.postbox) |> deliverOnMainQueue |> take(1) - _ = prefs.start(next: { [weak self] settings in + _ = prefs.start(next: { [weak self] filters in if index == 0 { self?.updateFilter { $0.withUpdatedFilter(nil) } self?.scrollup() - } else if settings.filters.count >= index { + } else if filters.count >= index { self?.updateFilter { - $0.withUpdatedFilter(settings.filters[index - 1]) + $0.withUpdatedFilter(filters[index - 1]) } self?.scrollup() } else { diff --git a/Telegram-Mac/ChatListFilterController.swift b/Telegram-Mac/ChatListFilterController.swift index 65747bc32..0f8c16f70 100644 --- a/Telegram-Mac/ChatListFilterController.swift +++ b/Telegram-Mac/ChatListFilterController.swift @@ -52,23 +52,23 @@ private extension ChatListFilter { } } -extension ChatListFiltersState { - mutating func withAddedFilter(_ filter: ChatListFilter, onlyReplace: Bool = false) { - if let index = filters.firstIndex(where: {$0.id == filter.id}) { - filters[index] = filter - } else if !onlyReplace { - filters.append(filter) - } - } - - mutating func withRemovedFilter(_ filter: ChatListFilter) { - filters.removeAll(where: {$0.id == filter.id }) - } - - mutating func withMoveFilter(_ from: Int, _ to: Int) { - filters.insert(filters.remove(at: from), at: to) - } -} +//extension ChatListFiltersState { +// mutating func withAddedFilter(_ filter: ChatListFilter, onlyReplace: Bool = false) { +// if let index = filters.firstIndex(where: {$0.id == filter.id}) { +// filters[index] = filter +// } else if !onlyReplace { +// filters.append(filter) +// } +// } +// +// mutating func withRemovedFilter(_ filter: ChatListFilter) { +// filters.removeAll(where: {$0.id == filter.id }) +// } +// +// mutating func withMoveFilter(_ from: Int, _ to: Int) { +// filters.insert(filters.remove(at: from), at: to) +// } +//} class SelectCallbackObject : ShareObject { private let callback:([PeerId])->Signal @@ -237,8 +237,9 @@ private func chatListFilterEntries(state: ChatListFiltersListState, includePeers entries.append(.desc(sectionId: sectionId, index: index, text: .plain(L10n.chatListFilterIncludeHeader), data: .init(color: theme.colors.listGrayText, detectBold: true, viewType: .textTopItem))) index += 1 + let hasAddInclude = state.filter.data.includePeers.count < maximumPeers || state.filter.data.categories != .all - if state.filter.data.includePeers.count < maximumPeers { + if hasAddInclude { entries.append(.custom(sectionId: sectionId, index: index, value: .none, identifier: _id_add_include, equatable: InputDataEquatable(state), item: { initialSize, stableId in return GeneralInteractedRowItem(initialSize, stableId: stableId, name: L10n.chatListFilterIncludeAddChat, nameStyle: blueActionButton, type: .none, viewType: includePeers.isEmpty ? .singleItem : .firstItem, action: arguments.addInclude, thumb: GeneralThumbAdditional(thumb: theme.icons.chat_filter_add, textInset: 46, thumbInset: 4)) })) @@ -250,7 +251,7 @@ private func chatListFilterEntries(state: ChatListFiltersListState, includePeers var fake:[Int] = [] fake.append(0) for (i, _) in includePeers.enumerated() { - if state.filter.data.includePeers.count < maximumPeers { + if hasAddInclude { fake.append(i + 1) } else { fake.append(i) @@ -271,7 +272,7 @@ private func chatListFilterEntries(state: ChatListFiltersListState, includePeers index += 1 break } else { - let viewType = bestGeneralViewType(fake, for: state.filter.data.includePeers.count < maximumPeers ? i + 1 : i) + let viewType = bestGeneralViewType(fake, for: hasAddInclude ? i + 1 : i) entries.append(.custom(sectionId: sectionId, index: index, value: .none, identifier: _id_include(peer.id), equatable: InputDataEquatable(E(viewType: viewType, peer: PeerEquatable(peer))), item: { initialSize, stableId in return ShortPeerRowItem(initialSize, peer: peer, account: arguments.context.account, stableId: stableId, height: 44, photoSize: NSMakeSize(30, 30), inset: NSEdgeInsets(left: 30, right: 30), viewType: viewType, action: { arguments.openInfo(peer.id) @@ -297,7 +298,10 @@ private func chatListFilterEntries(state: ChatListFiltersListState, includePeers entries.append(.desc(sectionId: sectionId, index: index, text: .plain(L10n.chatListFilterExcludeHeader), data: .init(color: theme.colors.listGrayText, detectBold: true, viewType: .textTopItem))) index += 1 - if state.filter.data.excludePeers.count < maximumPeers { + let hasAddExclude = state.filter.data.excludePeers.count < maximumPeers || !state.filter.data.excludeRead || !state.filter.data.excludeMuted || !state.filter.data.excludeArchived + + + if hasAddExclude { entries.append(.custom(sectionId: sectionId, index: index, value: .none, identifier: _id_add_exclude, equatable: InputDataEquatable(state), item: { initialSize, stableId in return GeneralInteractedRowItem(initialSize, stableId: stableId, name: L10n.chatListFilterExcludeAddChat, nameStyle: blueActionButton, type: .none, viewType: excludePeers.isEmpty ? .singleItem : .firstItem, action: arguments.addExclude, thumb: GeneralThumbAdditional(thumb: theme.icons.chat_filter_add, textInset: 46, thumbInset: 2)) })) @@ -309,7 +313,7 @@ private func chatListFilterEntries(state: ChatListFiltersListState, includePeers fake = [] fake.append(0) for (i, _) in excludePeers.enumerated() { - if state.filter.data.excludePeers.count < maximumPeers { + if hasAddExclude { fake.append(i + 1) } else { fake.append(i) @@ -328,7 +332,7 @@ private func chatListFilterEntries(state: ChatListFiltersListState, includePeers index += 1 break } else { - let viewType = bestGeneralViewType(fake, for: state.filter.data.excludePeers.count < maximumPeers ? i + 1 : i) + let viewType = bestGeneralViewType(fake, for: hasAddExclude ? i + 1 : i) entries.append(.custom(sectionId: sectionId, index: index, value: .none, identifier: _id_exclude(peer.id), equatable: InputDataEquatable(E(viewType: viewType, peer: PeerEquatable(peer))), item: { initialSize, stableId in return ShortPeerRowItem(initialSize, peer: peer, account: arguments.context.account, stableId: stableId, height: 44, photoSize: NSMakeSize(30, 30), inset: NSEdgeInsets(left: 30, right: 30), viewType: viewType, action: { arguments.openInfo(peer.id) @@ -367,12 +371,16 @@ func ChatListFilterController(context: AccountContext, filter: ChatListFilter, i let updateDisposable = MetaDisposable() let save:(Bool)->Void = { replace in - - _ = combineLatest(updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { state in - var state = state - state.withAddedFilter(stateValue.with { $0.filter }, onlyReplace: replace) - return state - }), replaceRemoteChatListFilters(account: context.account)).start() + _ = updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in + let filter = stateValue.with { $0.filter } + var filters = filters + if let index = filters.firstIndex(where: {$0.id == filter.id}) { + filters[index] = filter + } else if !replace { + filters.append(filter) + } + return filters + }).start() } @@ -611,7 +619,7 @@ func ChatListFilterController(context: AccountContext, filter: ChatListFilter, i alert(for: context.window, info: L10n.chatListFilterErrorEmpty) f(.fail(.fields([_id_add_include : .shake]))) } else { - _ = showModalProgress(signal: requestUpdateChatListFilter(account: context.account, id: filter.id, filter: filter), for: context.window).start(error: { error in + _ = showModalProgress(signal: requestUpdateChatListFilter(postbox: context.account.postbox, network: context.account.network, id: filter.id, filter: filter), for: context.window).start(error: { error in switch error { case .generic: alert(for: context.window, info: L10n.unknownError) @@ -634,54 +642,3 @@ func ChatListFilterController(context: AccountContext, filter: ChatListFilter, i - -/* - - - - // entries.append(.desc(sectionId: sectionId, index: index, text: .plain(L10n.chatListFilterCategoriesHeader), data: .init(color: theme.colors.listGrayText, detectBold: true, viewType: .textTopItem))) - // index += 1 - // - // - // - // entries.append(.sectionId(sectionId, type: .normal)) - // sectionId += 1 - // - - // entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_exclude_muted, data: .init(name: L10n.chatListFilterExcludeMuted, color: theme.colors.text, type: .switchable(state.filter.data.excludeMuted), viewType: .firstItem, enabled: true, action: { - // arguments.toggleExcludeMuted(!state.filter.data.excludeMuted) - // }))) - // index += 1 - // - // entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_exclude_read, data: .init(name: L10n.chatListFilterExcludeRead, color: theme.colors.text, type: .switchable(state.filter.data.excludeRead), viewType: .lastItem, enabled: true, action: { - // arguments.toggleExcludeRead(!state.filter.data.excludeRead) - // }))) - // index += 1 - - entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_private_chats, data: .init(name: L10n.chatListFilterPrivateChats, color: theme.colors.text, type: .selectable(state.filter.data.categories.contains(.privateChats)), viewType: .firstItem, enabled: true, action: { - arguments.toggleOption(.privateChats) - }))) - index += 1 - entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_secret_chats, data: .init(name: L10n.chatListFilterSecretChat, color: theme.colors.text, type: .selectable(state.filter.data.categories.contains(.secretChats)), viewType: .innerItem, enabled: true, action: { - arguments.toggleOption(.secretChats) - }))) - index += 1 - entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_public_groups, data: .init(name: L10n.chatListFilterPublicGroups, color: theme.colors.text, type: .selectable(state.filter.data.categories.contains(.publicGroups)), viewType: .innerItem, enabled: true, action: { - arguments.toggleOption(.publicGroups) - }))) - index += 1 - entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_private_groups, data: .init(name: L10n.chatListFilterPrivateGroups, color: theme.colors.text, type: .selectable(state.filter.data.categories.contains(.privateGroups)), viewType: .innerItem, enabled: true, action: { - arguments.toggleOption(.privateGroups) - }))) - index += 1 - entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_channels, data: .init(name: L10n.chatListFilterChannels, color: theme.colors.text, type: .selectable(state.filter.data.categories.contains(.channels)), viewType: .innerItem, enabled: true, action: { - arguments.toggleOption(.channels) - }))) - index += 1 - entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_bots, data: .init(name: L10n.chatListFilterBots, color: theme.colors.text, type: .selectable(state.filter.data.categories.contains(.bots)), viewType: .lastItem, enabled: true, action: { - arguments.toggleOption(.bots) - }))) - index += 1 - - - */ diff --git a/Telegram-Mac/ChatListFilterPreferences.swift b/Telegram-Mac/ChatListFilterPreferences.swift index 50caad3ca..e8d218893 100644 --- a/Telegram-Mac/ChatListFilterPreferences.swift +++ b/Telegram-Mac/ChatListFilterPreferences.swift @@ -55,17 +55,13 @@ extension ChatListFilter { } -func chatListFilterPreferences(postbox: Postbox) -> Signal { - return postbox.preferencesView(keys: [PreferencesKeys.chatListFilters]) |> map { view in - return view.values[PreferencesKeys.chatListFilters] as? ChatListFiltersState ?? ChatListFiltersState.default - } +func chatListFilterPreferences(postbox: Postbox) -> Signal<[ChatListFilter], NoError> { + return updatedChatListFilters(postbox: postbox) } func filtersBadgeCounters(context: AccountContext) -> Signal<[(id: Int32, count: Int32)], NoError> { - return chatListFilterPreferences(postbox: context.account.postbox) |> map { $0 } |> mapToSignal { settings -> Signal<[(id: Int32, count: Int32)], NoError> in - - let filters = settings.filters - + return chatListFilterPreferences(postbox: context.account.postbox) |> map { $0 } |> mapToSignal { filters -> Signal<[(id: Int32, count: Int32)], NoError> in + var signals:[Signal<(id: Int32, count: Int32), NoError>] = [] for current in filters { diff --git a/Telegram-Mac/ChatListFiltersListController.swift b/Telegram-Mac/ChatListFiltersListController.swift index 3264ef6ed..dd4e7eee8 100644 --- a/Telegram-Mac/ChatListFiltersListController.swift +++ b/Telegram-Mac/ChatListFiltersListController.swift @@ -135,30 +135,29 @@ func ChatListFiltersListController(context: AccountContext) -> InputDataControll let arguments = ChatListPresetArguments(context: context, openPreset: { filter, isNew in context.sharedContext.bindings.rootNavigation().push(ChatListFilterController(context: context, filter: filter, isNew: isNew)) }, removePreset: { filter in - _ = combineLatest(updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { state in - var state = state - state.withRemovedFilter(filter) - return state - }), replaceRemoteChatListFilters(account: context.account)).start() + confirm(for: context.window, header: L10n.chatListFilterConfirmRemoveHeader, information: L10n.chatListFilterConfirmRemoveText, okTitle: L10n.chatListFilterConfirmRemoveOK, successHandler: { _ in + _ = updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in + var filters = filters + filters.removeAll(where: { $0.id == filter.id }) + return filters + }).start() + }) + }, addFeatured: { featured in - _ = combineLatest(updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { state in - var state = state - var new = ChatListFilter.new(excludeIds: state.filters.map { $0.id }) + _ = updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in + var filters = filters + var new = ChatListFilter.new(excludeIds: filters.map { $0.id }) new.data = featured.data new.title = featured.title - state.withAddedFilter(new) - return state - }), replaceRemoteChatListFilters(account: context.account)).start() + filters.append(new) + return filters + }).start() }) let chatCountCache = Atomic<[ChatListFilterData: Int]>(value: [:]) - let filtersWithCounts = context.account.postbox.preferencesView(keys: [PreferencesKeys.chatListFilters]) - |> map { preferences -> [ChatListFilter] in - let filtersState = preferences.values[PreferencesKeys.chatListFilters] as? ChatListFiltersState ?? ChatListFiltersState.default - return filtersState.filters - } + let filtersWithCounts = chatListFilterPreferences(postbox: context.account.postbox) |> distinctUntilChanged |> mapToSignal { filters -> Signal<[(ChatListFilter, Int)], NoError> in return context.account.postbox.transaction { transaction -> [(ChatListFilter, Int)] in @@ -238,11 +237,11 @@ func ChatListFiltersListController(context: AccountContext) -> InputDataControll }, resort: { row in }, complete: { from, to in - _ = combineLatest(updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { state in - var state = state - state.withMoveFilter(from - range.location, to - range.location) - return state - }), replaceRemoteChatListFilters(account: context.account)).start() + _ = updateChatListFiltersInteractively(postbox: context.account.postbox, { filters in + var filters = filters + filters.move(at: from - range.location, to: to - range.location) + return filters + }).start() }) } else { diff --git a/Telegram-Mac/ChatListRevealItem.swift b/Telegram-Mac/ChatListRevealItem.swift index 05d5ecd8f..8ee1cff7c 100644 --- a/Telegram-Mac/ChatListRevealItem.swift +++ b/Telegram-Mac/ChatListRevealItem.swift @@ -42,6 +42,7 @@ class ChatListRevealItem: TableStickItem { self.counters = [:] super.init(initialSize) } + func menuItems(for item: ChatListFilter?) -> [ContextMenuItem] { return self._menuItems?(item) ?? [] diff --git a/Telegram-Mac/ChatListRowView.swift b/Telegram-Mac/ChatListRowView.swift index 237eba4c5..ebcbe7a0d 100644 --- a/Telegram-Mac/ChatListRowView.swift +++ b/Telegram-Mac/ChatListRowView.swift @@ -1233,4 +1233,5 @@ class ChatListRowView: TableRowView, ViewDisplayDelegate, RevealTableView { } } + } diff --git a/Telegram-Mac/ChatMessageItem.swift b/Telegram-Mac/ChatMessageItem.swift index e180918d9..79fe04e08 100644 --- a/Telegram-Mac/ChatMessageItem.swift +++ b/Telegram-Mac/ChatMessageItem.swift @@ -548,10 +548,9 @@ class ChatMessageItem: ChatRowItem { return super.isFixedRightPosition } - if textLayout.lines.count > 1, let line = textLayout.lines.last, max(realContentSize.width, maxTitleWidth) < line.frame.width + (rightSize.width + insetBetweenContentAndDate) { + if textLayout.lines.count > 1, let line = textLayout.lines.last, line.frame.width < contentSize.width - (rightSize.width + insetBetweenContentAndDate) { return true } - return super.isForceRightLine } diff --git a/Telegram-Mac/CoreExtension.swift b/Telegram-Mac/CoreExtension.swift index b03e76d28..9ddb50684 100644 --- a/Telegram-Mac/CoreExtension.swift +++ b/Telegram-Mac/CoreExtension.swift @@ -855,6 +855,9 @@ func canEditMessage(_ message:Message, context: AccountContext) -> Bool { if media is TelegramMediaPoll { return false } + if media is TelegramMediaDice { + return false + } } for attr in message.attributes { diff --git a/Telegram-Mac/Info.plist b/Telegram-Mac/Info.plist index 0c32b321d..c78b96b80 100644 --- a/Telegram-Mac/Info.plist +++ b/Telegram-Mac/Info.plist @@ -36,7 +36,7 @@ CFBundleVersion - 192486 + 192525 LSApplicationCategoryType public.app-category.social-networking LSFileQuarantineEnabled diff --git a/Telegram-Mac/PeerUtils.swift b/Telegram-Mac/PeerUtils.swift index f40a94310..e4b021ce0 100644 --- a/Telegram-Mac/PeerUtils.swift +++ b/Telegram-Mac/PeerUtils.swift @@ -81,28 +81,28 @@ final class TelegramFilterCategory : Peer { var icon: EmptyAvatartType? { if category == .contacts { - return .icon(colors: theme.colors.peerColors(5), icon: theme.icons.chat_filter_private_chats_avatar, iconSize: NSMakeSize(20, 20), cornerRadius: nil) + return .icon(colors: theme.colors.peerColors(5), icon: theme.icons.chat_filter_private_chats_avatar, iconSize: NSMakeSize(24, 24), cornerRadius: nil) } if category == .nonContacts { - return .icon(colors: theme.colors.peerColors(1), icon: theme.icons.chat_filter_non_contacts_avatar, iconSize: NSMakeSize(20, 20), cornerRadius: nil) + return .icon(colors: theme.colors.peerColors(1), icon: theme.icons.chat_filter_non_contacts_avatar, iconSize: NSMakeSize(24, 24), cornerRadius: nil) } if category == .groups { - return .icon(colors: theme.colors.peerColors(2), icon: theme.icons.chat_filter_large_groups_avatar, iconSize: NSMakeSize(20, 20), cornerRadius: nil) + return .icon(colors: theme.colors.peerColors(2), icon: theme.icons.chat_filter_large_groups_avatar, iconSize: NSMakeSize(24, 24), cornerRadius: nil) } if category == .channels { - return .icon(colors: theme.colors.peerColors(0), icon: theme.icons.chat_filter_channels_avatar, iconSize: NSMakeSize(20, 20), cornerRadius: nil) + return .icon(colors: theme.colors.peerColors(0), icon: theme.icons.chat_filter_channels_avatar, iconSize: NSMakeSize(24, 24), cornerRadius: nil) } if category == .bots { - return .icon(colors: theme.colors.peerColors(6), icon: theme.icons.chat_filter_bots_avatar, iconSize: NSMakeSize(20, 20), cornerRadius: nil) + return .icon(colors: theme.colors.peerColors(6), icon: theme.icons.chat_filter_bots_avatar, iconSize: NSMakeSize(24, 24), cornerRadius: nil) } if category == .excludeMuted { - return .icon(colors: theme.colors.peerColors(0), icon: theme.icons.chat_filter_muted_avatar, iconSize: NSMakeSize(20, 20), cornerRadius: nil) + return .icon(colors: theme.colors.peerColors(0), icon: theme.icons.chat_filter_muted_avatar, iconSize: NSMakeSize(24, 24), cornerRadius: nil) } if category == .excludeRead { - return .icon(colors: theme.colors.peerColors(3), icon: theme.icons.chat_filter_read_avatar, iconSize: NSMakeSize(20, 20), cornerRadius: nil) + return .icon(colors: theme.colors.peerColors(3), icon: theme.icons.chat_filter_read_avatar, iconSize: NSMakeSize(24, 24), cornerRadius: nil) } if category == .excludeArchived { - return .icon(colors: theme.colors.peerColors(5), icon: theme.icons.chat_filter_archive_avatar, iconSize: NSMakeSize(20, 20), cornerRadius: nil) + return .icon(colors: theme.colors.peerColors(5), icon: theme.icons.chat_filter_archive_avatar, iconSize: NSMakeSize(24, 24), cornerRadius: nil) } return nil } diff --git a/Telegram-Mac/PhoneCallWindowController.swift b/Telegram-Mac/PhoneCallWindowController.swift index e91a17de6..242bf9f93 100644 --- a/Telegram-Mac/PhoneCallWindowController.swift +++ b/Telegram-Mac/PhoneCallWindowController.swift @@ -55,7 +55,6 @@ private class PhoneCallWindowView : View { controls.material = .dark controls.blendingMode = .behindWindow - secureContainerView.wantsLayer = true secureContainerView.background = NSColor(0x000000, 0.75) secureTextView.backgroundColor = .clear diff --git a/Telegram-Mac/ShareModalController.swift b/Telegram-Mac/ShareModalController.swift index 68e767b2c..0a94d7ded 100644 --- a/Telegram-Mac/ShareModalController.swift +++ b/Telegram-Mac/ShareModalController.swift @@ -681,17 +681,12 @@ class ShareModalController: ModalViewController, Notifable, TGModernGrowingDeleg let added = value.selected.subtracting(oldValue.selected) let removed = oldValue.selected.subtracting(value.selected) - for item in added { - let title = item == share.context.account.peerId ? L10n.peerSavedMessages : value.peers[item]?.compactDisplayTitle ?? L10n.peerDeletedUser - genericView.tokenizedView.addToken(token: SearchToken(name: title, uniqueId: item.toInt64()), animated: animated) - } - for item in removed { - genericView.tokenizedView.removeToken(uniqueId: item.toInt64(), animated: animated) + let selected = value.selected.filter { + $0.namespace != ChatListFilterPeerCategories.Namespace } - self.modal?.interactions?.updateEnables(!value.selected.isEmpty) - - if let limit = self.share.limit, value.selected.count > limit { + + if let limit = self.share.limit, selected.count > limit { DispatchQueue.main.async { [unowned self] in self.selectInteractions.update(animated: true, { current in var current = current @@ -704,7 +699,20 @@ class ShareModalController: ModalViewController, Notifable, TGModernGrowingDeleg }) self.share.limitReached() } + return + } + + for item in added { + let title = item == share.context.account.peerId ? L10n.peerSavedMessages : value.peers[item]?.compactDisplayTitle ?? L10n.peerDeletedUser + genericView.tokenizedView.addToken(token: SearchToken(name: title, uniqueId: item.toInt64()), animated: animated) + } + + for item in removed { + genericView.tokenizedView.removeToken(uniqueId: item.toInt64(), animated: animated) } + self.modal?.interactions?.updateEnables(!value.selected.isEmpty) + + } } @@ -1006,11 +1014,18 @@ class ShareModalController: ModalViewController, Notifable, TGModernGrowingDeleg } else { var signal:Signal<(ChatListView,ViewUpdateType), NoError> + let predicate: ChatListFilterPredicate? + if !share.excludePeerIds.isEmpty { + predicate = ChatListFilterPredicate(includePeerIds: Set(), excludePeerIds: share.excludePeerIds, includeAdditionalPeerGroupIds: [], include: { _, _, _, _ in return true }) + } else { + predicate = nil + } + switch(location) { case let .Initial(count, _): - signal = context.account.viewTracker.tailChatListView(groupId: .root, filterPredicate: ChatListFilterPredicate(includePeerIds: Set(), excludePeerIds: share.excludePeerIds, includeAdditionalPeerGroupIds: [], include: { _, _, _, _ in return true }), count: count) + signal = context.account.viewTracker.tailChatListView(groupId: .root, filterPredicate: predicate, count: count) case let .Index(index, _): - signal = context.account.viewTracker.aroundChatListView(groupId: .root, filterPredicate: ChatListFilterPredicate(includePeerIds: Set(), excludePeerIds: share.excludePeerIds, includeAdditionalPeerGroupIds: [], include: { _, _, _, _ in return true }), index: index, count: 30) + signal = context.account.viewTracker.aroundChatListView(groupId: .root, filterPredicate: predicate, index: index, count: 30) } return signal |> deliverOnPrepareQueue |> mapToSignal { value -> Signal<(ChatListView,ViewUpdateType, [PeerId: PeerStatusStringResult], Peer), NoError> in diff --git a/Telegram-Mac/TelegramIconsTheme.swift b/Telegram-Mac/TelegramIconsTheme.swift index d672e2702..0f3937bbc 100644 --- a/Telegram-Mac/TelegramIconsTheme.swift +++ b/Telegram-Mac/TelegramIconsTheme.swift @@ -5763,6 +5763,19 @@ final class TelegramIconsTheme { return image } } + var chat_filter_edit: CGImage { + if let image = cached.with({ $0["chat_filter_edit"] }) { + return image + } else { + let image = _chat_filter_edit() + _ = cached.modify { current in + var current = current + current["chat_filter_edit"] = image + return current + } + return image + } + } var chat_filter_add: CGImage { if let image = cached.with({ $0["chat_filter_add"] }) { return image @@ -6688,6 +6701,7 @@ final class TelegramIconsTheme { private let _poll_selected_outgoing: ()->CGImage private let _poll_selected_correct_outgoing: ()->CGImage private let _poll_selected_incorrect_outgoing: ()->CGImage + private let _chat_filter_edit: ()->CGImage private let _chat_filter_add: ()->CGImage private let _chat_filter_bots: ()->CGImage private let _chat_filter_channels: ()->CGImage @@ -7170,6 +7184,7 @@ final class TelegramIconsTheme { poll_selected_outgoing: @escaping()->CGImage, poll_selected_correct_outgoing: @escaping()->CGImage, poll_selected_incorrect_outgoing: @escaping()->CGImage, + chat_filter_edit: @escaping()->CGImage, chat_filter_add: @escaping()->CGImage, chat_filter_bots: @escaping()->CGImage, chat_filter_channels: @escaping()->CGImage, @@ -7651,6 +7666,7 @@ final class TelegramIconsTheme { self._poll_selected_outgoing = poll_selected_outgoing self._poll_selected_correct_outgoing = poll_selected_correct_outgoing self._poll_selected_incorrect_outgoing = poll_selected_incorrect_outgoing + self._chat_filter_edit = chat_filter_edit self._chat_filter_add = chat_filter_add self._chat_filter_bots = chat_filter_bots self._chat_filter_channels = chat_filter_channels diff --git a/TelegramShare/Info.plist b/TelegramShare/Info.plist index a84b45082..ac25e839c 100644 --- a/TelegramShare/Info.plist +++ b/TelegramShare/Info.plist @@ -21,7 +21,7 @@ CFBundleShortVersionString 5.9.3 CFBundleVersion - 192486 + 192525 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSExtension diff --git a/submodules/TGUIKit/TGUIKit/ScrollableSegmentView.swift b/submodules/TGUIKit/TGUIKit/ScrollableSegmentView.swift index 6e5fba51a..60cc91b06 100644 --- a/submodules/TGUIKit/TGUIKit/ScrollableSegmentView.swift +++ b/submodules/TGUIKit/TGUIKit/ScrollableSegmentView.swift @@ -463,13 +463,20 @@ public class ScrollableSegmentView: View { super.layout() scrollView.frame = bounds borderView.frame = NSMakeRect(0, frame.height - .borderSize, frame.width, .borderSize) - selectorView.frame = selectorFrame for item in self.items { if let view = item.view { view.setFrameSize(NSMakeSize(view.size.width, frame.height)) } } - layoutItems(animated: false) + var x: CGFloat = 0 + for item in self.items { + if let view = item.view { + view.setFrameOrigin(NSMakePoint(x, 0)) + x += view.size.width + } + } + documentView.frame = CGRect(origin: .zero, size: NSMakeSize(x, frame.height)) + selectorView.frame = selectorFrame } public func updateItems(_ items:[ScrollableSegmentItem], animated: Bool, autoscroll: Bool = true) -> Void { diff --git a/submodules/TGUIKit/TGUIKit/TabBarView.swift b/submodules/TGUIKit/TGUIKit/TabBarView.swift index 29eb988a7..896cdec97 100644 --- a/submodules/TGUIKit/TGUIKit/TabBarView.swift +++ b/submodules/TGUIKit/TGUIKit/TabBarView.swift @@ -36,7 +36,9 @@ public class TabBarView: View { super.draw(layer, in: ctx) ctx.setFillColor(presentation.colors.border.cgColor) - ctx.fill(self.bounds) + ctx.fill(NSMakeRect(frame.width - .borderSize, 0, .borderSize, frame.height)) + ctx.fill(NSMakeRect(0, 0, frame.width, .borderSize)) + } func control(for index: Int) -> Control { diff --git a/submodules/TGUIKit/TGUIKit/TextView.swift b/submodules/TGUIKit/TGUIKit/TextView.swift index f2e3b2de2..86d89cd2d 100644 --- a/submodules/TGUIKit/TGUIKit/TextView.swift +++ b/submodules/TGUIKit/TGUIKit/TextView.swift @@ -651,24 +651,45 @@ public final class TextViewLayout : Equatable { calculateLayout(isBigEmoji: isBigEmoji) strokeRects.removeAll() + attributedString.enumerateAttribute(NSAttributedString.Key.link, in: attributedString.range, options: NSAttributedString.EnumerationOptions(rawValue: 0), using: { value, range, stop in if let value = value { - for line in lines { - let lineRange = NSIntersectionRange(range, line.range) - if lineRange.length != 0 { - var leftOffset: CGFloat = 0.0 - if lineRange.location != line.range.location { - leftOffset = floor(CTLineGetOffsetForStringIndex(line.line, lineRange.location, nil)) - } - let rightOffset: CGFloat = ceil(CTLineGetOffsetForStringIndex(line.line, lineRange.location + lineRange.length, nil)) - - - let color: NSColor = attributedString.attribute(NSAttributedString.Key.foregroundColor, at: range.location, effectiveRange: nil) as? NSColor ?? presentation.colors.link - if interactions.isDomainLink(value) && strokeLinks { + if interactions.isDomainLink(value) && strokeLinks { + for line in lines { + let lineRange = NSIntersectionRange(range, line.range) + if lineRange.length != 0 { + var leftOffset: CGFloat = 0.0 + if lineRange.location != line.range.location { + leftOffset = floor(CTLineGetOffsetForStringIndex(line.line, lineRange.location, nil)) + } + let rightOffset: CGFloat = ceil(CTLineGetOffsetForStringIndex(line.line, lineRange.location + lineRange.length, nil)) + + let color: NSColor = attributedString.attribute(NSAttributedString.Key.foregroundColor, at: range.location, effectiveRange: nil) as? NSColor ?? presentation.colors.link let rect = NSMakeRect(line.frame.minX + leftOffset, line.frame.minY + 1, rightOffset - leftOffset, 1.0) strokeRects.append((rect, color)) + + if !disableTooltips, interactions.resolveLink(value) != attributedString.string.nsstring.substring(with: range) { + var leftOffset: CGFloat = 0.0 + if lineRange.location != line.range.location { + leftOffset = floor(CTLineGetOffsetForStringIndex(line.line, lineRange.location, nil)) + } + let rightOffset: CGFloat = ceil(CTLineGetOffsetForStringIndex(line.line, lineRange.location + lineRange.length, nil)) + + toolTipRects.append(NSMakeRect(line.frame.minX + leftOffset, line.frame.minY - line.frame.height, rightOffset - leftOffset, line.frame.height)) + } } - if !disableTooltips, interactions.resolveLink(value) != attributedString.string.nsstring.substring(with: range) { + } + } + if !disableTooltips, interactions.resolveLink(value) != attributedString.string.nsstring.substring(with: range) { + for line in lines { + let lineRange = NSIntersectionRange(range, line.range) + if lineRange.length != 0 { + var leftOffset: CGFloat = 0.0 + if lineRange.location != line.range.location { + leftOffset = floor(CTLineGetOffsetForStringIndex(line.line, lineRange.location, nil)) + } + let rightOffset: CGFloat = ceil(CTLineGetOffsetForStringIndex(line.line, lineRange.location + lineRange.length, nil)) + toolTipRects.append(NSMakeRect(line.frame.minX + leftOffset, line.frame.minY - line.frame.height, rightOffset - leftOffset, line.frame.height)) } } @@ -686,8 +707,6 @@ public final class TextViewLayout : Equatable { if lineRange.location != line.range.location { leftOffset += floor(CTLineGetOffsetForStringIndex(line.line, lineRange.location, nil)) } - - let rect = NSMakeRect(line.frame.minX + leftOffset + 10, line.frame.minY - (size.height - 7) + 2, size.width - 8, size.height - 8) hexColorsRect.append((rect, color, attributedString.attributedSubstring(from: range).string)) } diff --git a/submodules/telegram-ios b/submodules/telegram-ios index 784175912..283e25659 160000 --- a/submodules/telegram-ios +++ b/submodules/telegram-ios @@ -1 +1 @@ -Subproject commit 784175912591aed77fa8ddc21c4b322e6062e96f +Subproject commit 283e25659eecb2178af73a13e2224cdbb2a625ae diff --git a/tools/generate-images.swift b/tools/generate-images.swift index 27e89aa3b..a2b70fd05 100644 --- a/tools/generate-images.swift +++ b/tools/generate-images.swift @@ -458,6 +458,7 @@ func initialize() -> [String] { array.append("poll_selected_correct_outgoing") array.append("poll_selected_incorrect_outgoing") + array.append("chat_filter_edit") array.append("chat_filter_add") array.append("chat_filter_bots") array.append("chat_filter_channels") @@ -487,6 +488,7 @@ func initialize() -> [String] { array.append("chat_filter_non_contacts_avatar") array.append("chat_filter_archive_avatar") + array.append("group_invite_via_link")