Merge commit '37e752c78f1fc0e83eb20a2063145939112be167'

# Conflicts:
#	submodules/ChatListUI/Sources/Node/ChatListItem.swift
#	submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift
#	submodules/TelegramCore/Sources/ForumChannels.swift
This commit is contained in:
Ali
2022-11-16 01:53:19 +04:00
62 changed files with 1532 additions and 526 deletions

View File

@@ -49,6 +49,7 @@ public final class EmojiStatusComponent: Component {
case text(color: UIColor, string: String)
case animation(content: AnimationContent, size: CGSize, placeholderColor: UIColor, themeColor: UIColor?, loopMode: LoopMode)
case topic(title: String, color: Int32, size: CGSize)
case image(image: UIImage?)
}
public let context: AccountContext
@@ -230,6 +231,8 @@ public final class EmojiStatusComponent: Component {
} else {
iconImage = nil
}
case let .image(image):
iconImage = image
case let .verified(fillColor, foregroundColor, sizeType):
let imageNamePrefix: String
switch sizeType {

View File

@@ -261,23 +261,33 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
}
}
private func updateTopicInfo(topicInfo: EngineMessageHistoryThread.Info) {
func generateTopicColors(_ color: Int32) -> ([UInt32], [UInt32]) {
return ([0x6FB9F0, 0x0261E4], [0x026CB5, 0x064BB7])
}
let topicColors: [Int32: ([UInt32], [UInt32])] = [
0x6FB9F0: ([0x6FB9F0, 0x0261E4], [0x026CB5, 0x064BB7]),
0xFFD67E: ([0xFFD67E, 0xFC8601], [0xDA9400, 0xFA5F00]),
0xCB86DB: ([0xCB86DB, 0x9338AF], [0x812E98, 0x6F2B87]),
0x8EEE98: ([0x8EEE98, 0x02B504], [0x02A01B, 0x009716]),
0xFF93B2: ([0xFF93B2, 0xE23264], [0xFC447A, 0xC80C46]),
0xFB6F5F: ([0xFB6F5F, 0xD72615], [0xDC1908, 0xB61506])
]
let colors = topicColors[topicInfo.iconColor] ?? generateTopicColors(topicInfo.iconColor)
if let image = generateTopicIcon(title: String(topicInfo.title.prefix(1)), backgroundColors: colors.0.map(UIColor.init(rgb:)), strokeColors: colors.1.map(UIColor.init(rgb:)), size: CGSize(width: 32.0, height: 32.0)) {
self.contents = image.cgImage
private func updateTopicInfo(topicInfo: (Int64, EngineMessageHistoryThread.Info)) {
if topicInfo.0 == 1 {
let image = generateImage(CGSize(width: 18.0, height: 18.0), contextGenerator: { size, context in
context.clear(CGRect(origin: .zero, size: size))
if let cgImage = generateTintedImage(image: UIImage(bundleImageName: "Chat List/GeneralTopicIcon"), color: .white)?.cgImage {
context.draw(cgImage, in: CGRect(origin: .zero, size: size))
}
})
self.contents = image?.cgImage
} else {
func generateTopicColors(_ color: Int32) -> ([UInt32], [UInt32]) {
return ([0x6FB9F0, 0x0261E4], [0x026CB5, 0x064BB7])
}
let topicColors: [Int32: ([UInt32], [UInt32])] = [
0x6FB9F0: ([0x6FB9F0, 0x0261E4], [0x026CB5, 0x064BB7]),
0xFFD67E: ([0xFFD67E, 0xFC8601], [0xDA9400, 0xFA5F00]),
0xCB86DB: ([0xCB86DB, 0x9338AF], [0x812E98, 0x6F2B87]),
0x8EEE98: ([0x8EEE98, 0x02B504], [0x02A01B, 0x009716]),
0xFF93B2: ([0xFF93B2, 0xE23264], [0xFC447A, 0xC80C46]),
0xFB6F5F: ([0xFB6F5F, 0xD72615], [0xDC1908, 0xB61506])
]
let colors = topicColors[topicInfo.1.iconColor] ?? generateTopicColors(topicInfo.1.iconColor)
if let image = generateTopicIcon(title: String(topicInfo.1.title.prefix(1)), backgroundColors: colors.0.map(UIColor.init(rgb:)), strokeColors: colors.1.map(UIColor.init(rgb:)), size: CGSize(width: 32.0, height: 32.0)) {
self.contents = image.cgImage
}
}
}

View File

@@ -24,6 +24,7 @@ private final class TitleFieldComponent: Component {
let textColor: UIColor
let accentColor: UIColor
let placeholderColor: UIColor
let isGeneral: Bool
let fileId: Int64
let iconColor: Int32
let text: String
@@ -36,6 +37,7 @@ private final class TitleFieldComponent: Component {
textColor: UIColor,
accentColor: UIColor,
placeholderColor: UIColor,
isGeneral: Bool,
fileId: Int64,
iconColor: Int32,
text: String,
@@ -47,6 +49,7 @@ private final class TitleFieldComponent: Component {
self.textColor = textColor
self.accentColor = accentColor
self.placeholderColor = placeholderColor
self.isGeneral = isGeneral
self.fileId = fileId
self.iconColor = iconColor
self.text = text
@@ -68,6 +71,9 @@ private final class TitleFieldComponent: Component {
if lhs.placeholderColor != rhs.placeholderColor {
return false
}
if lhs.isGeneral != rhs.isGeneral {
return false
}
if lhs.fileId != rhs.fileId {
return false
}
@@ -140,7 +146,10 @@ private final class TitleFieldComponent: Component {
self.state = state
let iconContent: EmojiStatusComponent.Content
if component.fileId == 0 {
if component.isGeneral {
iconContent = .image(image: generateTintedImage(image: UIImage(bundleImageName: "Chat List/GeneralTopicIcon"), color: component.placeholderColor))
self.iconButton.isUserInteractionEnabled = false
} else if component.fileId == 0 {
iconContent = .topic(title: String(component.text.prefix(1)), color: component.iconColor, size: CGSize(width: 32.0, height: 32.0))
self.iconButton.isUserInteractionEnabled = true
} else {
@@ -413,6 +422,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
private var defaultIconFilesDisposable: Disposable?
private var defaultIconFiles = Set<Int64>()
let isGeneral: Bool
var title: String
var fileId: Int64
var iconColor: Int32
@@ -427,11 +437,13 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
switch mode {
case .create:
self.isGeneral = false
self.title = ""
self.fileId = 0
self.iconColor = ForumCreateTopicScreen.iconColors.randomElement() ?? 0x0
case let .edit(info):
case let .edit(threadId, info):
self.isGeneral = threadId == 1
self.title = info.title
self.fileId = info.icon ?? 0
self.iconColor = info.iconColor
@@ -638,6 +650,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
textColor: environment.theme.list.itemPrimaryTextColor,
accentColor: environment.theme.list.itemAccentColor,
placeholderColor: environment.theme.list.disclosureArrowColor,
isGeneral: state.isGeneral,
fileId: state.fileId,
iconColor: state.iconColor,
text: state.title,
@@ -658,124 +671,128 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent {
contentHeight += titleBackground.size.height + sectionSpacing
let iconHeader = iconHeader.update(
component: MultilineTextComponent(
text: .plain(NSAttributedString(
string: environment.strings.CreateTopic_SelectTopicIcon,
font: Font.regular(13.0),
textColor: environment.theme.list.freeTextColor,
paragraphAlignment: .natural)
),
horizontalAlignment: .natural,
maximumNumberOfLines: 1
),
availableSize: CGSize(
width: context.availableSize.width - sideInset * 2.0,
height: CGFloat.greatestFiniteMagnitude
),
transition: .immediate
)
context.add(iconHeader
.position(CGPoint(x: sideInset * 2.0 + iconHeader.size.width / 2.0, y: contentHeight + iconHeader.size.height / 2.0))
)
contentHeight += iconHeader.size.height + headerSpacing
let bottomInset = max(environment.safeInsets.bottom, 12.0)
let iconBackground = iconBackground.update(
component: RoundedRectangle(
color: environment.theme.list.itemBlocksBackgroundColor,
cornerRadius: 10.0
),
availableSize: CGSize(
width: context.availableSize.width - sideInset * 2.0,
height: context.availableSize.height - contentHeight - bottomInset
),
transition: context.transition
)
context.add(iconBackground
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentHeight + iconBackground.size.height / 2.0))
)
if let emojiContent = state.emojiContent {
let availableHeight = context.availableSize.height - contentHeight - max(bottomInset, environment.inputHeight)
if case let .edit(threadId, _) = context.component.mode, threadId == 1 {
let iconSelector = iconSelector.update(
component: TopicIconSelectionComponent(
theme: environment.theme,
strings: environment.strings,
deviceMetrics: environment.deviceMetrics,
emojiContent: emojiContent,
backgroundColor: environment.theme.list.itemBlocksBackgroundColor,
separatorColor: environment.theme.list.blocksBackgroundColor
} else {
let iconHeader = iconHeader.update(
component: MultilineTextComponent(
text: .plain(NSAttributedString(
string: environment.strings.CreateTopic_SelectTopicIcon,
font: Font.regular(13.0),
textColor: environment.theme.list.freeTextColor,
paragraphAlignment: .natural)
),
horizontalAlignment: .natural,
maximumNumberOfLines: 1
),
availableSize: CGSize(
width: context.availableSize.width - sideInset * 2.0,
height: CGFloat.greatestFiniteMagnitude
),
transition: .immediate
)
context.add(iconHeader
.position(CGPoint(x: sideInset * 2.0 + iconHeader.size.width / 2.0, y: contentHeight + iconHeader.size.height / 2.0))
)
contentHeight += iconHeader.size.height + headerSpacing
let bottomInset = max(environment.safeInsets.bottom, 12.0)
let iconBackground = iconBackground.update(
component: RoundedRectangle(
color: environment.theme.list.itemBlocksBackgroundColor,
cornerRadius: 10.0
),
availableSize: CGSize(
width: context.availableSize.width - sideInset * 2.0,
height: context.availableSize.height - contentHeight - bottomInset
),
environment: {},
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: availableHeight),
transition: context.transition
)
context.add(iconSelector
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentHeight + iconSelector.size.height / 2.0))
.cornerRadius(10.0)
.clipsToBounds(true)
context.add(iconBackground
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentHeight + iconBackground.size.height / 2.0))
)
let accountContext = context.component.context
emojiContent.inputInteractionHolder.inputInteraction = EmojiPagerContentComponent.InputInteraction(
performItemAction: { [weak state] groupId, item, _, _, _, _ in
state?.applyItem(groupId: groupId, item: item)
},
deleteBackwards: {
},
openStickerSettings: {
},
openFeatured: {
},
addGroupAction: { groupId, isPremiumLocked in
guard let collectionId = groupId.base as? ItemCollectionId else {
return
}
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedEmojiPacks)
let _ = (accountContext.account.postbox.combinedView(keys: [viewKey])
|> take(1)
|> deliverOnMainQueue).start(next: { views in
guard let view = views.views[viewKey] as? OrderedItemListView else {
if let emojiContent = state.emojiContent {
let availableHeight = context.availableSize.height - contentHeight - max(bottomInset, environment.inputHeight)
let iconSelector = iconSelector.update(
component: TopicIconSelectionComponent(
theme: environment.theme,
strings: environment.strings,
deviceMetrics: environment.deviceMetrics,
emojiContent: emojiContent,
backgroundColor: environment.theme.list.itemBlocksBackgroundColor,
separatorColor: environment.theme.list.blocksBackgroundColor
),
environment: {},
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: availableHeight),
transition: context.transition
)
context.add(iconSelector
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentHeight + iconSelector.size.height / 2.0))
.cornerRadius(10.0)
.clipsToBounds(true)
)
let accountContext = context.component.context
emojiContent.inputInteractionHolder.inputInteraction = EmojiPagerContentComponent.InputInteraction(
performItemAction: { [weak state] groupId, item, _, _, _, _ in
state?.applyItem(groupId: groupId, item: item)
},
deleteBackwards: {
},
openStickerSettings: {
},
openFeatured: {
},
addGroupAction: { groupId, isPremiumLocked in
guard let collectionId = groupId.base as? ItemCollectionId else {
return
}
for featuredEmojiPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
if featuredEmojiPack.info.id == collectionId {
// if let strongSelf = self {
// strongSelf.scheduledEmojiContentAnimationHint = EmojiPagerContentComponent.ContentAnimation(type: .groupInstalled(id: collectionId))
// }
let _ = accountContext.engine.stickers.addStickerPackInteractively(info: featuredEmojiPack.info, items: featuredEmojiPack.topItems).start()
break
let viewKey = PostboxViewKey.orderedItemList(id: Namespaces.OrderedItemList.CloudFeaturedEmojiPacks)
let _ = (accountContext.account.postbox.combinedView(keys: [viewKey])
|> take(1)
|> deliverOnMainQueue).start(next: { views in
guard let view = views.views[viewKey] as? OrderedItemListView else {
return
}
}
})
},
clearGroup: { _ in
},
pushController: { c in
},
presentController: { c in
},
presentGlobalOverlayController: { c in
},
navigationController: {
return nil
},
requestUpdate: { _ in
},
updateSearchQuery: { _, _ in
},
chatPeerId: nil,
peekBehavior: nil,
customLayout: nil,
externalBackground: nil,
externalExpansionView: nil,
useOpaqueTheme: true
)
for featuredEmojiPack in view.items.lazy.map({ $0.contents.get(FeaturedStickerPackItem.self)! }) {
if featuredEmojiPack.info.id == collectionId {
// if let strongSelf = self {
// strongSelf.scheduledEmojiContentAnimationHint = EmojiPagerContentComponent.ContentAnimation(type: .groupInstalled(id: collectionId))
// }
let _ = accountContext.engine.stickers.addStickerPackInteractively(info: featuredEmojiPack.info, items: featuredEmojiPack.topItems).start()
break
}
}
})
},
clearGroup: { _ in
},
pushController: { c in
},
presentController: { c in
},
presentGlobalOverlayController: { c in
},
navigationController: {
return nil
},
requestUpdate: { _ in
},
updateSearchQuery: { _, _ in
},
chatPeerId: nil,
peekBehavior: nil,
customLayout: nil,
externalBackground: nil,
externalExpansionView: nil,
useOpaqueTheme: true
)
}
}
return context.availableSize
@@ -788,7 +805,7 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
public enum Mode: Equatable {
case create
case edit(topic: EngineMessageHistoryThread.Info)
case edit(threadId: Int64, threadInfo: EngineMessageHistoryThread.Info)
}
private let context: AccountContext
@@ -835,9 +852,9 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
case .create:
title = presentationData.strings.CreateTopic_CreateTitle
doneTitle = presentationData.strings.CreateTopic_Create
case let .edit(topic):
case let .edit(_, topic):
title = presentationData.strings.CreateTopic_EditTitle
doneTitle = presentationData.strings.Common_Done
doneTitle = presentationData.strings.Common_Done
self.state = (topic.title, topic.icon)
}