Folder improvements

This commit is contained in:
Ali 2023-04-05 21:19:31 +04:00
parent a1f78b5833
commit a4ff23c31a
10 changed files with 138 additions and 33 deletions

View File

@ -1404,13 +1404,34 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return .single(false)
}
return context.engine.data.get(
EngineDataList(data.includePeers.peers.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init(id:)))
EngineDataMap(data.includePeers.peers.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))),
EngineDataMap(data.includePeers.peers.map(TelegramEngine.EngineData.Item.Peer.NotificationSettings.init(id:))),
TelegramEngine.EngineData.Item.NotificationSettings.Global()
)
|> map { list -> Bool in
for item in list {
switch item.muteState {
case .default, .unmuted:
|> map { peers, list, globalSettings -> Bool in
for peerId in data.includePeers.peers {
switch list[peerId]?.muteState {
case .unmuted:
return false
case .default:
if let peer = peers[peerId], let peerValue = peer {
let globalValue: EngineGlobalNotificationSettings.CategorySettings
switch peerValue {
case .user, .secretChat:
globalValue = globalSettings.privateChats
case .legacyGroup:
globalValue = globalSettings.groupChats
case let .channel(channel):
if case .broadcast = channel.info {
globalValue = globalSettings.channels
} else {
globalValue = globalSettings.groupChats
}
}
if globalValue.enabled {
return false
}
}
default:
break
}
@ -1539,7 +1560,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
guard let strongSelf = self else {
return
}
strongSelf.push(chatListFilterAddChatsController(context: strongSelf.context, filter: filter, allFilters: filters, limit: limits.maxFolderChatsCount, premiumLimit: premiumLimits.maxFolderChatsCount, isPremium: isPremium))
strongSelf.push(chatListFilterAddChatsController(context: strongSelf.context, filter: filter, allFilters: filters, limit: limits.maxFolderChatsCount, premiumLimit: premiumLimits.maxFolderChatsCount, isPremium: isPremium, presentUndo: { content in
guard let strongSelf = self else {
return
}
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: content, elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
}))
f(.dismissWithoutContent)
})
found = true
@ -1591,18 +1617,24 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return
}
let iconColor: UIColor = .white
let overlayController: UndoOverlayController
if !filterPeersAreMuted {
let iconColor: UIColor = .white
overlayController = UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [
"Middle.Group 1.Fill 1": iconColor,
"Top.Group 1.Fill 1": iconColor,
"Bottom.Group 1.Fill 1": iconColor,
"EXAMPLE.Group 1.Fill 1": iconColor,
"Line.Group 1.Stroke 1": iconColor
overlayController = UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [
"Middle.Group 1.Fill 1": iconColor,
"Top.Group 1.Fill 1": iconColor,
"Bottom.Group 1.Fill 1": iconColor,
"EXAMPLE.Group 1.Fill 1": iconColor,
"Line.Group 1.Stroke 1": iconColor
], title: nil, text: "All chats in **\(title)** are now muted", customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false })
} else {
overlayController = UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_on", scale: 0.056, colors: [:], title: nil, text: "All chats in **\(title)** are now unmuted", customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false })
overlayController = UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [
"Middle.Group 1.Fill 1": iconColor,
"Top.Group 1.Fill 1": iconColor,
"Bottom.Group 1.Fill 1": iconColor,
"EXAMPLE.Group 1.Fill 1": iconColor,
"Line.Group 1.Stroke 1": iconColor
], title: nil, text: "All chats in **\(title)** are now unmuted", customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false })
}
strongSelf.present(overlayController, in: .current)
})

View File

@ -725,11 +725,11 @@ private enum AdditionalExcludeCategoryId: Int {
case archived
}
func chatListFilterAddChatsController(context: AccountContext, filter: ChatListFilter, allFilters: [ChatListFilter], limit: Int32, premiumLimit: Int32, isPremium: Bool) -> ViewController {
return internalChatListFilterAddChatsController(context: context, filter: filter, allFilters: allFilters, applyAutomatically: true, limit: limit, premiumLimit: premiumLimit, isPremium: isPremium, updated: { _ in })
func chatListFilterAddChatsController(context: AccountContext, filter: ChatListFilter, allFilters: [ChatListFilter], limit: Int32, premiumLimit: Int32, isPremium: Bool, presentUndo: @escaping (UndoOverlayContent) -> Void) -> ViewController {
return internalChatListFilterAddChatsController(context: context, filter: filter, allFilters: allFilters, applyAutomatically: true, limit: limit, premiumLimit: premiumLimit, isPremium: isPremium, updated: { _ in }, presentUndo: presentUndo)
}
private func internalChatListFilterAddChatsController(context: AccountContext, filter: ChatListFilter, allFilters: [ChatListFilter], applyAutomatically: Bool, limit: Int32, premiumLimit: Int32, isPremium: Bool, updated: @escaping (ChatListFilter) -> Void) -> ViewController {
private func internalChatListFilterAddChatsController(context: AccountContext, filter: ChatListFilter, allFilters: [ChatListFilter], applyAutomatically: Bool, limit: Int32, premiumLimit: Int32, isPremium: Bool, updated: @escaping (ChatListFilter) -> Void, presentUndo: @escaping (UndoOverlayContent) -> Void) -> ViewController {
guard case let .filter(_, _, _, filterData) = filter else {
return ViewController(navigationBarPresentationData: nil)
}
@ -840,6 +840,39 @@ private func internalChatListFilterAddChatsController(context: AccountContext, f
}
includePeers.sort()
let newPeers = includePeers.filter({ !(filter.data?.includePeers.peers.contains($0) ?? false) })
var removedPeers: [PeerId] = []
if let data = filter.data {
removedPeers = data.includePeers.peers.filter({ !includePeers.contains($0) })
}
if newPeers.count != 0 {
let title: String
let text: String
if newPeers.count == 1 {
title = "Сhat added to folder"
text = "It will not affect chatlist of the links of this folder"
} else {
title = "\(newPeers.count) chats added to folder"
text = "It will not affect chatlist of the links of this folder"
}
presentUndo(.info(title: title, text: text, timeout: nil))
} else if removedPeers.count != 0 {
let title: String
let text: String
if newPeers.count == 1 {
title = "Сhat removed from folder"
text = "It will not affect chatlist of the links of this folder"
} else {
title = "\(newPeers.count) chats removed from folder"
text = "It will not affect chatlist of the links of this folder"
}
presentUndo(.info(title: title, text: text, timeout: nil))
}
var categories: ChatListFilterPeerCategories = []
for id in additionalCategoryIds {
if let index = categoryMapping.firstIndex(where: { $0.1.rawValue == id }) {
@ -1243,6 +1276,9 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi
state.includeCategories = filter.data?.categories ?? []
return state
}
}, presentUndo: { content in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
})
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
})
@ -1527,7 +1563,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset initi
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Common_Delete, textColor: .destructive, icon: { theme in
items.append(.action(ContextMenuActionItem(text: presentationData.strings.ChatList_Context_RemoveFromFolder, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
}, action: { _, f in
f(.dismissWithoutContent)
@ -1884,6 +1920,9 @@ func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, chec
pushController(limitController)
return
case .someUserTooManyChannels:
//TODO:localize
text = "One of the groups in this folder cant be added because one of its admins has too many groups and channels."
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentController(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]))

View File

@ -396,6 +396,7 @@ public class CheckLayer: CALayer {
checkProgress = 0.0
let borderInset = borderWidth / 2.0 + inset
let borderFrame = CGRect(origin: CGPoint(), size: size).insetBy(dx: borderInset, dy: borderInset)
context.setLineDash(phase: -6.4, lengths: [4.0, 4.0])
context.strokeEllipse(in: borderFrame)
} else {
checkProgress = parameters.animationProgress

View File

@ -523,7 +523,7 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
}
if isGroup {
if isPrivate {
text = "You don't have the admin rights to share invite links to this private group chat."
text = "You don't have the admin rights to share invite links to this private group."
} else {
text = "You don't have the admin rights to share invite links to this group chat."
}

View File

@ -753,7 +753,7 @@ private final class LimitSheetContent: CombinedComponent {
)
var titleText = strings.Premium_LimitReached
var buttonAnimationName = "premium_x2"
var buttonAnimationName: String? = "premium_x2"
let iconName: String
var badgeText: String
var string: String
@ -844,6 +844,8 @@ private final class LimitSheetContent: CombinedComponent {
badgeText = "\(limit)"
string = strings.Premium_MaxSharedFolderLinksNoPremiumText("\(limit)").string
}
buttonAnimationName = nil
case .membershipInSharedFolders:
let limit = state.limits.maxSharedFolderJoin
let premiumLimit = state.premiumLimits.maxSharedFolderJoin
@ -863,6 +865,8 @@ private final class LimitSheetContent: CombinedComponent {
badgeText = "\(limit)"
string = strings.Premium_MaxSharedFolderMembershipNoPremiumText("\(limit)").string
}
buttonAnimationName = nil
case .pins:
let limit = state.limits.maxPinnedChatCount
let premiumLimit = state.premiumLimits.maxPinnedChatCount

View File

@ -260,6 +260,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1052885936] = { return Api.ImportedContact.parse_importedContact($0) }
dict[1008755359] = { return Api.InlineBotSwitchPM.parse_inlineBotSwitchPM($0) }
dict[-1250781739] = { return Api.InlineBotWebView.parse_inlineBotWebView($0) }
dict[238759180] = { return Api.InlineQueryPeerType.parse_inlineQueryPeerTypeBotPM($0) }
dict[1664413338] = { return Api.InlineQueryPeerType.parse_inlineQueryPeerTypeBroadcast($0) }
dict[-681130742] = { return Api.InlineQueryPeerType.parse_inlineQueryPeerTypeChat($0) }
dict[1589952067] = { return Api.InlineQueryPeerType.parse_inlineQueryPeerTypeMegagroup($0) }
@ -429,7 +430,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1318425559] = { return Api.KeyboardButton.parse_keyboardButtonRequestPhone($0) }
dict[-1144565411] = { return Api.KeyboardButton.parse_keyboardButtonRequestPoll($0) }
dict[-1598009252] = { return Api.KeyboardButton.parse_keyboardButtonSimpleWebView($0) }
dict[90744648] = { return Api.KeyboardButton.parse_keyboardButtonSwitchInline($0) }
dict[-1816527947] = { return Api.KeyboardButton.parse_keyboardButtonSwitchInline($0) }
dict[629866245] = { return Api.KeyboardButton.parse_keyboardButtonUrl($0) }
dict[280464681] = { return Api.KeyboardButton.parse_keyboardButtonUrlAuth($0) }
dict[814112961] = { return Api.KeyboardButton.parse_keyboardButtonUserProfile($0) }

View File

@ -263,7 +263,7 @@ public extension Api {
case keyboardButtonRequestPhone(text: String)
case keyboardButtonRequestPoll(flags: Int32, quiz: Api.Bool?, text: String)
case keyboardButtonSimpleWebView(text: String, url: String)
case keyboardButtonSwitchInline(flags: Int32, text: String, query: String)
case keyboardButtonSwitchInline(flags: Int32, text: String, query: String, peerTypes: [Api.InlineQueryPeerType]?)
case keyboardButtonUrl(text: String, url: String)
case keyboardButtonUrlAuth(flags: Int32, text: String, fwdText: String?, url: String, buttonId: Int32)
case keyboardButtonUserProfile(text: String, userId: Int64)
@ -349,13 +349,18 @@ public extension Api {
serializeString(text, buffer: buffer, boxed: false)
serializeString(url, buffer: buffer, boxed: false)
break
case .keyboardButtonSwitchInline(let flags, let text, let query):
case .keyboardButtonSwitchInline(let flags, let text, let query, let peerTypes):
if boxed {
buffer.appendInt32(90744648)
buffer.appendInt32(-1816527947)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(text, buffer: buffer, boxed: false)
serializeString(query, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(peerTypes!.count))
for item in peerTypes! {
item.serialize(buffer, true)
}}
break
case .keyboardButtonUrl(let text, let url):
if boxed {
@ -415,8 +420,8 @@ public extension Api {
return ("keyboardButtonRequestPoll", [("flags", flags as Any), ("quiz", quiz as Any), ("text", text as Any)])
case .keyboardButtonSimpleWebView(let text, let url):
return ("keyboardButtonSimpleWebView", [("text", text as Any), ("url", url as Any)])
case .keyboardButtonSwitchInline(let flags, let text, let query):
return ("keyboardButtonSwitchInline", [("flags", flags as Any), ("text", text as Any), ("query", query as Any)])
case .keyboardButtonSwitchInline(let flags, let text, let query, let peerTypes):
return ("keyboardButtonSwitchInline", [("flags", flags as Any), ("text", text as Any), ("query", query as Any), ("peerTypes", peerTypes as Any)])
case .keyboardButtonUrl(let text, let url):
return ("keyboardButtonUrl", [("text", text as Any), ("url", url as Any)])
case .keyboardButtonUrlAuth(let flags, let text, let fwdText, let url, let buttonId):
@ -600,11 +605,16 @@ public extension Api {
_2 = parseString(reader)
var _3: String?
_3 = parseString(reader)
var _4: [Api.InlineQueryPeerType]?
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InlineQueryPeerType.self)
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.KeyboardButton.keyboardButtonSwitchInline(flags: _1!, text: _2!, query: _3!)
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.KeyboardButton.keyboardButtonSwitchInline(flags: _1!, text: _2!, query: _3!, peerTypes: _4)
}
else {
return nil

View File

@ -958,6 +958,7 @@ public extension Api {
}
public extension Api {
enum InlineQueryPeerType: TypeConstructorDescription {
case inlineQueryPeerTypeBotPM
case inlineQueryPeerTypeBroadcast
case inlineQueryPeerTypeChat
case inlineQueryPeerTypeMegagroup
@ -966,6 +967,12 @@ public extension Api {
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .inlineQueryPeerTypeBotPM:
if boxed {
buffer.appendInt32(238759180)
}
break
case .inlineQueryPeerTypeBroadcast:
if boxed {
buffer.appendInt32(1664413338)
@ -1001,6 +1008,8 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .inlineQueryPeerTypeBotPM:
return ("inlineQueryPeerTypeBotPM", [])
case .inlineQueryPeerTypeBroadcast:
return ("inlineQueryPeerTypeBroadcast", [])
case .inlineQueryPeerTypeChat:
@ -1014,6 +1023,9 @@ public extension Api {
}
}
public static func parse_inlineQueryPeerTypeBotPM(_ reader: BufferReader) -> InlineQueryPeerType? {
return Api.InlineQueryPeerType.inlineQueryPeerTypeBotPM
}
public static func parse_inlineQueryPeerTypeBroadcast(_ reader: BufferReader) -> InlineQueryPeerType? {
return Api.InlineQueryPeerType.inlineQueryPeerTypeBroadcast
}

View File

@ -34,6 +34,7 @@ public enum ExportChatFolderError {
case limitExceeded(limit: Int32, premiumLimit: Int32)
case tooManyChannels(limit: Int32, premiumLimit: Int32)
case tooManyChannelsInAccount(limit: Int32, premiumLimit: Int32)
case someUserTooManyChannels
}
public struct ExportedChatFolderLink: Equatable {
@ -96,7 +97,9 @@ func _internal_exportChatFolder(account: Account, filterId: Int32, title: String
}
}
}
} else if error.errorDescription == "USER_CHANNELS_TOO_MUCH" || error.errorDescription == "CHANNELS_TOO_MUCH" {
} else if error.errorDescription == "USER_CHANNELS_TOO_MUCH" {
return .fail(.someUserTooManyChannels)
} else if error.errorDescription == "CHANNELS_TOO_MUCH" {
return account.postbox.transaction { transaction -> (AppConfiguration, Bool) in
return (currentAppConfiguration(transaction: transaction), transaction.getPeer(account.peerId)?.isPremium ?? false)
}
@ -106,9 +109,9 @@ func _internal_exportChatFolder(account: Account, filterId: Int32, title: String
let userPremiumLimits = UserLimitsConfiguration(appConfiguration: appConfiguration, isPremium: true)
if isPremium {
return .fail(.tooManyChannelsInAccount(limit: userPremiumLimits.maxFolderChatsCount, premiumLimit: userPremiumLimits.maxFolderChatsCount))
return .fail(.tooManyChannelsInAccount(limit: userPremiumLimits.maxChannelsCount, premiumLimit: userPremiumLimits.maxChannelsCount))
} else {
return .fail(.tooManyChannelsInAccount(limit: userDefaultLimits.maxFolderChatsCount, premiumLimit: userPremiumLimits.maxFolderChatsCount))
return .fail(.tooManyChannelsInAccount(limit: userDefaultLimits.maxChannelsCount, premiumLimit: userPremiumLimits.maxChannelsCount))
}
}
} else {
@ -512,9 +515,9 @@ func _internal_joinChatFolderLink(account: Account, slug: String, peerIds: [Engi
let userPremiumLimits = UserLimitsConfiguration(appConfiguration: appConfiguration, isPremium: true)
if isPremium {
return .fail(.tooManyChannelsInAccount(limit: userPremiumLimits.maxSharedFolderJoin, premiumLimit: userPremiumLimits.maxSharedFolderJoin))
return .fail(.tooManyChannelsInAccount(limit: userPremiumLimits.maxChannelsCount, premiumLimit: userPremiumLimits.maxChannelsCount))
} else {
return .fail(.tooManyChannelsInAccount(limit: userDefaultLimits.maxSharedFolderJoin, premiumLimit: userPremiumLimits.maxSharedFolderJoin))
return .fail(.tooManyChannelsInAccount(limit: userDefaultLimits.maxChannelsCount, premiumLimit: userPremiumLimits.maxChannelsCount))
}
}
} else {

View File

@ -1469,6 +1469,9 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
controller.dismiss()
return
case .someUserTooManyChannels:
//TODO:localize
text = "One of the groups in this folder cant be added because one of its admins has too many groups and channels."
}
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))