mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
Business fixes
This commit is contained in:
parent
c88e69ec29
commit
c69ba2c089
@ -101,6 +101,7 @@ swift_library(
|
|||||||
"//submodules/TelegramUI/Components/Settings/ArchiveInfoScreen",
|
"//submodules/TelegramUI/Components/Settings/ArchiveInfoScreen",
|
||||||
"//submodules/TelegramUI/Components/Settings/NewSessionInfoScreen",
|
"//submodules/TelegramUI/Components/Settings/NewSessionInfoScreen",
|
||||||
"//submodules/TelegramUI/Components/Settings/PeerNameColorItem",
|
"//submodules/TelegramUI/Components/Settings/PeerNameColorItem",
|
||||||
|
"//submodules/Components/MultilineTextComponent",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import ComponentFlow
|
|||||||
import EmojiStatusComponent
|
import EmojiStatusComponent
|
||||||
import AvatarVideoNode
|
import AvatarVideoNode
|
||||||
import AppBundle
|
import AppBundle
|
||||||
|
import MultilineTextComponent
|
||||||
|
|
||||||
public enum ChatListItemContent {
|
public enum ChatListItemContent {
|
||||||
public struct ThreadInfo: Equatable {
|
public struct ThreadInfo: Equatable {
|
||||||
@ -269,7 +270,9 @@ private final class ChatListItemTagListComponent: Component {
|
|||||||
func update(context: AccountContext, title: String, backgroundColor: UIColor, foregroundColor: UIColor) -> CGSize {
|
func update(context: AccountContext, title: String, backgroundColor: UIColor, foregroundColor: UIColor) -> CGSize {
|
||||||
let titleSize = self.title.update(
|
let titleSize = self.title.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(Text(text: title.isEmpty ? " " : title, font: Font.semibold(11.0), color: foregroundColor)),
|
component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(string: title.isEmpty ? " " : title, font: Font.semibold(11.0), textColor: foregroundColor))
|
||||||
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: 100.0, height: 100.0)
|
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||||
)
|
)
|
||||||
@ -800,8 +803,8 @@ private let playIconImage = UIImage(bundleImageName: "Chat List/MiniThumbnailPla
|
|||||||
|
|
||||||
private final class ChatListMediaPreviewNode: ASDisplayNode {
|
private final class ChatListMediaPreviewNode: ASDisplayNode {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let message: EngineMessage
|
let message: EngineMessage
|
||||||
private let media: EngineMedia
|
let media: EngineMedia
|
||||||
|
|
||||||
private let imageNode: TransformImageNode
|
private let imageNode: TransformImageNode
|
||||||
private let playIcon: ASImageNode
|
private let playIcon: ASImageNode
|
||||||
@ -862,11 +865,15 @@ private final class ChatListMediaPreviewNode: ASDisplayNode {
|
|||||||
if file.isInstantVideo {
|
if file.isInstantVideo {
|
||||||
isRound = true
|
isRound = true
|
||||||
}
|
}
|
||||||
|
if file.isSticker || file.isAnimatedSticker {
|
||||||
|
self.playIcon.isHidden = true
|
||||||
|
} else {
|
||||||
if file.isAnimated {
|
if file.isAnimated {
|
||||||
self.playIcon.isHidden = true
|
self.playIcon.isHidden = true
|
||||||
} else {
|
} else {
|
||||||
self.playIcon.isHidden = false
|
self.playIcon.isHidden = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if let mediaDimensions = file.dimensions {
|
if let mediaDimensions = file.dimensions {
|
||||||
dimensions = mediaDimensions.cgSize
|
dimensions = mediaDimensions.cgSize
|
||||||
if !self.requestedImage {
|
if !self.requestedImage {
|
||||||
@ -877,9 +884,18 @@ private final class ChatListMediaPreviewNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let radius: CGFloat
|
||||||
|
if isRound {
|
||||||
|
radius = size.width / 2.0
|
||||||
|
} else if size.width >= 30.0 {
|
||||||
|
radius = 8.0
|
||||||
|
} else {
|
||||||
|
radius = 2.0
|
||||||
|
}
|
||||||
|
|
||||||
let makeLayout = self.imageNode.asyncLayout()
|
let makeLayout = self.imageNode.asyncLayout()
|
||||||
self.imageNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.imageNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
let apply = makeLayout(TransformImageArguments(corners: ImageCorners(radius: isRound ? size.width / 2.0 : 2.0), imageSize: dimensions.aspectFilled(size), boundingSize: size, intrinsicInsets: UIEdgeInsets()))
|
let apply = makeLayout(TransformImageArguments(corners: ImageCorners(radius: radius), imageSize: dimensions.aspectFilled(size), boundingSize: size, intrinsicInsets: UIEdgeInsets()))
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1142,6 +1158,18 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct ContentImageSpec {
|
||||||
|
var message: EngineMessage
|
||||||
|
var media: EngineMedia
|
||||||
|
var size: CGSize
|
||||||
|
|
||||||
|
init(message: EngineMessage, media: EngineMedia, size: CGSize) {
|
||||||
|
self.message = message
|
||||||
|
self.media = media
|
||||||
|
self.size = size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var item: ChatListItem?
|
var item: ChatListItem?
|
||||||
|
|
||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
@ -1156,7 +1184,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
var avatarIconComponent: EmojiStatusComponent?
|
var avatarIconComponent: EmojiStatusComponent?
|
||||||
var avatarVideoNode: AvatarVideoNode?
|
var avatarVideoNode: AvatarVideoNode?
|
||||||
var avatarTapRecognizer: UITapGestureRecognizer?
|
var avatarTapRecognizer: UITapGestureRecognizer?
|
||||||
var avatarMediaNode: AvatarVideoNode?
|
private var avatarMediaNode: ChatListMediaPreviewNode?
|
||||||
|
|
||||||
private var inlineNavigationMarkLayer: SimpleLayer?
|
private var inlineNavigationMarkLayer: SimpleLayer?
|
||||||
|
|
||||||
@ -1197,7 +1225,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
private var cachedDataDisposable = MetaDisposable()
|
private var cachedDataDisposable = MetaDisposable()
|
||||||
|
|
||||||
private var currentTextLeftCutout: CGFloat = 0.0
|
private var currentTextLeftCutout: CGFloat = 0.0
|
||||||
private var currentMediaPreviewSpecs: [(message: EngineMessage, media: EngineMedia, size: CGSize)] = []
|
private var currentMediaPreviewSpecs: [ContentImageSpec] = []
|
||||||
private var mediaPreviewNodes: [EngineMedia.Id: ChatListMediaPreviewNode] = [:]
|
private var mediaPreviewNodes: [EngineMedia.Id: ChatListMediaPreviewNode] = [:]
|
||||||
|
|
||||||
var selectableControlNode: ItemListSelectableControlNode?
|
var selectableControlNode: ItemListSelectableControlNode?
|
||||||
@ -2153,6 +2181,21 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
if !itemTags.isEmpty {
|
if !itemTags.isEmpty {
|
||||||
forumTopicData = nil
|
forumTopicData = nil
|
||||||
topForumTopicItems = []
|
topForumTopicItems = []
|
||||||
|
|
||||||
|
if case let .chat(itemPeer, _, _, _, _, _, _) = contentData {
|
||||||
|
if let messagePeer = itemPeer.chatMainPeer {
|
||||||
|
switch messagePeer {
|
||||||
|
case let .channel(channel):
|
||||||
|
if case .group = channel.info {
|
||||||
|
useInlineAuthorPrefix = true
|
||||||
|
}
|
||||||
|
case .legacyGroup:
|
||||||
|
useInlineAuthorPrefix = true
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if useInlineAuthorPrefix {
|
if useInlineAuthorPrefix {
|
||||||
@ -2175,7 +2218,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
let contentImageSpacing: CGFloat = 2.0
|
let contentImageSpacing: CGFloat = 2.0
|
||||||
let forwardedIconSpacing: CGFloat = 6.0
|
let forwardedIconSpacing: CGFloat = 6.0
|
||||||
let contentImageTrailingSpace: CGFloat = 5.0
|
let contentImageTrailingSpace: CGFloat = 5.0
|
||||||
var contentImageSpecs: [(message: EngineMessage, media: EngineMedia, size: CGSize)] = []
|
|
||||||
|
var contentImageSpecs: [ContentImageSpec] = []
|
||||||
|
var avatarContentImageSpec: ContentImageSpec?
|
||||||
var forumThread: (id: Int64, title: String, iconId: Int64?, iconColor: Int32, isUnread: Bool)?
|
var forumThread: (id: Int64, title: String, iconId: Int64?, iconColor: Int32, isUnread: Bool)?
|
||||||
|
|
||||||
var displayForwardedIcon = false
|
var displayForwardedIcon = false
|
||||||
@ -2494,21 +2539,31 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
if displayMediaPreviews {
|
if displayMediaPreviews {
|
||||||
let contentImageFillSize = CGSize(width: 8.0, height: contentImageSize.height)
|
let contentImageFillSize = CGSize(width: 8.0, height: contentImageSize.height)
|
||||||
_ = contentImageFillSize
|
_ = contentImageFillSize
|
||||||
|
|
||||||
|
var contentImageIsDisplayedAsAvatar = false
|
||||||
|
if case let .peer(peerData) = item.content, let customMessageListData = peerData.customMessageListData, customMessageListData.commandPrefix != nil {
|
||||||
|
contentImageIsDisplayedAsAvatar = true
|
||||||
|
}
|
||||||
|
|
||||||
for message in messages {
|
for message in messages {
|
||||||
if contentImageSpecs.count >= 3 {
|
if contentImageSpecs.count >= 3 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
inner: for media in message.media {
|
inner: for media in message.media {
|
||||||
if let image = media as? TelegramMediaImage {
|
if let image = media as? TelegramMediaImage {
|
||||||
if let _ = largestImageRepresentation(image.representations) {
|
if let _ = largestImageRepresentation(image.representations) {
|
||||||
let fitSize = contentImageSize
|
let fitSize = contentImageSize
|
||||||
contentImageSpecs.append((message, .image(image), fitSize))
|
contentImageSpecs.append(ContentImageSpec(message: message, media: .image(image), size: fitSize))
|
||||||
}
|
}
|
||||||
break inner
|
break inner
|
||||||
} else if let file = media as? TelegramMediaFile {
|
} else if let file = media as? TelegramMediaFile {
|
||||||
if file.isVideo, !file.isVideoSticker, let _ = file.dimensions {
|
if file.isVideo, !file.isVideoSticker, let _ = file.dimensions {
|
||||||
let fitSize = contentImageSize
|
let fitSize = contentImageSize
|
||||||
contentImageSpecs.append((message, .file(file), fitSize))
|
contentImageSpecs.append(ContentImageSpec(message: message, media: .file(file), size: fitSize))
|
||||||
|
} else if contentImageIsDisplayedAsAvatar && (file.isSticker || file.isVideoSticker) {
|
||||||
|
let fitSize = contentImageSize
|
||||||
|
contentImageSpecs.append(ContentImageSpec(message: message, media: .file(file), size: fitSize))
|
||||||
}
|
}
|
||||||
break inner
|
break inner
|
||||||
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
|
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
|
||||||
@ -2516,36 +2571,41 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
if let image = content.image, let type = content.type, imageTypes.contains(type) {
|
if let image = content.image, let type = content.type, imageTypes.contains(type) {
|
||||||
if let _ = largestImageRepresentation(image.representations) {
|
if let _ = largestImageRepresentation(image.representations) {
|
||||||
let fitSize = contentImageSize
|
let fitSize = contentImageSize
|
||||||
contentImageSpecs.append((message, .image(image), fitSize))
|
contentImageSpecs.append(ContentImageSpec(message: message, media: .image(image), size: fitSize))
|
||||||
}
|
}
|
||||||
break inner
|
break inner
|
||||||
} else if let file = content.file {
|
} else if let file = content.file {
|
||||||
if file.isVideo, !file.isInstantVideo, let _ = file.dimensions {
|
if file.isVideo, !file.isInstantVideo, let _ = file.dimensions {
|
||||||
let fitSize = contentImageSize
|
let fitSize = contentImageSize
|
||||||
contentImageSpecs.append((message, .file(file), fitSize))
|
contentImageSpecs.append(ContentImageSpec(message: message, media: .file(file), size: fitSize))
|
||||||
}
|
}
|
||||||
break inner
|
break inner
|
||||||
}
|
}
|
||||||
} else if let action = media as? TelegramMediaAction, case let .suggestedProfilePhoto(image) = action.action, let _ = image {
|
} else if let action = media as? TelegramMediaAction, case let .suggestedProfilePhoto(image) = action.action, let _ = image {
|
||||||
let fitSize = contentImageSize
|
let fitSize = contentImageSize
|
||||||
contentImageSpecs.append((message, .action(action), fitSize))
|
contentImageSpecs.append(ContentImageSpec(message: message, media: .action(action), size: fitSize))
|
||||||
} else if let storyMedia = media as? TelegramMediaStory, let story = message.associatedStories[storyMedia.storyId], !story.data.isEmpty, case let .item(storyItem) = story.get(Stories.StoredItem.self) {
|
} else if let storyMedia = media as? TelegramMediaStory, let story = message.associatedStories[storyMedia.storyId], !story.data.isEmpty, case let .item(storyItem) = story.get(Stories.StoredItem.self) {
|
||||||
if let image = storyItem.media as? TelegramMediaImage {
|
if let image = storyItem.media as? TelegramMediaImage {
|
||||||
if let _ = largestImageRepresentation(image.representations) {
|
if let _ = largestImageRepresentation(image.representations) {
|
||||||
let fitSize = contentImageSize
|
let fitSize = contentImageSize
|
||||||
contentImageSpecs.append((message, .image(image), fitSize))
|
contentImageSpecs.append(ContentImageSpec(message: message, media: .image(image), size: fitSize))
|
||||||
}
|
}
|
||||||
break inner
|
break inner
|
||||||
} else if let file = storyItem.media as? TelegramMediaFile {
|
} else if let file = storyItem.media as? TelegramMediaFile {
|
||||||
if file.isVideo, !file.isInstantVideo, let _ = file.dimensions {
|
if file.isVideo, !file.isInstantVideo, let _ = file.dimensions {
|
||||||
let fitSize = contentImageSize
|
let fitSize = contentImageSize
|
||||||
contentImageSpecs.append((message, .file(file), fitSize))
|
contentImageSpecs.append(ContentImageSpec(message: message, media: .file(file), size: fitSize))
|
||||||
}
|
}
|
||||||
break inner
|
break inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if contentImageIsDisplayedAsAvatar {
|
||||||
|
avatarContentImageSpec = contentImageSpecs.first
|
||||||
|
contentImageSpecs.removeAll()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
attributedText = NSAttributedString(string: messageText, font: textFont, textColor: theme.messageTextColor)
|
attributedText = NSAttributedString(string: messageText, font: textFont, textColor: theme.messageTextColor)
|
||||||
@ -4056,7 +4116,11 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var validMediaIds: [EngineMedia.Id] = []
|
var validMediaIds: [EngineMedia.Id] = []
|
||||||
for (message, media, mediaSize) in contentImageSpecs {
|
for spec in contentImageSpecs {
|
||||||
|
let message = spec.message
|
||||||
|
let media = spec.media
|
||||||
|
let mediaSize = spec.size
|
||||||
|
|
||||||
var mediaId = media.id
|
var mediaId = media.id
|
||||||
if mediaId == nil, case let .action(action) = media, case let .suggestedProfilePhoto(image) = action.action {
|
if mediaId == nil, case let .action(action) = media, case let .suggestedProfilePhoto(image) = action.action {
|
||||||
mediaId = image?.id
|
mediaId = image?.id
|
||||||
@ -4095,6 +4159,36 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
strongSelf.currentMediaPreviewSpecs = contentImageSpecs
|
strongSelf.currentMediaPreviewSpecs = contentImageSpecs
|
||||||
strongSelf.currentTextLeftCutout = textLeftCutout
|
strongSelf.currentTextLeftCutout = textLeftCutout
|
||||||
|
|
||||||
|
if let avatarContentImageSpec {
|
||||||
|
strongSelf.avatarNode.isHidden = true
|
||||||
|
|
||||||
|
if let previous = strongSelf.avatarMediaNode, previous.media != avatarContentImageSpec.media {
|
||||||
|
strongSelf.avatarMediaNode = nil
|
||||||
|
previous.removeFromSupernode()
|
||||||
|
}
|
||||||
|
|
||||||
|
var avatarMediaNodeTransition = transition
|
||||||
|
let avatarMediaNode: ChatListMediaPreviewNode
|
||||||
|
if let current = strongSelf.avatarMediaNode {
|
||||||
|
avatarMediaNode = current
|
||||||
|
} else {
|
||||||
|
avatarMediaNodeTransition = .immediate
|
||||||
|
avatarMediaNode = ChatListMediaPreviewNode(context: item.context, message: avatarContentImageSpec.message, media: avatarContentImageSpec.media)
|
||||||
|
strongSelf.avatarMediaNode = avatarMediaNode
|
||||||
|
strongSelf.contextContainer.addSubnode(avatarMediaNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
avatarMediaNodeTransition.updateFrame(node: avatarMediaNode, frame: avatarFrame)
|
||||||
|
avatarMediaNode.updateLayout(size: avatarFrame.size, synchronousLoads: synchronousLoads)
|
||||||
|
} else {
|
||||||
|
strongSelf.avatarNode.isHidden = false
|
||||||
|
|
||||||
|
if let avatarMediaNode = strongSelf.avatarMediaNode {
|
||||||
|
strongSelf.avatarMediaNode = nil
|
||||||
|
avatarMediaNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !contentDelta.x.isZero || !contentDelta.y.isZero {
|
if !contentDelta.x.isZero || !contentDelta.y.isZero {
|
||||||
let titlePosition = strongSelf.titleNode.position
|
let titlePosition = strongSelf.titleNode.position
|
||||||
transition.animatePosition(node: strongSelf.titleNode, from: CGPoint(x: titlePosition.x - contentDelta.x, y: titlePosition.y - contentDelta.y))
|
transition.animatePosition(node: strongSelf.titleNode, from: CGPoint(x: titlePosition.x - contentDelta.x, y: titlePosition.y - contentDelta.y))
|
||||||
|
|||||||
@ -702,9 +702,29 @@ private struct ContactsListNodeTransition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum ContactListPresentation {
|
public enum ContactListPresentation {
|
||||||
|
public struct Search {
|
||||||
|
public var signal: Signal<String, NoError>
|
||||||
|
public var searchChatList: Bool
|
||||||
|
public var searchDeviceContacts: Bool
|
||||||
|
public var searchGroups: Bool
|
||||||
|
public var searchChannels: Bool
|
||||||
|
public var globalSearch: Bool
|
||||||
|
public var displaySavedMessages: Bool
|
||||||
|
|
||||||
|
public init(signal: Signal<String, NoError>, searchChatList: Bool, searchDeviceContacts: Bool, searchGroups: Bool, searchChannels: Bool, globalSearch: Bool, displaySavedMessages: Bool) {
|
||||||
|
self.signal = signal
|
||||||
|
self.searchChatList = searchChatList
|
||||||
|
self.searchDeviceContacts = searchDeviceContacts
|
||||||
|
self.searchGroups = searchGroups
|
||||||
|
self.searchChannels = searchChannels
|
||||||
|
self.globalSearch = globalSearch
|
||||||
|
self.displaySavedMessages = displaySavedMessages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case orderedByPresence(options: [ContactListAdditionalOption])
|
case orderedByPresence(options: [ContactListAdditionalOption])
|
||||||
case natural(options: [ContactListAdditionalOption], includeChatList: Bool, topPeers: Bool)
|
case natural(options: [ContactListAdditionalOption], includeChatList: Bool, topPeers: Bool)
|
||||||
case search(signal: Signal<String, NoError>, searchChatList: Bool, searchDeviceContacts: Bool, searchGroups: Bool, searchChannels: Bool, globalSearch: Bool)
|
case search(Search)
|
||||||
|
|
||||||
public var sortOrder: ContactsSortOrder? {
|
public var sortOrder: ContactsSortOrder? {
|
||||||
switch self {
|
switch self {
|
||||||
@ -1097,7 +1117,15 @@ public final class ContactListNode: ASDisplayNode {
|
|||||||
displayTopPeers = displayTopPeersValue
|
displayTopPeers = displayTopPeersValue
|
||||||
}
|
}
|
||||||
|
|
||||||
if case let .search(query, searchChatList, searchDeviceContacts, searchGroups, searchChannels, globalSearch) = presentation {
|
if case let .search(search) = presentation {
|
||||||
|
let query = search.signal
|
||||||
|
let searchChatList = search.searchChatList
|
||||||
|
let searchDeviceContacts = search.searchDeviceContacts
|
||||||
|
let searchGroups = search.searchGroups
|
||||||
|
let searchChannels = search.searchChannels
|
||||||
|
let globalSearch = search.globalSearch
|
||||||
|
let displaySavedMessages = search.displaySavedMessages
|
||||||
|
|
||||||
return query
|
return query
|
||||||
|> mapToSignal { query in
|
|> mapToSignal { query in
|
||||||
let foundLocalContacts: Signal<([FoundPeer], [EnginePeer.Id: EnginePeer.Presence]), NoError>
|
let foundLocalContacts: Signal<([FoundPeer], [EnginePeer.Id: EnginePeer.Presence]), NoError>
|
||||||
@ -1108,6 +1136,12 @@ public final class ContactListNode: ASDisplayNode {
|
|||||||
var resultPeers: [FoundPeer] = []
|
var resultPeers: [FoundPeer] = []
|
||||||
|
|
||||||
for peer in peers {
|
for peer in peers {
|
||||||
|
if !displaySavedMessages {
|
||||||
|
if peer.peerId == context.account.peerId {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if searchGroups || searchChannels {
|
if searchGroups || searchChannels {
|
||||||
let mainPeer = peer.chatMainPeer
|
let mainPeer = peer.chatMainPeer
|
||||||
if let _ = mainPeer as? TelegramUser {
|
if let _ = mainPeer as? TelegramUser {
|
||||||
|
|||||||
@ -354,7 +354,7 @@ public final class TelegramBusinessHours: Equatable, Codable {
|
|||||||
}
|
}
|
||||||
if minutes.isEmpty {
|
if minutes.isEmpty {
|
||||||
return .closed
|
return .closed
|
||||||
} else if minutes == IndexSet(integersIn: 0 ..< 24 * 60) {
|
} else if minutes == IndexSet(integersIn: 0 ..< 24 * 60) || minutes == IndexSet(integersIn: 0 ..< (24 * 60 - 1)) {
|
||||||
return .open
|
return .open
|
||||||
} else {
|
} else {
|
||||||
return .intervals(day)
|
return .intervals(day)
|
||||||
|
|||||||
@ -22,6 +22,10 @@ private func dayBusinessHoursText(presentationData: PresentationData, day: Teleg
|
|||||||
businessHoursText += "closed"
|
businessHoursText += "closed"
|
||||||
case let .intervals(intervals):
|
case let .intervals(intervals):
|
||||||
func clipMinutes(_ value: Int) -> Int {
|
func clipMinutes(_ value: Int) -> Int {
|
||||||
|
var value = value
|
||||||
|
if value < 0 {
|
||||||
|
value = 24 * 60 + value
|
||||||
|
}
|
||||||
return value % (24 * 60)
|
return value % (24 * 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,7 +482,13 @@ private final class PeerInfoScreenBusinessHoursItemNode: PeerInfoScreenItemNode
|
|||||||
|
|
||||||
var dayHeights: CGFloat = 0.0
|
var dayHeights: CGFloat = 0.0
|
||||||
|
|
||||||
for i in 0 ..< businessDays.count {
|
for rawI in 0 ..< businessDays.count {
|
||||||
|
if rawI == 0 {
|
||||||
|
//skip current day
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let i = (rawI + currentDayIndex) % businessDays.count
|
||||||
|
|
||||||
dayHeights += daySpacing
|
dayHeights += daySpacing
|
||||||
|
|
||||||
var dayTransition = transition
|
var dayTransition = transition
|
||||||
|
|||||||
@ -41,7 +41,7 @@ private func generateRingImage(color: UIColor, size: CGSize = CGSize(width: 40.0
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func generatePeerNameColorImage(nameColor: PeerNameColors.Colors?, isDark: Bool, isLocked: Bool = false, bounds: CGSize = CGSize(width: 40.0, height: 40.0), size: CGSize = CGSize(width: 40.0, height: 40.0)) -> UIImage? {
|
public func generatePeerNameColorImage(nameColor: PeerNameColors.Colors?, isDark: Bool, isLocked: Bool = false, isEmpty: Bool = false, bounds: CGSize = CGSize(width: 40.0, height: 40.0), size: CGSize = CGSize(width: 40.0, height: 40.0)) -> UIImage? {
|
||||||
return generateImage(bounds, rotatedContext: { contextSize, context in
|
return generateImage(bounds, rotatedContext: { contextSize, context in
|
||||||
let bounds = CGRect(origin: CGPoint(), size: contextSize)
|
let bounds = CGRect(origin: CGPoint(), size: contextSize)
|
||||||
context.clear(bounds)
|
context.clear(bounds)
|
||||||
@ -105,6 +105,25 @@ public func generatePeerNameColorImage(nameColor: PeerNameColors.Colors?, isDark
|
|||||||
context.scaleBy(x: 1.0, y: -1.0)
|
context.scaleBy(x: 1.0, y: -1.0)
|
||||||
context.translateBy(x: -imageFrame.midX, y: -imageFrame.midY)
|
context.translateBy(x: -imageFrame.midX, y: -imageFrame.midY)
|
||||||
|
|
||||||
|
if let cgImage = image.cgImage {
|
||||||
|
context.clip(to: imageFrame, mask: cgImage)
|
||||||
|
context.setFillColor(UIColor.clear.cgColor)
|
||||||
|
context.setBlendMode(.copy)
|
||||||
|
context.fill(imageFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if isEmpty {
|
||||||
|
if let image = UIImage(bundleImageName: "Chat/Message/SideCloseIcon") {
|
||||||
|
let scaleFactor: CGFloat = 1.0
|
||||||
|
let imageSize = CGSize(width: floor(image.size.width * scaleFactor), height: floor(image.size.height * scaleFactor))
|
||||||
|
var imageFrame = CGRect(origin: CGPoint(x: circleBounds.minX + floor((circleBounds.width - imageSize.width) * 0.5), y: circleBounds.minY + floor((circleBounds.height - imageSize.height) * 0.5)), size: imageSize)
|
||||||
|
imageFrame.origin.y += 0.5
|
||||||
|
imageFrame.origin.x += 0.5
|
||||||
|
|
||||||
|
context.translateBy(x: imageFrame.midX, y: imageFrame.midY)
|
||||||
|
context.scaleBy(x: 1.0, y: -1.0)
|
||||||
|
context.translateBy(x: -imageFrame.midX, y: -imageFrame.midY)
|
||||||
|
|
||||||
if let cgImage = image.cgImage {
|
if let cgImage = image.cgImage {
|
||||||
context.clip(to: imageFrame, mask: cgImage)
|
context.clip(to: imageFrame, mask: cgImage)
|
||||||
context.setFillColor(UIColor.clear.cgColor)
|
context.setFillColor(UIColor.clear.cgColor)
|
||||||
@ -212,7 +231,7 @@ private final class PeerNameColorIconItemNode : ASDisplayNode {
|
|||||||
self.item = item
|
self.item = item
|
||||||
|
|
||||||
if updatedAccentColor {
|
if updatedAccentColor {
|
||||||
self.fillNode.image = generatePeerNameColorImage(nameColor: item.colors, isDark: item.isDark, isLocked: item.selected && item.isLocked, bounds: size, size: size)
|
self.fillNode.image = generatePeerNameColorImage(nameColor: item.colors, isDark: item.isDark, isLocked: item.selected && item.isLocked, isEmpty: item.colors == nil, bounds: size, size: size)
|
||||||
self.ringNode.image = generateRingImage(color: item.colors?.main ?? UIColor(rgb: 0x798896), size: size)
|
self.ringNode.image = generateRingImage(color: item.colors?.main ?? UIColor(rgb: 0x798896), size: size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -252,6 +252,8 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
|||||||
var searchGroups = false
|
var searchGroups = false
|
||||||
var searchChannels = false
|
var searchChannels = false
|
||||||
var globalSearch = false
|
var globalSearch = false
|
||||||
|
var displaySavedMessages = true
|
||||||
|
var filters = filters
|
||||||
switch mode {
|
switch mode {
|
||||||
case .groupCreation, .channelCreation:
|
case .groupCreation, .channelCreation:
|
||||||
globalSearch = true
|
globalSearch = true
|
||||||
@ -260,15 +262,31 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
|||||||
searchGroups = searchGroupsValue
|
searchGroups = searchGroupsValue
|
||||||
searchChannels = searchChannelsValue
|
searchChannels = searchChannelsValue
|
||||||
globalSearch = true
|
globalSearch = true
|
||||||
case .chatSelection:
|
case let .chatSelection(chatSelection):
|
||||||
|
if chatSelection.onlyUsers {
|
||||||
|
searchChatList = true
|
||||||
|
searchGroups = false
|
||||||
|
searchChannels = false
|
||||||
|
displaySavedMessages = false
|
||||||
|
filters.append(.excludeSelf)
|
||||||
|
} else {
|
||||||
searchChatList = true
|
searchChatList = true
|
||||||
searchGroups = true
|
searchGroups = true
|
||||||
searchChannels = true
|
searchChannels = true
|
||||||
|
}
|
||||||
globalSearch = false
|
globalSearch = false
|
||||||
case .premiumGifting, .requestedUsersSelection:
|
case .premiumGifting, .requestedUsersSelection:
|
||||||
searchChatList = true
|
searchChatList = true
|
||||||
}
|
}
|
||||||
let searchResultsNode = ContactListNode(context: context, presentation: .single(.search(signal: searchText.get(), searchChatList: searchChatList, searchDeviceContacts: false, searchGroups: searchGroups, searchChannels: searchChannels, globalSearch: globalSearch)), filters: filters, onlyWriteable: strongSelf.onlyWriteable, isPeerEnabled: strongSelf.isPeerEnabled, selectionState: selectionState, isSearch: true)
|
let searchResultsNode = ContactListNode(context: context, presentation: .single(.search(ContactListPresentation.Search(
|
||||||
|
signal: searchText.get(),
|
||||||
|
searchChatList: searchChatList,
|
||||||
|
searchDeviceContacts: false,
|
||||||
|
searchGroups: searchGroups,
|
||||||
|
searchChannels: searchChannels,
|
||||||
|
globalSearch: globalSearch,
|
||||||
|
displaySavedMessages: displaySavedMessages
|
||||||
|
))), filters: filters, onlyWriteable: strongSelf.onlyWriteable, isPeerEnabled: strongSelf.isPeerEnabled, selectionState: selectionState, isSearch: true)
|
||||||
searchResultsNode.openPeer = { peer, _ in
|
searchResultsNode.openPeer = { peer, _ in
|
||||||
self?.tokenListNode.setText("")
|
self?.tokenListNode.setText("")
|
||||||
self?.openPeer?(peer)
|
self?.openPeer?(peer)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user