mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-05 12:13:02 +00:00
Merge commit 'c4618f19dba05b1896ea9da7908ae294abb2f666'
This commit is contained in:
commit
348473b4f4
@ -10150,11 +10150,15 @@ Sorry for the inconvenience.";
|
|||||||
"NameColor.UnsavedChanges.Discard" = "Discard";
|
"NameColor.UnsavedChanges.Discard" = "Discard";
|
||||||
"NameColor.UnsavedChanges.Apply" = "Apply";
|
"NameColor.UnsavedChanges.Apply" = "Apply";
|
||||||
|
|
||||||
|
"NameColor.YourColorUpdated" = "Your name color has been updated.";
|
||||||
|
"NameColor.ChannelColorUpdated" = "Channel name color has been updated.";
|
||||||
|
|
||||||
"Chat.ErrorQuoteOutdatedTitle" = "Quote Outdated";
|
"Chat.ErrorQuoteOutdatedTitle" = "Quote Outdated";
|
||||||
"Chat.ErrorQuoteOutdatedText" = "**%@** updated the message you are quoting. Edit your quote to make it up-to-date.";
|
"Chat.ErrorQuoteOutdatedText" = "**%@** updated the message you are quoting. Edit your quote to make it up-to-date.";
|
||||||
"Chat.ErrorQuoteOutdatedActionEdit" = "Edit";
|
"Chat.ErrorQuoteOutdatedActionEdit" = "Edit";
|
||||||
|
|
||||||
"Premium.BoostByGiftDescription" = "Boost your channel by gifting your subscribers Telegram Premium. [Get boosts >]()";
|
"Premium.BoostByGiftDescription" = "Boost your channel by gifting your subscribers Telegram Premium. [Get boosts >]()";
|
||||||
|
"Premium.BoostByGiftDescription2" = "Boost your channel by gifting your subscribers Telegram Premium. [Get boosts >]()";
|
||||||
|
|
||||||
"ChatContextMenu.QuoteSelectionTip" = "Hold on a word, then move cursor to select more| text to quote.";
|
"ChatContextMenu.QuoteSelectionTip" = "Hold on a word, then move cursor to select more| text to quote.";
|
||||||
|
|
||||||
@ -10413,3 +10417,5 @@ Sorry for the inconvenience.";
|
|||||||
"ChannelBoost.BoostAgain" = "Boost Again";
|
"ChannelBoost.BoostAgain" = "Boost Again";
|
||||||
|
|
||||||
"Settings.New" = "NEW";
|
"Settings.New" = "NEW";
|
||||||
|
|
||||||
|
"ChannelBoost.Or" = "or";
|
||||||
|
@ -968,6 +968,7 @@ public enum PremiumIntroSource {
|
|||||||
case storiesExpirationDurations
|
case storiesExpirationDurations
|
||||||
case storiesSuggestedReactions
|
case storiesSuggestedReactions
|
||||||
case channelBoost(EnginePeer.Id)
|
case channelBoost(EnginePeer.Id)
|
||||||
|
case nameColor
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PremiumDemoSubject {
|
public enum PremiumDemoSubject {
|
||||||
|
@ -175,23 +175,42 @@ public func PremiumBoostScreen(
|
|||||||
replaceController?.dismiss(animated: true)
|
replaceController?.dismiss(animated: true)
|
||||||
}
|
}
|
||||||
} else if let boost = occupiedBoosts.first, let occupiedPeer = boost.peer {
|
} else if let boost = occupiedBoosts.first, let occupiedPeer = boost.peer {
|
||||||
let replaceController = replaceBoostConfirmationController(context: context, fromPeers: [occupiedPeer], toPeer: peer, commit: {
|
if let cooldown = boost.cooldownUntil {
|
||||||
currentMyBoostCount += 1
|
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||||
myBoostCount += 1
|
let timeout = cooldown - currentTime
|
||||||
let _ = (context.engine.peers.applyChannelBoost(peerId: peerId, slots: [boost.slot])
|
let valueText = timeIntervalString(strings: presentationData.strings, value: timeout, usage: .afterTime, preferLowerValue: false)
|
||||||
|> deliverOnMainQueue).startStandalone(completed: { [weak controller] in
|
let controller = textAlertController(
|
||||||
let _ = (updatedState.get()
|
sharedContext: context.sharedContext,
|
||||||
|> take(1)
|
updatedPresentationData: nil,
|
||||||
|> deliverOnMainQueue).startStandalone(next: { [weak controller] state in
|
title: presentationData.strings.ChannelBoost_Error_BoostTooOftenTitle,
|
||||||
guard let state else {
|
text: presentationData.strings.ChannelBoost_Error_BoostTooOftenText(valueText).string,
|
||||||
return
|
actions: [
|
||||||
}
|
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})
|
||||||
let (subject, count) = state.displayData(peer: peer, isCurrent: isCurrent, canBoostAgain: canBoostAgain, myBoostCount: myBoostCount, currentMyBoostCount: currentMyBoostCount)
|
],
|
||||||
controller?.updateSubject(subject, count: count)
|
parseMarkdown: true
|
||||||
|
)
|
||||||
|
presentController(controller)
|
||||||
|
} else {
|
||||||
|
let replaceController = replaceBoostConfirmationController(context: context, fromPeers: [occupiedPeer], toPeer: peer, commit: {
|
||||||
|
currentMyBoostCount += 1
|
||||||
|
myBoostCount += 1
|
||||||
|
let _ = (context.engine.peers.applyChannelBoost(peerId: peerId, slots: [boost.slot])
|
||||||
|
|> deliverOnMainQueue).startStandalone(completed: { [weak controller] in
|
||||||
|
let _ = (updatedState.get()
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).startStandalone(next: { [weak controller] state in
|
||||||
|
guard let state else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let (subject, count) = state.displayData(peer: peer, isCurrent: isCurrent, canBoostAgain: canBoostAgain, myBoostCount: myBoostCount, currentMyBoostCount: currentMyBoostCount)
|
||||||
|
controller?.updateSubject(subject, count: count)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
presentController(replaceController)
|
||||||
presentController(replaceController)
|
}
|
||||||
|
} else {
|
||||||
|
dismissImpl?()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if isPremium {
|
if isPremium {
|
||||||
|
@ -233,6 +233,12 @@ public enum PremiumSource: Equatable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case .nameColor:
|
||||||
|
if case .nameColor = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,6 +276,7 @@ public enum PremiumSource: Equatable {
|
|||||||
case storiesExpirationDurations
|
case storiesExpirationDurations
|
||||||
case storiesSuggestedReactions
|
case storiesSuggestedReactions
|
||||||
case channelBoost(EnginePeer.Id)
|
case channelBoost(EnginePeer.Id)
|
||||||
|
case nameColor
|
||||||
|
|
||||||
var identifier: String? {
|
var identifier: String? {
|
||||||
switch self {
|
switch self {
|
||||||
@ -343,6 +350,8 @@ public enum PremiumSource: Equatable {
|
|||||||
return "stories__suggested_reactions"
|
return "stories__suggested_reactions"
|
||||||
case let .channelBoost(peerId):
|
case let .channelBoost(peerId):
|
||||||
return "channel_boost__\(peerId.id._internalGetInt64Value())"
|
return "channel_boost__\(peerId.id._internalGetInt64Value())"
|
||||||
|
case .nameColor:
|
||||||
|
return "name_color"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1541,7 +1541,7 @@ private final class LimitSheetContent: CombinedComponent {
|
|||||||
var additionalContentHeight: CGFloat = 0.0
|
var additionalContentHeight: CGFloat = 0.0
|
||||||
if case let .storiesChannelBoost(_, _, _, _, _, _, link, _, _) = component.subject, link != nil, let openGift = component.openGift {
|
if case let .storiesChannelBoost(_, _, _, _, _, _, link, _, _) = component.subject, link != nil, let openGift = component.openGift {
|
||||||
let orText = orText.update(
|
let orText = orText.update(
|
||||||
component: MultilineTextComponent(text: .plain(NSAttributedString(string: "or", font: Font.regular(15.0), textColor: textColor.withAlphaComponent(0.8), paragraphAlignment: .center))),
|
component: MultilineTextComponent(text: .plain(NSAttributedString(string: environment.strings.ChannelBoost_Or, font: Font.regular(15.0), textColor: textColor.withAlphaComponent(0.8), paragraphAlignment: .center))),
|
||||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: context.availableSize.height),
|
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: context.availableSize.height),
|
||||||
transition: .immediate
|
transition: .immediate
|
||||||
)
|
)
|
||||||
@ -1571,7 +1571,7 @@ private final class LimitSheetContent: CombinedComponent {
|
|||||||
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: linkColor)!, environment.theme)
|
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: linkColor)!, environment.theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
let giftString = environment.strings.Premium_BoostByGiftDescription
|
let giftString = environment.strings.Premium_BoostByGiftDescription2
|
||||||
let giftAttributedString = parseMarkdownIntoAttributedString(giftString, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString
|
let giftAttributedString = parseMarkdownIntoAttributedString(giftString, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString
|
||||||
|
|
||||||
if let range = giftAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 {
|
if let range = giftAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 {
|
||||||
|
@ -289,7 +289,7 @@ private func themePickerControllerEntries(presentationData: PresentationData, pr
|
|||||||
entries.append(.themes(presentationData.theme, presentationData.strings, chatThemes, themeReference, nightMode, animatedEmojiStickers, presentationThemeSettings.themeSpecificAccentColors, presentationThemeSettings.themeSpecificChatWallpapers))
|
entries.append(.themes(presentationData.theme, presentationData.strings, chatThemes, themeReference, nightMode, animatedEmojiStickers, presentationThemeSettings.themeSpecificAccentColors, presentationThemeSettings.themeSpecificChatWallpapers))
|
||||||
|
|
||||||
entries.append(.customHeader(presentationData.theme, presentationData.strings.Themes_BuildOwn.uppercased()))
|
entries.append(.customHeader(presentationData.theme, presentationData.strings.Themes_BuildOwn.uppercased()))
|
||||||
entries.append(.chatPreview(presentationData.theme, presentationData.chatWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (presentationData.strings.Appearance_PreviewReplyAuthor, presentationData.strings.Appearance_PreviewReplyText), text: presentationData.strings.Appearance_PreviewIncomingText), ChatPreviewMessageItem(outgoing: true, reply: nil, text: presentationData.strings.Appearance_PreviewOutgoingText)]))
|
entries.append(.chatPreview(presentationData.theme, presentationData.chatWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (presentationData.strings.Appearance_PreviewReplyAuthor, presentationData.strings.Appearance_PreviewReplyText), text: presentationData.strings.Appearance_PreviewIncomingText, nameColor: .blue, backgroundEmojiId: nil), ChatPreviewMessageItem(outgoing: true, reply: nil, text: presentationData.strings.Appearance_PreviewOutgoingText, nameColor: .blue, backgroundEmojiId: nil)]))
|
||||||
|
|
||||||
let generalThemes: [PresentationThemeReference] = availableThemes.filter { reference in
|
let generalThemes: [PresentationThemeReference] = availableThemes.filter { reference in
|
||||||
if case let .cloud(theme) = reference {
|
if case let .cloud(theme) = reference {
|
||||||
|
@ -283,7 +283,7 @@ private func editThemeControllerEntries(presentationData: PresentationData, stat
|
|||||||
entries.append(.slugInfo(presentationData.theme, infoText))
|
entries.append(.slugInfo(presentationData.theme, infoText))
|
||||||
|
|
||||||
entries.append(.chatPreviewHeader(presentationData.theme, presentationData.strings.EditTheme_Preview.uppercased()))
|
entries.append(.chatPreviewHeader(presentationData.theme, presentationData.strings.EditTheme_Preview.uppercased()))
|
||||||
entries.append(.chatPreview(presentationData.theme, previewTheme, previewTheme.chat.defaultWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (previewIncomingReplyName, previewIncomingReplyText), text: previewIncomingText), ChatPreviewMessageItem(outgoing: true, reply: nil, text: previewOutgoingText)]))
|
entries.append(.chatPreview(presentationData.theme, previewTheme, previewTheme.chat.defaultWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (previewIncomingReplyName, previewIncomingReplyText), text: previewIncomingText, nameColor: .blue, backgroundEmojiId: nil), ChatPreviewMessageItem(outgoing: true, reply: nil, text: previewOutgoingText, nameColor: .blue, backgroundEmojiId: nil)]))
|
||||||
|
|
||||||
entries.append(.changeColors(presentationData.theme, presentationData.strings.EditTheme_ChangeColors))
|
entries.append(.changeColors(presentationData.theme, presentationData.strings.EditTheme_ChangeColors))
|
||||||
if hasSettings {
|
if hasSettings {
|
||||||
|
@ -25,12 +25,20 @@ struct ChatPreviewMessageItem: Equatable {
|
|||||||
if lhs.text != rhs.text {
|
if lhs.text != rhs.text {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.nameColor != rhs.nameColor {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.backgroundEmojiId != rhs.backgroundEmojiId {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
let outgoing: Bool
|
let outgoing: Bool
|
||||||
let reply: (String, String)?
|
let reply: (String, String)?
|
||||||
let text: String
|
let text: String
|
||||||
|
let nameColor: PeerNameColor
|
||||||
|
let backgroundEmojiId: Int64?
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThemeSettingsChatPreviewItem: ListViewItem, ItemListItem {
|
class ThemeSettingsChatPreviewItem: ListViewItem, ItemListItem {
|
||||||
@ -155,7 +163,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3)
|
let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3)
|
||||||
if let (author, text) = messageItem.reply {
|
if let (author, text) = messageItem.reply {
|
||||||
peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: author, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil)
|
peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: author, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: messageItem.nameColor, backgroundEmojiId: messageItem.backgroundEmojiId)
|
||||||
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,16 +375,26 @@ private func themeSettingsControllerEntries(presentationData: PresentationData,
|
|||||||
let strings = presentationData.strings
|
let strings = presentationData.strings
|
||||||
let title = presentationData.autoNightModeTriggered ? strings.Appearance_ColorThemeNight.uppercased() : strings.Appearance_ColorTheme.uppercased()
|
let title = presentationData.autoNightModeTriggered ? strings.Appearance_ColorThemeNight.uppercased() : strings.Appearance_ColorTheme.uppercased()
|
||||||
entries.append(.themeListHeader(presentationData.theme, title))
|
entries.append(.themeListHeader(presentationData.theme, title))
|
||||||
entries.append(.chatPreview(presentationData.theme, presentationData.chatWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (presentationData.strings.Appearance_PreviewReplyAuthor, presentationData.strings.Appearance_PreviewReplyText), text: presentationData.strings.Appearance_PreviewIncomingText), ChatPreviewMessageItem(outgoing: true, reply: nil, text: presentationData.strings.Appearance_PreviewOutgoingText)]))
|
|
||||||
|
let nameColor: PeerNameColor
|
||||||
|
var authorName = presentationData.strings.Appearance_PreviewReplyAuthor
|
||||||
|
if let accountPeer {
|
||||||
|
nameColor = accountPeer.nameColor ?? .blue
|
||||||
|
if accountPeer._asPeer().hasCustomNameColor {
|
||||||
|
authorName = accountPeer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nameColor = .blue
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.append(.chatPreview(presentationData.theme, presentationData.chatWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (authorName, presentationData.strings.Appearance_PreviewReplyText), text: presentationData.strings.Appearance_PreviewIncomingText, nameColor: nameColor, backgroundEmojiId: accountPeer?.backgroundEmojiId), ChatPreviewMessageItem(outgoing: true, reply: nil, text: presentationData.strings.Appearance_PreviewOutgoingText, nameColor: .blue, backgroundEmojiId: nil)]))
|
||||||
|
|
||||||
entries.append(.themes(presentationData.theme, presentationData.strings, chatThemes, themeReference, presentationThemeSettings.automaticThemeSwitchSetting.force || presentationData.autoNightModeTriggered, animatedEmojiStickers, presentationThemeSettings.themeSpecificAccentColors, presentationThemeSettings.themeSpecificChatWallpapers))
|
entries.append(.themes(presentationData.theme, presentationData.strings, chatThemes, themeReference, presentationThemeSettings.automaticThemeSwitchSetting.force || presentationData.autoNightModeTriggered, animatedEmojiStickers, presentationThemeSettings.themeSpecificAccentColors, presentationThemeSettings.themeSpecificChatWallpapers))
|
||||||
entries.append(.chatTheme(presentationData.theme, strings.Settings_ChatThemes))
|
entries.append(.chatTheme(presentationData.theme, strings.Settings_ChatThemes))
|
||||||
entries.append(.wallpaper(presentationData.theme, strings.Settings_ChatBackground))
|
entries.append(.wallpaper(presentationData.theme, strings.Settings_ChatBackground))
|
||||||
|
|
||||||
if let accountPeer {
|
let colors = nameColors.get(nameColor)
|
||||||
let colors = nameColors.get(accountPeer.nameColor ?? .blue)
|
entries.append(.nameColor(presentationData.theme, strings.Appearance_NameColor, accountPeer?.compactDisplayTitle ?? "", colors.main))
|
||||||
entries.append(.nameColor(presentationData.theme, strings.Appearance_NameColor, accountPeer.compactDisplayTitle, colors.main))
|
|
||||||
}
|
|
||||||
|
|
||||||
entries.append(.autoNight(presentationData.theme, strings.Appearance_NightTheme, presentationThemeSettings.automaticThemeSwitchSetting.force, !presentationData.autoNightModeTriggered || presentationThemeSettings.automaticThemeSwitchSetting.force))
|
entries.append(.autoNight(presentationData.theme, strings.Appearance_NightTheme, presentationThemeSettings.automaticThemeSwitchSetting.force, !presentationData.autoNightModeTriggered || presentationThemeSettings.automaticThemeSwitchSetting.force))
|
||||||
let autoNightMode: String
|
let autoNightMode: String
|
||||||
|
@ -236,6 +236,14 @@ public extension Peer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hasCustomNameColor: Bool {
|
||||||
|
let defaultNameColor = PeerNameColor(rawValue: Int32(self.id.id._internalGetInt64Value() % 7))
|
||||||
|
if self.nameColor != defaultNameColor {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var backgroundEmojiId: Int64? {
|
var backgroundEmojiId: Int64? {
|
||||||
switch self {
|
switch self {
|
||||||
case let user as TelegramUser:
|
case let user as TelegramUser:
|
||||||
|
@ -125,12 +125,12 @@ private func generateRingImage(nameColor: PeerNameColors.Colors) -> UIImage? {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private func generateFillImage(nameColor: PeerNameColors.Colors) -> UIImage? {
|
func generatePeerNameColorImage(nameColor: PeerNameColors.Colors, bounds: CGSize = CGSize(width: 40.0, height: 40.0), size: CGSize = CGSize(width: 40.0, height: 40.0)) -> UIImage? {
|
||||||
return generateImage(CGSize(width: 40.0, height: 40.0), rotatedContext: { size, context in
|
return generateImage(bounds, rotatedContext: { contextSize, context in
|
||||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
let bounds = CGRect(origin: CGPoint(), size: contextSize)
|
||||||
context.clear(bounds)
|
context.clear(bounds)
|
||||||
|
|
||||||
let circleBounds = bounds
|
let circleBounds = CGRect(origin: CGPoint(x: floorToScreenPixels((bounds.width - size.width) / 2.0), y: floorToScreenPixels((bounds.height - size.height) / 2.0)), size: size)
|
||||||
context.addEllipse(in: circleBounds)
|
context.addEllipse(in: circleBounds)
|
||||||
context.clip()
|
context.clip()
|
||||||
|
|
||||||
@ -139,24 +139,26 @@ private func generateFillImage(nameColor: PeerNameColors.Colors) -> UIImage? {
|
|||||||
context.fill(circleBounds)
|
context.fill(circleBounds)
|
||||||
|
|
||||||
if let thirdColor = nameColor.tertiary {
|
if let thirdColor = nameColor.tertiary {
|
||||||
context.move(to: CGPoint(x: size.width, y: 0.0))
|
context.move(to: CGPoint(x: contextSize.width, y: 0.0))
|
||||||
context.addLine(to: CGPoint(x: size.width, y: size.height))
|
context.addLine(to: CGPoint(x: contextSize.width, y: contextSize.height))
|
||||||
context.addLine(to: CGPoint(x: 0.0, y: size.height))
|
context.addLine(to: CGPoint(x: 0.0, y: contextSize.height))
|
||||||
context.closePath()
|
context.closePath()
|
||||||
context.setFillColor(nameColor.main.cgColor)
|
context.setFillColor(nameColor.main.cgColor)
|
||||||
context.fillPath()
|
context.fillPath()
|
||||||
|
|
||||||
context.setFillColor(thirdColor.cgColor)
|
context.setFillColor(thirdColor.cgColor)
|
||||||
context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
|
context.translateBy(x: contextSize.width / 2.0, y: contextSize.height / 2.0)
|
||||||
context.rotate(by: .pi / 4.0)
|
context.rotate(by: .pi / 4.0)
|
||||||
|
|
||||||
let path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(x: -9.0, y: -9.0), size: CGSize(width: 18.0, height: 18.0)), cornerRadius: 4.0)
|
let rectSide = size.width / 40.0 * 18.0
|
||||||
|
let rectCornerRadius = round(size.width / 40.0 * 4.0)
|
||||||
|
let path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(x: -rectSide / 2.0, y: -rectSide / 2.0), size: CGSize(width: rectSide, height: rectSide)), cornerRadius: rectCornerRadius)
|
||||||
context.addPath(path.cgPath)
|
context.addPath(path.cgPath)
|
||||||
context.fillPath()
|
context.fillPath()
|
||||||
} else {
|
} else {
|
||||||
context.move(to: .zero)
|
context.move(to: .zero)
|
||||||
context.addLine(to: CGPoint(x: size.width, y: 0.0))
|
context.addLine(to: CGPoint(x: contextSize.width, y: 0.0))
|
||||||
context.addLine(to: CGPoint(x: 0.0, y: size.height))
|
context.addLine(to: CGPoint(x: 0.0, y: contextSize.height))
|
||||||
context.closePath()
|
context.closePath()
|
||||||
context.setFillColor(nameColor.main.cgColor)
|
context.setFillColor(nameColor.main.cgColor)
|
||||||
context.fillPath()
|
context.fillPath()
|
||||||
@ -230,7 +232,7 @@ private final class PeerNameColorIconItemNode : ListViewItemNode {
|
|||||||
strongSelf.item = item
|
strongSelf.item = item
|
||||||
|
|
||||||
if updatedAccentColor {
|
if updatedAccentColor {
|
||||||
strongSelf.fillNode.image = generateFillImage(nameColor: item.colors)
|
strongSelf.fillNode.image = generatePeerNameColorImage(nameColor: item.colors)
|
||||||
strongSelf.ringNode.image = generateRingImage(nameColor: item.colors)
|
strongSelf.ringNode.image = generateRingImage(nameColor: item.colors)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,9 +525,9 @@ final class PeerNameColorItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
var i: Int = 0
|
var i: Int = 0
|
||||||
for index in item.colors.displayOrder {
|
for index in item.colors.displayOrder {
|
||||||
let color = PeerNameColor(rawValue: index)
|
let color = PeerNameColor(rawValue: index)
|
||||||
if let colors = item.colors.colors[index] {
|
let colors = item.colors.get(color, dark: item.theme.overallDarkAppearance)
|
||||||
entries.append(.color(i, color, colors, color == item.currentColor))
|
entries.append(.color(i, color, colors, color == item.currentColor))
|
||||||
}
|
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,6 +280,8 @@ public func PeerNameColorScreen(
|
|||||||
statePromise.set(stateValue.modify { f($0) })
|
statePromise.set(stateValue.modify { f($0) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||||
|
|
||||||
var presentImpl: ((ViewController) -> Void)?
|
var presentImpl: ((ViewController) -> Void)?
|
||||||
var pushImpl: ((ViewController) -> Void)?
|
var pushImpl: ((ViewController) -> Void)?
|
||||||
var dismissImpl: (() -> Void)?
|
var dismissImpl: (() -> Void)?
|
||||||
@ -416,7 +418,7 @@ public func PeerNameColorScreen(
|
|||||||
elevatedLayout: false,
|
elevatedLayout: false,
|
||||||
action: { action in
|
action: { action in
|
||||||
if case .info = action {
|
if case .info = action {
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .storiesSuggestedReactions, forceDark: false, dismissed: nil)
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .nameColor, forceDark: false, dismissed: nil)
|
||||||
pushImpl?(controller)
|
pushImpl?(controller)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -550,7 +552,7 @@ public func PeerNameColorScreen(
|
|||||||
return attemptNavigationImpl?(f) ?? true
|
return attemptNavigationImpl?(f) ?? true
|
||||||
}
|
}
|
||||||
attemptNavigationImpl = { f in
|
attemptNavigationImpl = { f in
|
||||||
if !context.isPremium {
|
if case .account = subject, !context.isPremium {
|
||||||
f()
|
f()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -576,20 +578,33 @@ public func PeerNameColorScreen(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
applyChangesImpl = {
|
applyChangesImpl = { [weak controller] in
|
||||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||||
|> deliverOnMainQueue).startStandalone(next: { peer in
|
|> deliverOnMainQueue).startStandalone(next: { peer in
|
||||||
guard let peer else {
|
guard let peer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let state = stateValue.with { $0 }
|
let state = stateValue.with { $0 }
|
||||||
|
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
let nameColor = state.updatedNameColor ?? peer.nameColor
|
let nameColor = state.updatedNameColor ?? peer.nameColor
|
||||||
let backgroundEmojiId = state.updatedBackgroundEmojiId ?? peer.backgroundEmojiId
|
let backgroundEmojiId = state.updatedBackgroundEmojiId ?? peer.backgroundEmojiId
|
||||||
|
let colors = context.peerNameColors.get(nameColor ?? .blue, dark: presentationData.theme.overallDarkAppearance)
|
||||||
|
|
||||||
switch subject {
|
switch subject {
|
||||||
case .account:
|
case .account:
|
||||||
let _ = context.engine.accountData.updateNameColorAndEmoji(nameColor: nameColor ?? .blue, backgroundEmojiId: backgroundEmojiId ?? 0).startStandalone()
|
let _ = context.engine.accountData.updateNameColorAndEmoji(nameColor: nameColor ?? .blue, backgroundEmojiId: backgroundEmojiId ?? 0).startStandalone()
|
||||||
|
|
||||||
|
if let navigationController = controller?.navigationController as? NavigationController {
|
||||||
|
Queue.mainQueue().after(0.25) {
|
||||||
|
if let lastController = navigationController.viewControllers.last as? ViewController {
|
||||||
|
let tipController = UndoOverlayController(presentationData: presentationData, content: .image(image: generatePeerNameColorImage(nameColor: colors, bounds: CGSize(width: 32.0, height: 32.0), size: CGSize(width: 22.0, height: 22.0))!, title: nil, text: presentationData.strings.NameColor_YourColorUpdated, round: false, undoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false })
|
||||||
|
lastController.present(tipController, in: .window(.root))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
case let .channel(peerId):
|
case let .channel(peerId):
|
||||||
updateState { state in
|
updateState { state in
|
||||||
@ -616,10 +631,10 @@ public func PeerNameColorScreen(
|
|||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
presentImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.ChannelBoost_BoostLinkCopied), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }))
|
presentImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.ChannelBoost_BoostLinkCopied), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }))
|
||||||
return true
|
return true
|
||||||
}, openStats: nil, openGift: {
|
}, openStats: nil, openGift: premiumConfiguration.giveawayGiftsPurchaseAvailable ? {
|
||||||
let controller = createGiveawayController(context: context, peerId: peerId, subject: .generic)
|
let controller = createGiveawayController(context: context, peerId: peerId, subject: .generic)
|
||||||
pushImpl?(controller)
|
pushImpl?(controller)
|
||||||
})
|
} : nil)
|
||||||
pushImpl?(controller)
|
pushImpl?(controller)
|
||||||
|
|
||||||
HapticFeedback().impact(.light)
|
HapticFeedback().impact(.light)
|
||||||
@ -633,6 +648,15 @@ public func PeerNameColorScreen(
|
|||||||
return updatedState
|
return updatedState
|
||||||
}
|
}
|
||||||
}, completed: {
|
}, completed: {
|
||||||
|
if let navigationController = controller?.navigationController as? NavigationController {
|
||||||
|
Queue.mainQueue().after(0.25) {
|
||||||
|
if let lastController = navigationController.viewControllers.last as? ViewController {
|
||||||
|
let tipController = UndoOverlayController(presentationData: presentationData, content: .image(image: generatePeerNameColorImage(nameColor: colors, bounds: CGSize(width: 32.0, height: 32.0), size: CGSize(width: 22.0, height: 22.0))!, title: nil, text: presentationData.strings.NameColor_ChannelColorUpdated, round: false, undoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false })
|
||||||
|
lastController.present(tipController, in: .window(.root))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -514,7 +514,7 @@ private final class StoryContainerScreenComponent: Component {
|
|||||||
|
|
||||||
var apply = true
|
var apply = true
|
||||||
let currentTime = CACurrentMediaTime()
|
let currentTime = CACurrentMediaTime()
|
||||||
if let previousTime = self.previousSeekTime, currentTime - previousTime < 0.1 {
|
if let previousTime = self.previousSeekTime, currentTime - previousTime < 0.15 {
|
||||||
apply = false
|
apply = false
|
||||||
}
|
}
|
||||||
if apply {
|
if apply {
|
||||||
|
@ -496,7 +496,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
|||||||
let botsKey = ValueBoxKey(length: 8)
|
let botsKey = ValueBoxKey(length: 8)
|
||||||
botsKey.setInt64(0, value: 0)
|
botsKey.setInt64(0, value: 0)
|
||||||
|
|
||||||
var iconLoaded: [EnginePeer.Id: Bool] = [:]
|
let iconLoaded = Atomic<[EnginePeer.Id: Bool]>(value: [:])
|
||||||
let bots = context.engine.data.subscribe(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: Namespaces.CachedItemCollection.attachMenuBots, id: botsKey))
|
let bots = context.engine.data.subscribe(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: Namespaces.CachedItemCollection.attachMenuBots, id: botsKey))
|
||||||
|> mapToSignal { entry -> Signal<[AttachMenuBot], NoError> in
|
|> mapToSignal { entry -> Signal<[AttachMenuBot], NoError> in
|
||||||
let bots: [AttachMenuBots.Bot] = entry?.get(AttachMenuBots.self)?.bots ?? []
|
let bots: [AttachMenuBots.Bot] = entry?.get(AttachMenuBots.self)?.bots ?? []
|
||||||
@ -512,7 +512,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
|||||||
if let peer = PeerReference(peer._asPeer()), let icon = bot.icons[.iOSSettingsStatic] {
|
if let peer = PeerReference(peer._asPeer()), let icon = bot.icons[.iOSSettingsStatic] {
|
||||||
let fileReference: FileMediaReference = .attachBot(peer: peer, media: icon)
|
let fileReference: FileMediaReference = .attachBot(peer: peer, media: icon)
|
||||||
let signal: Signal<AttachMenuBot?, NoError>
|
let signal: Signal<AttachMenuBot?, NoError>
|
||||||
if let _ = iconLoaded[peer.id] {
|
if let _ = iconLoaded.with({ $0 })[peer.id] {
|
||||||
signal = .single(resultBot)
|
signal = .single(resultBot)
|
||||||
} else {
|
} else {
|
||||||
signal = .single(nil)
|
signal = .single(nil)
|
||||||
@ -523,7 +523,11 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
|||||||
return resultBot
|
return resultBot
|
||||||
}
|
}
|
||||||
|> afterNext { _ in
|
|> afterNext { _ in
|
||||||
iconLoaded[peer.id] = true
|
let _ = iconLoaded.modify { current in
|
||||||
|
var updated = current
|
||||||
|
updated[peer.id] = true
|
||||||
|
return updated
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1744,6 +1744,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
mappedSource = .storiesSuggestedReactions
|
mappedSource = .storiesSuggestedReactions
|
||||||
case let .channelBoost(peerId):
|
case let .channelBoost(peerId):
|
||||||
mappedSource = .channelBoost(peerId)
|
mappedSource = .channelBoost(peerId)
|
||||||
|
case .nameColor:
|
||||||
|
mappedSource = .nameColor
|
||||||
}
|
}
|
||||||
let controller = PremiumIntroScreen(context: context, source: mappedSource, forceDark: forceDark)
|
let controller = PremiumIntroScreen(context: context, source: mappedSource, forceDark: forceDark)
|
||||||
controller.wasDismissed = dismissed
|
controller.wasDismissed = dismissed
|
||||||
|
Loading…
x
Reference in New Issue
Block a user