mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
64aa306cf9
32 changed files with 652 additions and 243 deletions
|
|
@ -1 +1 @@
|
|||
06de25b179c80e59
|
||||
c27f02bf6e413fdc
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ private enum InnerState: Equatable {
|
|||
|
||||
public final class AuthorizationSequenceController: NavigationController, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
|
||||
static func navigationBarTheme(_ theme: PresentationTheme) -> NavigationBarTheme {
|
||||
return NavigationBarTheme(overallDarkAppearance: theme.overallDarkAppearance, buttonColor: theme.chat.inputPanel.panelControlColor, disabledButtonColor: theme.intro.disabledTextColor, primaryTextColor: theme.intro.primaryTextColor, backgroundColor: .clear, opaqueBackgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: theme.rootController.navigationBar.badgeBackgroundColor, badgeStrokeColor: theme.rootController.navigationBar.badgeStrokeColor, badgeTextColor: theme.rootController.navigationBar.badgeTextColor, edgeEffectColor: .clear, accentButtonColor: theme.list.itemCheckColors.fillColor, accentForegroundColor: theme.list.itemCheckColors.foregroundColor, style: .glass)
|
||||
return NavigationBarTheme(overallDarkAppearance: theme.overallDarkAppearance, buttonColor: theme.chat.inputPanel.panelControlColor, disabledButtonColor: theme.intro.disabledTextColor, primaryTextColor: theme.intro.primaryTextColor, backgroundColor: .clear, opaqueBackgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: theme.rootController.navigationBar.badgeBackgroundColor, badgeStrokeColor: theme.rootController.navigationBar.badgeStrokeColor, badgeTextColor: theme.rootController.navigationBar.badgeTextColor, edgeEffectColor: .clear, accentButtonColor: theme.list.itemCheckColors.fillColor, accentDisabledButtonColor: theme.chat.inputPanel.panelControlDisabledColor, accentForegroundColor: theme.list.itemCheckColors.foregroundColor, style: .glass)
|
||||
}
|
||||
|
||||
private let sharedContext: SharedAccountContext
|
||||
|
|
|
|||
|
|
@ -3136,20 +3136,11 @@ open class ListViewImpl: ASDisplayNode, ListView, ASScrollViewDelegate, ASGestur
|
|||
} else if self.snapToBottomInsetUntilFirstInteraction {
|
||||
offsetFix = -updateSizeAndInsets.insets.bottom + self.insets.bottom
|
||||
} else {
|
||||
/*if let visualInsets = self.visualInsets, animated, (visualInsets.top == updateSizeAndInsets.insets.top || visualInsets.top == self.insets.top) {
|
||||
offsetFix = 0.0
|
||||
} else {*/
|
||||
offsetFix = updateSizeAndInsets.insets.top - self.insets.top
|
||||
//}
|
||||
offsetFix = updateSizeAndInsets.insets.top - self.insets.top
|
||||
}
|
||||
|
||||
offsetFix += additionalScrollDistance
|
||||
|
||||
/*if let topItemNode = self.itemNodes.first(where: { $0.index == 0 }) {
|
||||
let topEdge = self.scroller.contentOffset.y + updateSizeAndInsets.insets.top
|
||||
offsetFix = -(topEdge - topItemNode.apparentFrame.minY)
|
||||
}*/
|
||||
|
||||
self.insets = updateSizeAndInsets.insets
|
||||
self.headerInsets = updateSizeAndInsets.headerInsets ?? self.insets
|
||||
self.scrollIndicatorInsets = updateSizeAndInsets.scrollIndicatorInsets ?? self.insets
|
||||
|
|
@ -3239,16 +3230,18 @@ open class ListViewImpl: ASDisplayNode, ListView, ASScrollViewDelegate, ASGestur
|
|||
animation = basicAnimation
|
||||
}
|
||||
|
||||
deferredUpdateVisible = true
|
||||
animation.completion = { [weak self] _ in
|
||||
self?.updateItemNodesVisibilities(onlyPositive: false)
|
||||
}
|
||||
self.layer.add(animation, forKey: nil)
|
||||
if !completeOffset.isZero {
|
||||
for itemNode in self.itemNodes {
|
||||
itemNode.applyAbsoluteOffset(value: CGPoint(x: 0.0, y: -completeOffset), animationCurve: animationCurve, duration: animationDuration)
|
||||
if customAnimationTransition == nil {
|
||||
deferredUpdateVisible = true
|
||||
animation.completion = { [weak self] _ in
|
||||
self?.updateItemNodesVisibilities(onlyPositive: false)
|
||||
}
|
||||
self.layer.add(animation, forKey: nil)
|
||||
if !completeOffset.isZero {
|
||||
for itemNode in self.itemNodes {
|
||||
itemNode.applyAbsoluteOffset(value: CGPoint(x: 0.0, y: -completeOffset), animationCurve: animationCurve, duration: animationDuration)
|
||||
}
|
||||
self.didScrollWithOffset?(-completeOffset, ContainedViewLayoutTransition.animated(duration: animationDuration, curve: animationCurve), nil, self.isTrackingOrDecelerating)
|
||||
}
|
||||
self.didScrollWithOffset?(-completeOffset, ContainedViewLayoutTransition.animated(duration: animationDuration, curve: animationCurve), nil, self.isTrackingOrDecelerating)
|
||||
}
|
||||
} else {
|
||||
self.didScrollWithOffset?(-completeOffset, .immediate, nil, self.isTrackingOrDecelerating)
|
||||
|
|
|
|||
|
|
@ -29,11 +29,12 @@ public final class NavigationBarTheme {
|
|||
public let badgeTextColor: UIColor
|
||||
public let edgeEffectColor: UIColor?
|
||||
public let accentButtonColor: UIColor
|
||||
public let accentDisabledButtonColor: UIColor
|
||||
public let accentForegroundColor: UIColor
|
||||
public let style: NavigationBar.Style
|
||||
public let glassStyle: NavigationBar.GlassStyle
|
||||
|
||||
public init(overallDarkAppearance: Bool, buttonColor: UIColor, disabledButtonColor: UIColor, primaryTextColor: UIColor, backgroundColor: UIColor, opaqueBackgroundColor: UIColor? = nil, enableBackgroundBlur: Bool, separatorColor: UIColor, badgeBackgroundColor: UIColor, badgeStrokeColor: UIColor, badgeTextColor: UIColor, edgeEffectColor: UIColor? = nil, accentButtonColor: UIColor, accentForegroundColor: UIColor, style: NavigationBar.Style = .legacy, glassStyle: NavigationBar.GlassStyle = .default) {
|
||||
public init(overallDarkAppearance: Bool, buttonColor: UIColor, disabledButtonColor: UIColor, primaryTextColor: UIColor, backgroundColor: UIColor, opaqueBackgroundColor: UIColor? = nil, enableBackgroundBlur: Bool, separatorColor: UIColor, badgeBackgroundColor: UIColor, badgeStrokeColor: UIColor, badgeTextColor: UIColor, edgeEffectColor: UIColor? = nil, accentButtonColor: UIColor, accentDisabledButtonColor: UIColor, accentForegroundColor: UIColor, style: NavigationBar.Style = .legacy, glassStyle: NavigationBar.GlassStyle = .default) {
|
||||
self.overallDarkAppearance = overallDarkAppearance
|
||||
self.buttonColor = buttonColor
|
||||
self.disabledButtonColor = disabledButtonColor
|
||||
|
|
@ -47,17 +48,18 @@ public final class NavigationBarTheme {
|
|||
self.badgeTextColor = badgeTextColor
|
||||
self.edgeEffectColor = edgeEffectColor
|
||||
self.accentButtonColor = accentButtonColor
|
||||
self.accentDisabledButtonColor = accentDisabledButtonColor
|
||||
self.accentForegroundColor = accentForegroundColor
|
||||
self.style = style
|
||||
self.glassStyle = glassStyle
|
||||
}
|
||||
|
||||
public func withUpdatedBackgroundColor(_ color: UIColor) -> NavigationBarTheme {
|
||||
return NavigationBarTheme(overallDarkAppearance: self.overallDarkAppearance, buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: color, opaqueBackgroundColor: self.opaqueBackgroundColor, enableBackgroundBlur: false, separatorColor: self.separatorColor, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor, edgeEffectColor: self.edgeEffectColor, accentButtonColor: self.accentButtonColor, accentForegroundColor: self.accentForegroundColor, style: self.style, glassStyle: self.glassStyle)
|
||||
return NavigationBarTheme(overallDarkAppearance: self.overallDarkAppearance, buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: color, opaqueBackgroundColor: self.opaqueBackgroundColor, enableBackgroundBlur: false, separatorColor: self.separatorColor, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor, edgeEffectColor: self.edgeEffectColor, accentButtonColor: self.accentButtonColor, accentDisabledButtonColor: self.accentDisabledButtonColor, accentForegroundColor: self.accentForegroundColor, style: self.style, glassStyle: self.glassStyle)
|
||||
}
|
||||
|
||||
public func withUpdatedSeparatorColor(_ color: UIColor) -> NavigationBarTheme {
|
||||
return NavigationBarTheme(overallDarkAppearance: self.overallDarkAppearance, buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: self.backgroundColor, opaqueBackgroundColor: self.opaqueBackgroundColor, enableBackgroundBlur: self.enableBackgroundBlur, separatorColor: color, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor, edgeEffectColor: self.edgeEffectColor, accentButtonColor: self.accentButtonColor, accentForegroundColor: self.accentForegroundColor, style: self.style, glassStyle: self.glassStyle)
|
||||
return NavigationBarTheme(overallDarkAppearance: self.overallDarkAppearance, buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: self.backgroundColor, opaqueBackgroundColor: self.opaqueBackgroundColor, enableBackgroundBlur: self.enableBackgroundBlur, separatorColor: color, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor, edgeEffectColor: self.edgeEffectColor, accentButtonColor: self.accentButtonColor, accentDisabledButtonColor: self.accentDisabledButtonColor, accentForegroundColor: self.accentForegroundColor, style: self.style, glassStyle: self.glassStyle)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -690,7 +690,7 @@ private func galleryEntriesForMessageHistoryEntries(_ entries: [MessageHistoryEn
|
|||
}
|
||||
|
||||
public class GalleryController: ViewController, StandalonePresentableController, KeyShortcutResponder, GalleryControllerProtocol {
|
||||
public static let darkNavigationTheme = NavigationBarTheme(overallDarkAppearance: true, buttonColor: .white, disabledButtonColor: UIColor(rgb: 0x525252), primaryTextColor: .white, backgroundColor: UIColor(white: 0.0, alpha: 0.6), enableBackgroundBlur: false, separatorColor: UIColor(white: 0.0, alpha: 0.8), badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, edgeEffectColor: .clear, accentButtonColor: .white, accentForegroundColor: .black, style: .glass)
|
||||
public static let darkNavigationTheme = NavigationBarTheme(overallDarkAppearance: true, buttonColor: .white, disabledButtonColor: UIColor(rgb: 0x525252), primaryTextColor: .white, backgroundColor: UIColor(white: 0.0, alpha: 0.6), enableBackgroundBlur: false, separatorColor: UIColor(white: 0.0, alpha: 0.8), badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, edgeEffectColor: .clear, accentButtonColor: .white, accentDisabledButtonColor: .white, accentForegroundColor: .black, style: .glass)
|
||||
|
||||
private var galleryNode: GalleryControllerNode {
|
||||
return self.displayNode as! GalleryControllerNode
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class SetupTwoStepVerificationController: ViewController {
|
|||
|
||||
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(overallDarkAppearance: self.presentationData.theme.overallDarkAppearance, buttonColor: self.presentationData.theme.rootController.navigationBar.accentTextColor, disabledButtonColor: self.presentationData.theme.rootController.navigationBar.disabledButtonColor, primaryTextColor: self.presentationData.theme.rootController.navigationBar.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, accentButtonColor: self.presentationData.theme.list.itemCheckColors.fillColor, accentForegroundColor: self.presentationData.theme.list.itemCheckColors.foregroundColor), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(overallDarkAppearance: self.presentationData.theme.overallDarkAppearance, buttonColor: self.presentationData.theme.rootController.navigationBar.accentTextColor, disabledButtonColor: self.presentationData.theme.rootController.navigationBar.disabledButtonColor, primaryTextColor: self.presentationData.theme.rootController.navigationBar.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, accentButtonColor: self.presentationData.theme.list.itemCheckColors.fillColor, accentDisabledButtonColor: self.presentationData.theme.chat.inputPanel.panelControlDisabledColor, accentForegroundColor: self.presentationData.theme.list.itemCheckColors.foregroundColor), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)))
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
|||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let defaultTheme = NavigationBarTheme(rootControllerTheme: self.presentationData.theme)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: defaultTheme.overallDarkAppearance, buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor, accentButtonColor: defaultTheme.accentButtonColor, accentForegroundColor: defaultTheme.accentForegroundColor)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: defaultTheme.overallDarkAppearance, buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor, accentButtonColor: defaultTheme.accentButtonColor, accentDisabledButtonColor: defaultTheme.accentDisabledButtonColor, accentForegroundColor: defaultTheme.accentForegroundColor)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Common_Back, close: self.presentationData.strings.Common_Close)))
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public final class TwoFactorAuthSplashScreen: ViewController {
|
|||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let defaultTheme = NavigationBarTheme(rootControllerTheme: self.presentationData.theme)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: defaultTheme.overallDarkAppearance, buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor, accentButtonColor: defaultTheme.accentButtonColor, accentForegroundColor: defaultTheme.accentForegroundColor)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: defaultTheme.overallDarkAppearance, buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor, accentButtonColor: defaultTheme.accentButtonColor, accentDisabledButtonColor: defaultTheme.accentDisabledButtonColor, accentForegroundColor: defaultTheme.accentForegroundColor)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Common_Back, close: self.presentationData.strings.Common_Close)))
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ public final class QrCodeScanScreen: ViewController {
|
|||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: self.presentationData.theme.overallDarkAppearance, buttonColor: .white, disabledButtonColor: .white, primaryTextColor: .white, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, accentButtonColor: .white, accentForegroundColor: .black)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: self.presentationData.theme.overallDarkAppearance, buttonColor: .white, disabledButtonColor: .white, primaryTextColor: .white, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, accentButtonColor: .white, accentDisabledButtonColor: .white, accentForegroundColor: .black)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Common_Back, close: self.presentationData.strings.Common_Close)))
|
||||
|
||||
|
|
|
|||
|
|
@ -1341,6 +1341,8 @@ extension StoreMessage {
|
|||
attributes.append(ReplyMessageAttribute(messageId: MessageId(peerId: replyPeerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId), threadMessageId: threadMessageId, quote: quote, isQuote: isQuote, innerSubject: innerSubject))
|
||||
} else if let replyHeader = replyHeader {
|
||||
attributes.append(QuotedReplyMessageAttribute(apiHeader: replyHeader, quote: quote, isQuote: isQuote))
|
||||
} else if let replyToTopId, peerIsForum {
|
||||
threadId = Int64(replyToTopId)
|
||||
}
|
||||
case let .messageReplyStoryHeader(messageReplyStoryHeaderData):
|
||||
let (peer, storyId) = (messageReplyStoryHeaderData.peer, messageReplyStoryHeaderData.storyId)
|
||||
|
|
|
|||
|
|
@ -4011,7 +4011,7 @@ func replayFinalState(
|
|||
case cancel
|
||||
}
|
||||
|
||||
var liveTypingDraftUpdates: [PeerAndThreadId: LiveTypingDraftUpdate] = [:]
|
||||
var liveTypingDraftUpdates: [PeerAndThreadId: [LiveTypingDraftUpdate]] = [:]
|
||||
|
||||
for operation in finalState.state.operations {
|
||||
switch operation {
|
||||
|
|
@ -4226,11 +4226,11 @@ func replayFinalState(
|
|||
let allKey = PeerAndThreadId(peerId: chatPeerId, threadId: nil)
|
||||
|
||||
if liveTypingDraftUpdates[key] != nil {
|
||||
liveTypingDraftUpdates[key] = .cancel
|
||||
liveTypingDraftUpdates[allKey] = .cancel
|
||||
liveTypingDraftUpdates[key] = [.cancel]
|
||||
liveTypingDraftUpdates[allKey] = [.cancel]
|
||||
} else if let currentDraft = transaction.getCurrentTypingDraft(location: key) {
|
||||
liveTypingDraftUpdates[key] = .cancel
|
||||
liveTypingDraftUpdates[allKey] = .cancel
|
||||
liveTypingDraftUpdates[key] = [.cancel]
|
||||
liveTypingDraftUpdates[allKey] = [.cancel]
|
||||
messages[i] = messages[i].withUpdatedCustomStableId(currentDraft.stableId)
|
||||
}
|
||||
}
|
||||
|
|
@ -4930,23 +4930,30 @@ func replayFinalState(
|
|||
updatedSecretChatTypingActivities.insert(chatPeerId.peerId)
|
||||
}
|
||||
case let .AddPeerLiveTypingDraftUpdate(peerAndThreadId, id, timestamp, authorId, text, entities):
|
||||
liveTypingDraftUpdates[peerAndThreadId] = .update(LiveTypingDraftUpdate.Update(
|
||||
if liveTypingDraftUpdates[peerAndThreadId] == nil {
|
||||
liveTypingDraftUpdates[peerAndThreadId] = []
|
||||
}
|
||||
liveTypingDraftUpdates[peerAndThreadId]?.append(.update(LiveTypingDraftUpdate.Update(
|
||||
id: id,
|
||||
threadId: peerAndThreadId.threadId,
|
||||
authorId: authorId,
|
||||
timestamp: timestamp,
|
||||
text: text,
|
||||
entities: entities
|
||||
))
|
||||
)))
|
||||
if peerAndThreadId.threadId != nil {
|
||||
liveTypingDraftUpdates[PeerAndThreadId(peerId: peerAndThreadId.peerId, threadId: nil)] = .update(LiveTypingDraftUpdate.Update(
|
||||
let allKey = PeerAndThreadId(peerId: peerAndThreadId.peerId, threadId: nil)
|
||||
if liveTypingDraftUpdates[allKey] == nil {
|
||||
liveTypingDraftUpdates[allKey] = []
|
||||
}
|
||||
liveTypingDraftUpdates[allKey]?.append(.update(LiveTypingDraftUpdate.Update(
|
||||
id: id,
|
||||
threadId: peerAndThreadId.threadId,
|
||||
authorId: authorId,
|
||||
timestamp: timestamp,
|
||||
text: text,
|
||||
entities: entities
|
||||
))
|
||||
)))
|
||||
}
|
||||
case let .UpdatePinnedItemIds(groupId, pinnedOperation):
|
||||
switch pinnedOperation {
|
||||
|
|
@ -6049,11 +6056,26 @@ func replayFinalState(
|
|||
|
||||
if !liveTypingDraftUpdates.isEmpty {
|
||||
transaction.combineTypingDrafts(locations: Set(liveTypingDraftUpdates.keys), update: { key, current in
|
||||
guard let update = liveTypingDraftUpdates[key] else {
|
||||
guard let update = liveTypingDraftUpdates[key]?.max(by: { lhs, rhs in
|
||||
switch lhs {
|
||||
case .cancel:
|
||||
return false
|
||||
case let .update(lhsUpdate):
|
||||
switch rhs {
|
||||
case .cancel:
|
||||
return true
|
||||
case let .update(rhsUpdate):
|
||||
return lhsUpdate.timestamp < rhsUpdate.timestamp
|
||||
}
|
||||
}
|
||||
}) else {
|
||||
return current
|
||||
}
|
||||
switch update {
|
||||
case let .update(update):
|
||||
if let current, current.id > update.id {
|
||||
return current
|
||||
}
|
||||
return (
|
||||
update.id,
|
||||
Namespaces.Message.Cloud,
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public extension NavigationBarTheme {
|
|||
badgeTextColor = theme.badgeTextColor
|
||||
}
|
||||
|
||||
self.init(overallDarkAppearance: rootControllerTheme.overallDarkAppearance, buttonColor: buttonColor, disabledButtonColor: disabledButtonColor, primaryTextColor: theme.primaryTextColor, backgroundColor: hideBackground ? .clear : theme.blurredBackgroundColor, opaqueBackgroundColor: hideBackground ? .clear : theme.opaqueBackgroundColor, enableBackgroundBlur: enableBackgroundBlur, separatorColor: hideBackground || hideSeparator ? .clear : theme.separatorColor, badgeBackgroundColor: hideBadge ? .clear : badgeBackgroundColor, badgeStrokeColor: .clear, badgeTextColor: hideBadge ? .clear : badgeTextColor, edgeEffectColor: edgeEffectColor, accentButtonColor: rootControllerTheme.list.itemCheckColors.fillColor, accentForegroundColor: rootControllerTheme.list.itemCheckColors.foregroundColor, style: style, glassStyle: glassStyle)
|
||||
self.init(overallDarkAppearance: rootControllerTheme.overallDarkAppearance, buttonColor: buttonColor, disabledButtonColor: disabledButtonColor, primaryTextColor: theme.primaryTextColor, backgroundColor: hideBackground ? .clear : theme.blurredBackgroundColor, opaqueBackgroundColor: hideBackground ? .clear : theme.opaqueBackgroundColor, enableBackgroundBlur: enableBackgroundBlur, separatorColor: hideBackground || hideSeparator ? .clear : theme.separatorColor, badgeBackgroundColor: hideBadge ? .clear : badgeBackgroundColor, badgeStrokeColor: .clear, badgeTextColor: hideBadge ? .clear : badgeTextColor, edgeEffectColor: edgeEffectColor, accentButtonColor: rootControllerTheme.list.itemCheckColors.fillColor, accentDisabledButtonColor: rootControllerTheme.chat.inputPanel.panelControlDisabledColor, accentForegroundColor: rootControllerTheme.list.itemCheckColors.foregroundColor, style: style, glassStyle: glassStyle)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -518,7 +518,7 @@ public final class ChatMessageItemImpl: ChatMessageItem, CustomStringConvertible
|
|||
}
|
||||
}
|
||||
|
||||
if viewClassName == ChatMessageBubbleItemNode.self && self.presentationData.largeEmoji && self.message.media.isEmpty {
|
||||
if viewClassName == ChatMessageBubbleItemNode.self && self.presentationData.largeEmoji && self.message.media.isEmpty && !self.message.attributes.contains(where: { $0 is TypingDraftMessageAttribute }) {
|
||||
if case let .message(_, _, _, attributes, _) = self.content {
|
||||
switch attributes.contentTypeHint {
|
||||
case .largeEmoji:
|
||||
|
|
|
|||
|
|
@ -249,7 +249,6 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
let currentMaxGlyphCount: Int?
|
||||
if let textRevealAnimationState = self.textRevealAnimationState {
|
||||
currentMaxGlyphCount = textRevealAnimationState.glyphCount(timestamp: CACurrentMediaTime())
|
||||
//print("currentMaxGlyphCount(\(textRevealAnimationState.fromCount) -> \(textRevealAnimationState.toCount)) fraction: \(textRevealAnimationState.fraction(timestamp: CACurrentMediaTime()))")
|
||||
} else {
|
||||
currentMaxGlyphCount = nil
|
||||
}
|
||||
|
|
@ -792,7 +791,6 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
|
||||
if let clippedGlyphCountLayout {
|
||||
textFrame.size = clippedGlyphCountLayout.size
|
||||
//print("currentMaxGlyphCount: \(currentMaxGlyphCount), size: \(textFrame.size.height)")
|
||||
textFrameWithoutInsets.size = CGSize(width: textFrame.width - textInsets.left - textInsets.right, height: textFrame.height - textInsets.top - textInsets.bottom)
|
||||
}
|
||||
|
||||
|
|
@ -1053,7 +1051,10 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
codeHighlightState.disposable.dispose()
|
||||
}
|
||||
|
||||
if previousAnimateGlyphCount != nil || strongSelf.textRevealAnimationState != nil || hadDraft {
|
||||
if previousAnimateGlyphCount != nil || strongSelf.textRevealAnimationState != nil || hasDraft || hadDraft {
|
||||
if strongSelf.textNode.textNode.revealGlyphCount == nil {
|
||||
strongSelf.textNode.textNode.updateRevealGlyphCount(count: previousAnimateGlyphCount ?? 0)
|
||||
}
|
||||
strongSelf.updateTextRevealAnimation(previousGlyphCount: previousAnimateGlyphCount ?? 0)
|
||||
}
|
||||
}
|
||||
|
|
@ -1092,7 +1093,6 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
duration: duration
|
||||
)
|
||||
if self.textRevealLink == nil, self.textRevealAnimationState != nil {
|
||||
var lastLineUpdateTimestamp = timestamp
|
||||
self.textRevealLink = SharedDisplayLinkDriver.shared.add { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
|
|
@ -1109,22 +1109,22 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
self.textNode.textNode.updateRevealGlyphCount(count: nil)
|
||||
self.requestFullUpdate?()
|
||||
} else {
|
||||
let lineUpdateTimeout = timestamp - lastLineUpdateTimestamp
|
||||
|
||||
var requestUpdate = false
|
||||
let glyphCount = textRevealAnimationState.glyphCount(timestamp: timestamp)
|
||||
if let revealGlyphCount = self.textNode.textNode.revealGlyphCount, let cachedLayout = self.textNode.textNode.cachedLayout {
|
||||
let previousLayout = cachedLayout.layoutForGlyphCount(glyphCount: revealGlyphCount)
|
||||
let updatedLayout = cachedLayout.layoutForGlyphCount(glyphCount: glyphCount)
|
||||
|
||||
if updatedLayout.size.height != previousLayout.size.height || abs(updatedLayout.size.width - previousLayout.size.width) > 8.0 {
|
||||
if lineUpdateTimeout >= 0.0 {
|
||||
lastLineUpdateTimestamp = timestamp
|
||||
if let previousRevealGlyphCount = self.textNode.textNode.revealGlyphCount, previousRevealGlyphCount != glyphCount {
|
||||
if let cachedLayout = self.textNode.textNode.cachedLayout {
|
||||
if cachedLayout.sizeForGlyphCount(glyphCount: previousRevealGlyphCount) != cachedLayout.sizeForGlyphCount(glyphCount: glyphCount) {
|
||||
requestUpdate = true
|
||||
}
|
||||
} else {
|
||||
requestUpdate = true
|
||||
}
|
||||
if requestUpdate {
|
||||
//print("glyphCount: request update")
|
||||
}
|
||||
|
||||
self.textNode.textNode.updateRevealGlyphCount(count: glyphCount)
|
||||
}
|
||||
self.textNode.textNode.updateRevealGlyphCount(count: glyphCount)
|
||||
|
||||
if requestUpdate {
|
||||
self.requestFullUpdate?()
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ public final class ChatNewThreadInfoItemNode: ListViewItemNode, ASGestureRecogni
|
|||
public let offsetContainer: ASDisplayNode
|
||||
public let titleNode: TextNode
|
||||
public let subtitleNode: TextNode
|
||||
let arrowView: UIImageView
|
||||
var arrowView: UIImageView?
|
||||
let iconBackground: SimpleLayer
|
||||
var icon = ComponentView<Empty>()
|
||||
|
||||
|
|
@ -106,8 +106,6 @@ public final class ChatNewThreadInfoItemNode: ListViewItemNode, ASGestureRecogni
|
|||
self.subtitleNode.isUserInteractionEnabled = false
|
||||
self.subtitleNode.displaysAsynchronously = false
|
||||
|
||||
self.arrowView = UIImageView()
|
||||
|
||||
super.init(layerBacked: false, rotated: true)
|
||||
|
||||
self.transform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
||||
|
|
@ -231,8 +229,14 @@ public final class ChatNewThreadInfoItemNode: ListViewItemNode, ASGestureRecogni
|
|||
if strongSelf.iconBackground.superlayer == nil {
|
||||
strongSelf.offsetContainer.layer.addSublayer(strongSelf.iconBackground)
|
||||
}
|
||||
if strongSelf.arrowView.superview == nil {
|
||||
strongSelf.offsetContainer.view.addSubview(strongSelf.arrowView)
|
||||
|
||||
let arrowView: UIImageView
|
||||
if let current = self?.arrowView {
|
||||
arrowView = current
|
||||
} else {
|
||||
arrowView = UIImageView()
|
||||
strongSelf.arrowView = arrowView
|
||||
strongSelf.offsetContainer.view.addSubview(arrowView)
|
||||
}
|
||||
|
||||
let iconComponent = AnyComponent(BundleIconComponent(
|
||||
|
|
@ -265,15 +269,15 @@ public final class ChatNewThreadInfoItemNode: ListViewItemNode, ASGestureRecogni
|
|||
contentOriginY += subtitleLayout.size.height
|
||||
contentOriginY += 20.0
|
||||
|
||||
if strongSelf.arrowView.image == nil {
|
||||
strongSelf.arrowView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Search/DownButton"), color: .white)?.withRenderingMode(.alwaysTemplate)
|
||||
if arrowView.image == nil {
|
||||
arrowView.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Search/DownButton"), color: .white)?.withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
strongSelf.arrowView.tintColor = primaryTextColor.withMultipliedAlpha(0.5)
|
||||
if let image = strongSelf.arrowView.image {
|
||||
arrowView.tintColor = primaryTextColor.withMultipliedAlpha(0.5)
|
||||
if let image = arrowView.image {
|
||||
let scaleFactor: CGFloat = 0.8
|
||||
let imageSize = CGSize(width: floor(image.size.width * scaleFactor), height: floor(image.size.height * scaleFactor))
|
||||
let arrowFrame = CGRect(origin: CGPoint(x: backgroundFrame.origin.x + floor((backgroundSize.width - imageSize.width) / 2.0), y: backgroundFrame.minY + backgroundFrame.height - 8.0 - imageSize.height), size: imageSize)
|
||||
strongSelf.arrowView.frame = arrowFrame
|
||||
arrowView.frame = arrowFrame
|
||||
}
|
||||
|
||||
if strongSelf.backgroundContent == nil, let backgroundContent = item.controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {
|
||||
|
|
|
|||
|
|
@ -941,8 +941,8 @@ public final class ChatSideTopicsPanel: Component {
|
|||
}
|
||||
let size = CGSize(width: contentSize, height: availableSize.height)
|
||||
|
||||
let iconFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - iconSize.height) * 0.5)), size: iconSize)
|
||||
let titleFrame = CGRect(origin: CGPoint(x: iconFrame.maxX + spacing, y: floor((size.height - titleSize.height) * 0.5)), size: titleSize)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - iconSize.height) * 0.5) - 1.0), size: iconSize)
|
||||
let titleFrame = CGRect(origin: CGPoint(x: iconFrame.maxX + spacing, y: floor((size.height - titleSize.height) * 0.5) - 1.0), size: titleSize)
|
||||
|
||||
if let icon = self.icon {
|
||||
if let avatarNode = self.avatarNode {
|
||||
|
|
@ -1422,7 +1422,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
let contentSize: CGFloat = leftInset + rightInset + titleSize.width
|
||||
let size = CGSize(width: contentSize, height: availableSize.height)
|
||||
|
||||
let titleFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - titleSize.height) * 0.5)), size: titleSize)
|
||||
let titleFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - titleSize.height) * 0.5) - 1.0), size: titleSize)
|
||||
|
||||
if let titleView = self.title.view {
|
||||
if titleView.superview == nil {
|
||||
|
|
@ -1502,7 +1502,6 @@ public final class ChatSideTopicsPanel: Component {
|
|||
self.scrollContainerView = UIView()
|
||||
self.scrollViewMask = UIImageView()
|
||||
self.scrollContainerView.mask = self.scrollViewMask
|
||||
//self.scrollContainerView.addSubview(self.scrollViewMask)
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
|
|
@ -1599,6 +1598,20 @@ public final class ChatSideTopicsPanel: Component {
|
|||
}
|
||||
}
|
||||
if isPinned {
|
||||
if !seenPinnedItems {
|
||||
switch component.location {
|
||||
case .side:
|
||||
beforePinnedItemsPosition = item.frame.minY
|
||||
case .top, .bottom:
|
||||
beforePinnedItemsPosition = item.frame.minX
|
||||
}
|
||||
switch component.location {
|
||||
case .side:
|
||||
afterPinnedItemsPosition = item.frame.maxY
|
||||
case .top, .bottom:
|
||||
afterPinnedItemsPosition = item.frame.maxX
|
||||
}
|
||||
}
|
||||
seenPinnedItems = true
|
||||
} else {
|
||||
if !seenPinnedItems {
|
||||
|
|
@ -1885,7 +1898,7 @@ public final class ChatSideTopicsPanel: Component {
|
|||
itemFrame = CGRect(origin: CGPoint(x: 8.0 + 4.0, y: directionContainerInset + 6.0), size: itemSize)
|
||||
directionContainerInset += itemSize.height
|
||||
case .top, .bottom:
|
||||
itemFrame = CGRect(origin: CGPoint(x: 12.0, y: 6.0), size: itemSize)
|
||||
itemFrame = CGRect(origin: CGPoint(x: 12.0, y: 5.0), size: itemSize)
|
||||
directionContainerInset += itemSize.width - 20.0
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -818,7 +818,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
|||
if let transitionInfo = reference.transitionInfo() {
|
||||
if let referenceView = transitionInfo.referenceView as? ContextExtractableContainer {
|
||||
if #available(iOS 26.2, *) {
|
||||
if transitionInfo.referenceView.bounds.width == transitionInfo.referenceView.bounds.height {
|
||||
if !"".isEmpty, transitionInfo.referenceView.bounds.width == transitionInfo.referenceView.bounds.height {
|
||||
contextExtractableContainer = (referenceView, convertFrame(transitionInfo.referenceView.bounds.inset(by: transitionInfo.insets), from: transitionInfo.referenceView, to: self.view))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1020,10 +1020,10 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
|
|||
switch mode {
|
||||
case .create:
|
||||
title = presentationData.strings.CreateTopic_CreateTitle
|
||||
doneTitle = presentationData.strings.CreateTopic_Create
|
||||
doneTitle = "___done"
|
||||
case let .edit(threadId, topic, isHidden):
|
||||
title = presentationData.strings.CreateTopic_EditTitle
|
||||
doneTitle = presentationData.strings.Common_Done
|
||||
doneTitle = "___done"
|
||||
|
||||
self.state = (topic.title, topic.icon, topic.iconColor, threadId == 1 ? isHidden : nil)
|
||||
}
|
||||
|
|
@ -1032,7 +1032,7 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer {
|
|||
|
||||
self.readyValue.set(componentReady.get() |> timeout(0.3, queue: .mainQueue(), alternate: .single(true)))
|
||||
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "___close", style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||
|
||||
self.doneBarItem = UIBarButtonItem(title: doneTitle, style: .done, target: self, action: #selector(self.createPressed))
|
||||
self.navigationItem.rightBarButtonItem = self.doneBarItem
|
||||
|
|
|
|||
|
|
@ -2390,14 +2390,12 @@ final class TextContentItemLayer: SimpleLayer {
|
|||
let size: CGSize
|
||||
let item: TextContentItem
|
||||
let mask: RenderMask?
|
||||
let maxGlyphDrawCount: Int?
|
||||
|
||||
init(size: CGSize, item: TextContentItem, mask: RenderMask?, maxGlyphDrawCount: Int?) {
|
||||
|
||||
init(size: CGSize, item: TextContentItem, mask: RenderMask?) {
|
||||
self.size = size
|
||||
self.item = item
|
||||
self.mask = mask
|
||||
self.maxGlyphDrawCount = maxGlyphDrawCount
|
||||
|
||||
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
|
@ -2476,8 +2474,6 @@ final class TextContentItemLayer: SimpleLayer {
|
|||
let offset = params.item.contentOffset
|
||||
let alignment: NSTextAlignment = .left
|
||||
|
||||
var drawnGlyphCount = 0
|
||||
|
||||
for i in 0 ..< params.item.segment.lines.count {
|
||||
let line = params.item.segment.lines[i]
|
||||
|
||||
|
|
@ -2508,14 +2504,6 @@ final class TextContentItemLayer: SimpleLayer {
|
|||
let run = run as! CTRun
|
||||
let glyphCount = CTRunGetGlyphCount(run)
|
||||
|
||||
var runDrawGlyphCount = glyphCount
|
||||
if let maxGlyphDrawCount = params.maxGlyphDrawCount {
|
||||
if drawnGlyphCount >= maxGlyphDrawCount {
|
||||
break
|
||||
}
|
||||
runDrawGlyphCount = CFIndex(max(0, min(Int(glyphCount), maxGlyphDrawCount - drawnGlyphCount)))
|
||||
}
|
||||
|
||||
let attributes = CTRunGetAttributes(run) as NSDictionary
|
||||
if attributes["Attribute__EmbeddedItem"] != nil {
|
||||
continue
|
||||
|
|
@ -2565,14 +2553,12 @@ final class TextContentItemLayer: SimpleLayer {
|
|||
let stringRange = CTRunGetStringRange(run)
|
||||
if line.attachments.contains(where: { $0.range.contains(stringRange.location) }) {
|
||||
} else {
|
||||
CTRunDraw(run, context, CFRangeMake(0, runDrawGlyphCount))
|
||||
CTRunDraw(run, context, CFRangeMake(0, glyphCount))
|
||||
}
|
||||
} else {
|
||||
CTRunDraw(run, context, CFRangeMake(0, runDrawGlyphCount))
|
||||
CTRunDraw(run, context, CFRangeMake(0, glyphCount))
|
||||
}
|
||||
|
||||
drawnGlyphCount += Int(glyphCount)
|
||||
|
||||
|
||||
if fixDoubleEmoji {
|
||||
context.setBlendMode(.normal)
|
||||
}
|
||||
|
|
@ -2740,8 +2726,9 @@ final class TextContentItemLayer: SimpleLayer {
|
|||
}
|
||||
|
||||
private(set) var params: Params?
|
||||
|
||||
|
||||
let renderNode: RenderNode
|
||||
private let renderNodeContainer: SimpleLayer
|
||||
private var contentMaskNode: ASImageNode?
|
||||
|
||||
private var overlayContentLayer: SimpleLayer?
|
||||
|
|
@ -2755,21 +2742,26 @@ final class TextContentItemLayer: SimpleLayer {
|
|||
private var currentAnimationId: Int = 0
|
||||
private var isAnimating: Bool = false
|
||||
private var currentContentMask: RenderMask?
|
||||
|
||||
private var revealMaskLayer: SimpleLayer?
|
||||
private var revealLineMaskLayers: [SimpleLayer] = []
|
||||
|
||||
private var maxGlyphDrawCount: Int?
|
||||
|
||||
init(displaysAsynchronously: Bool) {
|
||||
self.renderNode = RenderNode()
|
||||
self.renderNode.displaysAsynchronously = displaysAsynchronously
|
||||
|
||||
self.renderNodeContainer = SimpleLayer()
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSublayer(self.renderNode.layer)
|
||||
|
||||
self.renderNodeContainer.addSublayer(self.renderNode.layer)
|
||||
self.addSublayer(self.renderNodeContainer)
|
||||
}
|
||||
|
||||
|
||||
override init(layer: Any) {
|
||||
self.renderNode = RenderNode()
|
||||
|
||||
self.renderNodeContainer = SimpleLayer()
|
||||
|
||||
super.init(layer: layer)
|
||||
}
|
||||
|
||||
|
|
@ -2778,13 +2770,155 @@ final class TextContentItemLayer: SimpleLayer {
|
|||
}
|
||||
|
||||
func updateMaxGlyphDrawCount(value: Int?) {
|
||||
if self.maxGlyphDrawCount != value {
|
||||
self.maxGlyphDrawCount = value
|
||||
|
||||
if let renderParams = self.renderNode.params {
|
||||
self.renderNode.params = RenderParams(size: renderParams.size, item: renderParams.item, mask: renderParams.mask, maxGlyphDrawCount: self.maxGlyphDrawCount)
|
||||
self.renderNode.displayImmediately()
|
||||
if self.maxGlyphDrawCount == value {
|
||||
return
|
||||
}
|
||||
self.maxGlyphDrawCount = value
|
||||
self.updateRevealMask()
|
||||
}
|
||||
|
||||
private func updateRevealMask() {
|
||||
guard let params = self.params else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let maxGlyphDrawCount = self.maxGlyphDrawCount else {
|
||||
if let _ = self.revealMaskLayer {
|
||||
self.renderNodeContainer.mask = nil
|
||||
self.revealMaskLayer = nil
|
||||
self.revealLineMaskLayers.removeAll()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let item = params.item
|
||||
let lines = item.segment.lines
|
||||
let layerSize = item.size
|
||||
let offset = item.contentOffset
|
||||
|
||||
let revealMaskLayer: SimpleLayer
|
||||
if let existing = self.revealMaskLayer {
|
||||
revealMaskLayer = existing
|
||||
} else {
|
||||
revealMaskLayer = SimpleLayer()
|
||||
revealMaskLayer.backgroundColor = UIColor.clear.cgColor
|
||||
self.revealMaskLayer = revealMaskLayer
|
||||
self.renderNodeContainer.mask = revealMaskLayer
|
||||
}
|
||||
revealMaskLayer.frame = CGRect(origin: CGPoint(), size: layerSize)
|
||||
|
||||
// First pass: compute per-line state
|
||||
struct LineInfo {
|
||||
let minY: CGFloat
|
||||
let maxY: CGFloat
|
||||
let maskFrame: CGRect // only meaningful for partial lines
|
||||
let isFull: Bool
|
||||
}
|
||||
|
||||
var lineInfos: [LineInfo] = []
|
||||
var remainingGlyphs = maxGlyphDrawCount
|
||||
|
||||
for i in 0 ..< lines.count {
|
||||
let line = lines[i]
|
||||
|
||||
var lineFrame = line.frame
|
||||
lineFrame.origin.y += offset.y
|
||||
|
||||
if line.isRTL {
|
||||
lineFrame.origin.x = offset.x + floor(layerSize.width - lineFrame.width)
|
||||
lineFrame = displayLineFrame(frame: lineFrame, isRTL: true, boundingRect: CGRect(origin: CGPoint(), size: layerSize), cutout: nil)
|
||||
} else {
|
||||
lineFrame.origin.x += offset.x
|
||||
}
|
||||
|
||||
let lineHeight = line.ascent + line.descent
|
||||
|
||||
if remainingGlyphs <= 0 {
|
||||
// Empty line — skip, no mask rect needed
|
||||
continue
|
||||
}
|
||||
|
||||
var lineGlyphCount = 0
|
||||
var revealedWidth: CGFloat = 0.0
|
||||
let glyphRuns = CTLineGetGlyphRuns(line.line) as NSArray
|
||||
|
||||
for run in glyphRuns {
|
||||
let run = run as! CTRun
|
||||
let glyphCount = Int(CTRunGetGlyphCount(run))
|
||||
lineGlyphCount += glyphCount
|
||||
|
||||
if remainingGlyphs > 0 {
|
||||
let revealCount = min(glyphCount, remainingGlyphs)
|
||||
|
||||
var advances = [CGSize](repeating: CGSize(), count: revealCount)
|
||||
CTRunGetAdvances(run, CFRangeMake(0, revealCount), &advances)
|
||||
|
||||
for j in 0 ..< revealCount {
|
||||
revealedWidth += advances[j].width
|
||||
}
|
||||
|
||||
remainingGlyphs -= glyphCount
|
||||
}
|
||||
}
|
||||
|
||||
let isFull = remainingGlyphs >= 0
|
||||
revealedWidth = ceil(revealedWidth)
|
||||
|
||||
let maskFrame: CGRect
|
||||
if isFull {
|
||||
maskFrame = CGRect(x: 0.0, y: lineFrame.minY, width: layerSize.width, height: lineHeight)
|
||||
} else if line.isRTL {
|
||||
maskFrame = CGRect(x: lineFrame.maxX - revealedWidth, y: lineFrame.minY, width: revealedWidth, height: lineHeight)
|
||||
} else {
|
||||
maskFrame = CGRect(x: lineFrame.minX, y: lineFrame.minY, width: revealedWidth, height: lineHeight)
|
||||
}
|
||||
|
||||
lineInfos.append(LineInfo(minY: lineFrame.minY, maxY: lineFrame.minY + lineHeight, maskFrame: maskFrame, isFull: isFull))
|
||||
}
|
||||
|
||||
// Second pass: merge consecutive fully-filled lines into single rects
|
||||
var maskRects: [CGRect] = []
|
||||
var mergeStartY: CGFloat?
|
||||
var mergeEndY: CGFloat?
|
||||
|
||||
for info in lineInfos {
|
||||
if info.isFull {
|
||||
if mergeStartY != nil {
|
||||
mergeEndY = info.maxY
|
||||
} else {
|
||||
mergeStartY = info.minY
|
||||
mergeEndY = info.maxY
|
||||
}
|
||||
} else {
|
||||
// Flush any pending merged full-lines
|
||||
if let startY = mergeStartY, let endY = mergeEndY {
|
||||
maskRects.append(CGRect(x: 0.0, y: startY, width: layerSize.width, height: endY - startY))
|
||||
mergeStartY = nil
|
||||
mergeEndY = nil
|
||||
}
|
||||
// Add the partial line
|
||||
maskRects.append(info.maskFrame)
|
||||
}
|
||||
}
|
||||
// Flush trailing merged full-lines
|
||||
if let startY = mergeStartY, let endY = mergeEndY {
|
||||
maskRects.append(CGRect(x: 0.0, y: startY, width: layerSize.width, height: endY - startY))
|
||||
}
|
||||
|
||||
// Update mask child layers to match the number of rects
|
||||
while self.revealLineMaskLayers.count < maskRects.count {
|
||||
let childLayer = SimpleLayer()
|
||||
childLayer.backgroundColor = UIColor.white.cgColor
|
||||
revealMaskLayer.addSublayer(childLayer)
|
||||
self.revealLineMaskLayers.append(childLayer)
|
||||
}
|
||||
while self.revealLineMaskLayers.count > maskRects.count {
|
||||
let removed = self.revealLineMaskLayers.removeLast()
|
||||
removed.removeFromSuperlayer()
|
||||
}
|
||||
|
||||
for i in 0 ..< maskRects.count {
|
||||
self.revealLineMaskLayers[i].frame = maskRects[i]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2923,7 +3057,8 @@ final class TextContentItemLayer: SimpleLayer {
|
|||
}
|
||||
}
|
||||
|
||||
animation.animator.updateFrame(layer: self.renderNode.layer, frame: effectiveContentFrame, completion: nil)
|
||||
animation.animator.updateFrame(layer: self.renderNodeContainer, frame: effectiveContentFrame, completion: nil)
|
||||
animation.animator.updateFrame(layer: self.renderNode.layer, frame: CGRect(origin: CGPoint(), size: effectiveContentFrame.size), completion: nil)
|
||||
|
||||
var staticContentMask = contentMask
|
||||
if let contentMask, self.isAnimating {
|
||||
|
|
@ -3040,10 +3175,11 @@ final class TextContentItemLayer: SimpleLayer {
|
|||
|
||||
self.currentContentMask = contentMask
|
||||
|
||||
self.renderNode.params = RenderParams(size: contentFrame.size, item: params.item, mask: staticContentMask, maxGlyphDrawCount: self.maxGlyphDrawCount)
|
||||
self.renderNode.params = RenderParams(size: contentFrame.size, item: params.item, mask: staticContentMask)
|
||||
self.updateRevealMask()
|
||||
if synchronously {
|
||||
if let spoilerExpandRect, animation.isAnimated {
|
||||
let localSpoilerExpandRect = spoilerExpandRect.offsetBy(dx: -self.renderNode.frame.minX, dy: -self.renderNode.frame.minY)
|
||||
let localSpoilerExpandRect = spoilerExpandRect.offsetBy(dx: -self.renderNodeContainer.frame.minX, dy: -self.renderNodeContainer.frame.minY)
|
||||
|
||||
let revealAnimationDuration: CGFloat = 0.55
|
||||
|
||||
|
|
@ -3051,7 +3187,7 @@ final class TextContentItemLayer: SimpleLayer {
|
|||
|
||||
let previousContents = self.renderNode.layer.contents
|
||||
let copyContentsLayer = SimpleLayer()
|
||||
copyContentsLayer.frame = self.renderNode.frame
|
||||
copyContentsLayer.frame = self.renderNodeContainer.frame
|
||||
copyContentsLayer.contents = previousContents
|
||||
copyContentsLayer.masksToBounds = self.renderNode.layer.masksToBounds
|
||||
copyContentsLayer.contentsGravity = self.renderNode.layer.contentsGravity
|
||||
|
|
@ -3073,7 +3209,7 @@ final class TextContentItemLayer: SimpleLayer {
|
|||
|
||||
copyContentsLayer.addSublayer(copySublayer)
|
||||
}
|
||||
self.renderNode.layer.superlayer?.insertSublayer(copyContentsLayer, below: self.renderNode.layer)
|
||||
self.renderNodeContainer.superlayer?.insertSublayer(copyContentsLayer, below: self.renderNodeContainer)
|
||||
|
||||
self.renderNode.displayImmediately()
|
||||
|
||||
|
|
|
|||
|
|
@ -721,6 +721,12 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.leftButtonNodeImpl.requestUpdate = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.requestLayout()
|
||||
}
|
||||
|
||||
self.rightButtonNodeImpl.pressed = { [weak self] index in
|
||||
if let item = self?.item {
|
||||
|
|
@ -733,6 +739,12 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.rightButtonNodeImpl.requestUpdate = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.requestLayout()
|
||||
}
|
||||
}
|
||||
|
||||
public var isBackgroundVisible: Bool {
|
||||
|
|
@ -906,6 +918,9 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
case .accent:
|
||||
self.leftButtonNodeImpl.color = self.presentationData.theme.accentForegroundColor
|
||||
self.leftButtonNodeImpl.disabledColor = self.presentationData.theme.accentForegroundColor.withMultipliedAlpha(0.5)
|
||||
case .accentDisabled:
|
||||
self.leftButtonNodeImpl.color = self.presentationData.theme.accentForegroundColor
|
||||
self.leftButtonNodeImpl.disabledColor = self.presentationData.theme.accentForegroundColor.withMultipliedAlpha(0.5)
|
||||
case .generic:
|
||||
self.leftButtonNodeImpl.color = self.presentationData.theme.buttonColor
|
||||
self.leftButtonNodeImpl.disabledColor = self.presentationData.theme.disabledButtonColor
|
||||
|
|
@ -946,6 +961,9 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
case .accent:
|
||||
self.rightButtonNodeImpl.color = self.presentationData.theme.accentForegroundColor
|
||||
self.rightButtonNodeImpl.disabledColor = self.presentationData.theme.accentForegroundColor.withMultipliedAlpha(0.5)
|
||||
case .accentDisabled:
|
||||
self.rightButtonNodeImpl.color = self.presentationData.theme.accentForegroundColor
|
||||
self.rightButtonNodeImpl.disabledColor = self.presentationData.theme.accentForegroundColor.withMultipliedAlpha(0.5)
|
||||
case .generic:
|
||||
self.rightButtonNodeImpl.color = self.presentationData.theme.buttonColor
|
||||
self.rightButtonNodeImpl.disabledColor = self.presentationData.theme.disabledButtonColor
|
||||
|
|
@ -994,6 +1012,8 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
switch self.leftButtonNodeImpl.commonContentType {
|
||||
case .accent:
|
||||
leftButtonsColor = .init(kind: .custom(style: self.presentationData.theme.glassStyle == .clear ? .clear : .default, color: self.presentationData.theme.accentButtonColor))
|
||||
case .accentDisabled:
|
||||
leftButtonsColor = .init(kind: .custom(style: self.presentationData.theme.glassStyle == .clear ? .clear : .default, color: self.presentationData.theme.accentDisabledButtonColor))
|
||||
case .generic:
|
||||
break
|
||||
}
|
||||
|
|
@ -1028,6 +1048,8 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
switch self.rightButtonNodeImpl.commonContentType {
|
||||
case .accent:
|
||||
rightButtonsColor = .init(kind: .custom(style: self.presentationData.theme.glassStyle == .clear ? .clear : .default, color: self.presentationData.theme.accentButtonColor))
|
||||
case .accentDisabled:
|
||||
rightButtonsColor = .init(kind: .custom(style: self.presentationData.theme.glassStyle == .clear ? .clear : .default, color: self.presentationData.theme.accentDisabledButtonColor))
|
||||
case .generic:
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ private final class ItemComponent: Component {
|
|||
|
||||
private final class NavigationButtonItemNode: ImmediateTextNode {
|
||||
private let isGlass: Bool
|
||||
var requestUpdate: (() -> Void)?
|
||||
|
||||
private func fontForCurrentState() -> UIFont {
|
||||
return self.bold ? Font.semibold(17.0) : Font.medium(17.0)
|
||||
|
|
@ -235,7 +236,13 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
|
|||
|
||||
if let item = self.item {
|
||||
self.setEnabledListener = item.addSetEnabledListener { [weak self] value in
|
||||
self?.isEnabled = value
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if self.isEnabled != value {
|
||||
self.isEnabled = value
|
||||
self.requestUpdate?()
|
||||
}
|
||||
}
|
||||
self.accessibilityHint = item.accessibilityHint
|
||||
self.accessibilityLabel = item.accessibilityLabel
|
||||
|
|
@ -528,6 +535,7 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
|
|||
public final class NavigationButtonNodeImpl: ContextControllerSourceNode, NavigationButtonNode {
|
||||
enum ContentType {
|
||||
case accent
|
||||
case accentDisabled
|
||||
case generic
|
||||
}
|
||||
|
||||
|
|
@ -537,6 +545,8 @@ public final class NavigationButtonNodeImpl: ContextControllerSourceNode, Naviga
|
|||
private var items: [UIBarButtonItem] = []
|
||||
private var nodes: [NavigationButtonItemNode] = []
|
||||
|
||||
var requestUpdate: (() -> Void)?
|
||||
|
||||
private var disappearingNodes: [(frame: CGRect, size: CGSize, node: NavigationButtonItemNode)] = []
|
||||
|
||||
public var singleCustomNode: ASDisplayNode? {
|
||||
|
|
@ -633,6 +643,9 @@ public final class NavigationButtonNodeImpl: ContextControllerSourceNode, Naviga
|
|||
}
|
||||
}
|
||||
}
|
||||
node.requestUpdate = { [weak self] in
|
||||
self?.requestUpdate?()
|
||||
}
|
||||
self.nodes.append(node)
|
||||
self.addSubnode(node)
|
||||
}
|
||||
|
|
@ -680,6 +693,9 @@ public final class NavigationButtonNodeImpl: ContextControllerSourceNode, Naviga
|
|||
}
|
||||
}
|
||||
}
|
||||
node.requestUpdate = { [weak self] in
|
||||
self?.requestUpdate?()
|
||||
}
|
||||
self.nodes.append(node)
|
||||
self.addSubnode(node)
|
||||
}
|
||||
|
|
@ -812,7 +828,11 @@ public final class NavigationButtonNodeImpl: ContextControllerSourceNode, Naviga
|
|||
if item.title == "___close" {
|
||||
} else if item.title == "___clear" {
|
||||
} else if item.title == "___done" {
|
||||
nodeContentType = .accent
|
||||
if item.isEnabled {
|
||||
nodeContentType = .accent
|
||||
} else {
|
||||
nodeContentType = .accentDisabled
|
||||
}
|
||||
}
|
||||
|
||||
if commonType == nil {
|
||||
|
|
|
|||
|
|
@ -6459,6 +6459,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||
badgeStrokeColor: baseNavigationBarPresentationData.theme.badgeStrokeColor,
|
||||
badgeTextColor: baseNavigationBarPresentationData.theme.badgeTextColor,
|
||||
accentButtonColor: baseNavigationBarPresentationData.theme.accentButtonColor,
|
||||
accentDisabledButtonColor: baseNavigationBarPresentationData.theme.accentDisabledButtonColor,
|
||||
accentForegroundColor: baseNavigationBarPresentationData.theme.accentForegroundColor
|
||||
), strings: baseNavigationBarPresentationData.strings))
|
||||
|
||||
|
|
|
|||
|
|
@ -409,39 +409,45 @@ extension ChatControllerImpl {
|
|||
}
|
||||
})))
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Chat_CreateTopic, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] action in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
action.dismissWithResult(.default)
|
||||
|
||||
let controller = ForumCreateTopicScreen(context: self.context, peerId: peerId, mode: .create)
|
||||
controller.navigationPresentation = .modal
|
||||
|
||||
controller.completion = { [weak self, weak controller] title, fileId, iconColor, _ in
|
||||
controller?.isInProgress = true
|
||||
controller?.view.endEditing(true)
|
||||
|
||||
var canCreateTopics = false
|
||||
if let peer = self.presentationInterfaceState.renderedPeer?.chatMainPeer as? TelegramUser, let botInfo = peer.botInfo, botInfo.flags.contains(.forumManagedByUser) {
|
||||
canCreateTopics = true
|
||||
}
|
||||
if canCreateTopics {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Chat_CreateTopic, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] action in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = (self.context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: iconColor, iconFileId: fileId)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self, weak controller] topicId in
|
||||
action.dismissWithResult(.default)
|
||||
|
||||
let controller = ForumCreateTopicScreen(context: self.context, peerId: peerId, mode: .create)
|
||||
controller.navigationPresentation = .modal
|
||||
|
||||
controller.completion = { [weak self, weak controller] title, fileId, iconColor, _ in
|
||||
controller?.isInProgress = true
|
||||
controller?.view.endEditing(true)
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.updateChatLocationThread(threadId: topicId)
|
||||
controller?.dismiss()
|
||||
}, error: { _ in
|
||||
controller?.isInProgress = false
|
||||
})
|
||||
}
|
||||
self.push(controller)
|
||||
})))
|
||||
|
||||
let _ = (self.context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: iconColor, iconFileId: fileId)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self, weak controller] topicId in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.updateChatLocationThread(threadId: topicId)
|
||||
controller?.dismiss()
|
||||
}, error: { _ in
|
||||
controller?.isInProgress = false
|
||||
})
|
||||
}
|
||||
self.push(controller)
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
let presentationData = self.presentationData
|
||||
|
|
|
|||
|
|
@ -2281,78 +2281,112 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
guard let strongSelf else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, { current in
|
||||
var current = current
|
||||
current = current.updatedInterfaceState { interfaceState in
|
||||
var interfaceState = interfaceState
|
||||
interfaceState = interfaceState.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil).withUpdatedPostSuggestionState(nil)
|
||||
if clearInput {
|
||||
interfaceState = interfaceState.withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString()))
|
||||
}
|
||||
return interfaceState
|
||||
}.updatedInputMode { current in
|
||||
if case let .media(mode, maybeExpanded, focused) = current, maybeExpanded != nil {
|
||||
return .media(mode: mode, expanded: nil, focused: focused)
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
return current
|
||||
})
|
||||
}
|
||||
}, shouldAnimateMessageTransition ? correlationId : nil)
|
||||
|
||||
if shouldAnimateMessageTransition {
|
||||
if let sourceNode = sourceView?.asyncdisplaykit_node as? ChatMediaInputStickerGridItemNode {
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .stickerMediaInput(input: .inputPanel(itemNode: sourceNode), replyPanel: replyPanel), initiated: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, { current in
|
||||
var current = current
|
||||
current = current.updatedInputMode { current in
|
||||
if case let .media(mode, maybeExpanded, focused) = current, maybeExpanded != nil {
|
||||
return .media(mode: mode, expanded: nil, focused: focused)
|
||||
}
|
||||
return current
|
||||
let addToTransitionNodeIfNeeded: () -> Void = {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if shouldAnimateMessageTransition {
|
||||
if let sourceNode = sourceView?.asyncdisplaykit_node as? ChatMediaInputStickerGridItemNode {
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .stickerMediaInput(input: .inputPanel(itemNode: sourceNode), replyPanel: replyPanel), initiated: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
return current
|
||||
})
|
||||
})
|
||||
} else if let sourceNode = sourceView?.asyncdisplaykit_node as? HorizontalStickerGridItemNode {
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .stickerMediaInput(input: .mediaPanel(itemNode: sourceNode), replyPanel: replyPanel), initiated: {})
|
||||
} else if let sourceNode = sourceView?.asyncdisplaykit_node as? ChatEmptyNodeStickerContentNode {
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .stickerMediaInput(input: .emptyPanel(itemNode: sourceNode), replyPanel: nil), initiated: {})
|
||||
} else if let sourceLayer, let sourceView, let sourceRect {
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .stickerMediaInput(input: .universal(sourceContainerView: sourceView, sourceRect: sourceRect, sourceLayer: sourceLayer), replyPanel: replyPanel), initiated: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, { current in
|
||||
var current = current
|
||||
current = current.updatedInputMode { current in
|
||||
if case let .media(mode, maybeExpanded, focused) = current, maybeExpanded != nil {
|
||||
return .media(mode: mode, expanded: nil, focused: focused)
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, { current in
|
||||
var current = current
|
||||
current = current.updatedInputMode { current in
|
||||
if case let .media(mode, maybeExpanded, focused) = current, maybeExpanded != nil {
|
||||
return .media(mode: mode, expanded: nil, focused: focused)
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
return current
|
||||
}
|
||||
|
||||
return current
|
||||
})
|
||||
})
|
||||
})
|
||||
} else if let sourceNode = sourceView?.asyncdisplaykit_node as? HorizontalStickerGridItemNode {
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .stickerMediaInput(input: .mediaPanel(itemNode: sourceNode), replyPanel: replyPanel), initiated: {})
|
||||
} else if let sourceNode = sourceView?.asyncdisplaykit_node as? ChatEmptyNodeStickerContentNode {
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .stickerMediaInput(input: .emptyPanel(itemNode: sourceNode), replyPanel: nil), initiated: {})
|
||||
} else if let sourceLayer, let sourceView, let sourceRect {
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .stickerMediaInput(input: .universal(sourceContainerView: sourceView, sourceRect: sourceRect, sourceLayer: sourceLayer), replyPanel: replyPanel), initiated: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, { current in
|
||||
var current = current
|
||||
current = current.updatedInputMode { current in
|
||||
if case let .media(mode, maybeExpanded, focused) = current, maybeExpanded != nil {
|
||||
return .media(mode: mode, expanded: nil, focused: focused)
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
return current
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let messages: [EnqueueMessage] = [.message(text: "", attributes: attributes, inlineStickers: [:], mediaReference: fileReference.abstract, threadId: strongSelf.chatLocation.threadId, replyToMessageId: strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject?.subjectModel, replyToStoryId: nil, localGroupingKey: nil, correlationId: correlationId, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets)]
|
||||
let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||
|
||||
let messages: [EnqueueMessage] = [.message(text: "", attributes: attributes, inlineStickers: [:], mediaReference: fileReference.abstract, threadId: strongSelf.chatLocation.threadId, replyToMessageId: replyMessageSubject?.subjectModel, replyToStoryId: nil, localGroupingKey: nil, correlationId: correlationId, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets)]
|
||||
if silentPosting {
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, { current in
|
||||
var current = current
|
||||
current = current.updatedInterfaceState { interfaceState in
|
||||
var interfaceState = interfaceState
|
||||
interfaceState = interfaceState.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil).withUpdatedPostSuggestionState(nil)
|
||||
if clearInput {
|
||||
interfaceState = interfaceState.withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString()))
|
||||
}
|
||||
return interfaceState
|
||||
}.updatedInputMode { current in
|
||||
if case let .media(mode, maybeExpanded, focused) = current, maybeExpanded != nil {
|
||||
return .media(mode: mode, expanded: nil, focused: focused)
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
return current
|
||||
})
|
||||
}
|
||||
}, shouldAnimateMessageTransition ? correlationId : nil)
|
||||
|
||||
addToTransitionNodeIfNeeded()
|
||||
let transformedMessages = strongSelf.transformEnqueueMessages(messages, silentPosting: silentPosting, postpone: postpone)
|
||||
strongSelf.sendMessages(transformedMessages)
|
||||
} else if schedule {
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, { current in
|
||||
var current = current
|
||||
current = current.updatedInterfaceState { interfaceState in
|
||||
var interfaceState = interfaceState
|
||||
interfaceState = interfaceState.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil).withUpdatedPostSuggestionState(nil)
|
||||
if clearInput {
|
||||
interfaceState = interfaceState.withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString()))
|
||||
}
|
||||
return interfaceState
|
||||
}.updatedInputMode { current in
|
||||
if case let .media(mode, maybeExpanded, focused) = current, maybeExpanded != nil {
|
||||
return .media(mode: mode, expanded: nil, focused: focused)
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
return current
|
||||
})
|
||||
}
|
||||
}, shouldAnimateMessageTransition ? correlationId : nil)
|
||||
|
||||
strongSelf.presentScheduleTimePicker(completion: { [weak self] scheduleTime, repeatPeriod in
|
||||
if let strongSelf = self {
|
||||
let transformedMessages = strongSelf.transformEnqueueMessages(messages, silentPosting: false, scheduleTime: scheduleTime, repeatPeriod: repeatPeriod, postpone: postpone)
|
||||
|
|
@ -2360,8 +2394,90 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
}
|
||||
})
|
||||
} else {
|
||||
let transformedMessages = strongSelf.transformEnqueueMessages(messages, postpone: postpone)
|
||||
strongSelf.sendMessages(transformedMessages)
|
||||
let messages = strongSelf.transformEnqueueMessages(messages, postpone: postpone)
|
||||
|
||||
var targetThreadId: Int64?
|
||||
var clearMainThreadForward = false
|
||||
if strongSelf.chatLocation.threadId == nil, let user = strongSelf.presentationInterfaceState.renderedPeer?.peer as? TelegramUser, let botInfo = user.botInfo, botInfo.flags.contains(.hasForum), botInfo.flags.contains(.forumManagedByUser) {
|
||||
if let message = messages.first {
|
||||
switch message {
|
||||
case let .message(_, _, _, _, _, replyToMessageId, _, _, _, _):
|
||||
if let _ = replyToMessageId {
|
||||
if let replyMessage = strongSelf.presentationInterfaceState.replyMessage {
|
||||
targetThreadId = replyMessage.threadId
|
||||
}
|
||||
} else {
|
||||
targetThreadId = EngineMessage.newTopicThreadId
|
||||
}
|
||||
case let .forward(_, threadId, _, _, _):
|
||||
if let threadId {
|
||||
targetThreadId = threadId
|
||||
} else {
|
||||
targetThreadId = EngineMessage.newTopicThreadId
|
||||
clearMainThreadForward = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let doSend: (Int64?) -> Void = { [weak self] overrideThreadId in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
var messages = messages
|
||||
if let overrideThreadId {
|
||||
messages = messages.map { message in
|
||||
return message.withUpdatedThreadId(overrideThreadId)
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, { current in
|
||||
var current = current
|
||||
current = current.updatedInterfaceState { interfaceState in
|
||||
var interfaceState = interfaceState
|
||||
interfaceState = interfaceState.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil).withUpdatedPostSuggestionState(nil)
|
||||
if clearInput {
|
||||
interfaceState = interfaceState.withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString()))
|
||||
}
|
||||
return interfaceState
|
||||
}.updatedInputMode { current in
|
||||
if case let .media(mode, maybeExpanded, focused) = current, maybeExpanded != nil {
|
||||
return .media(mode: mode, expanded: nil, focused: focused)
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
return current
|
||||
})
|
||||
}
|
||||
}, shouldAnimateMessageTransition ? correlationId : nil)
|
||||
|
||||
addToTransitionNodeIfNeeded()
|
||||
|
||||
strongSelf.sendMessages(messages.map { $0.withUpdatedReplyToMessageId(replyMessageSubject?.subjectModel) })
|
||||
}
|
||||
|
||||
if let targetThreadId {
|
||||
strongSelf.chatDisplayNode.historyNode.stopHistoryUpdates()
|
||||
strongSelf.updateChatLocationThread(threadId: targetThreadId, animationDirection: .right, transferInputState: true, completion: { [weak strongSelf] in
|
||||
guard let strongSelf else {
|
||||
return
|
||||
}
|
||||
doSend(targetThreadId)
|
||||
if clearMainThreadForward, let peerId = strongSelf.chatLocation.peerId {
|
||||
let _ = ChatInterfaceState.update(engine: strongSelf.context.engine, peerId: peerId, threadId: nil, { current in
|
||||
return current.withUpdatedForwardMessageIds(nil)
|
||||
}).startStandalone()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
doSend(nil)
|
||||
}
|
||||
}
|
||||
})
|
||||
return true
|
||||
|
|
@ -8689,10 +8805,58 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
|
||||
mappedMessages.append(message)
|
||||
}
|
||||
|
||||
let messages = strongSelf.transformEnqueueMessages(mappedMessages, silentPosting: silentPosting, scheduleTime: scheduleTime, postpone: postpone)
|
||||
let replyMessageSubject = replyToSubject ?? strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||
|
||||
var targetThreadId: Int64?
|
||||
var clearMainThreadForward = false
|
||||
if strongSelf.chatLocation.threadId == nil, let user = strongSelf.presentationInterfaceState.renderedPeer?.peer as? TelegramUser, let botInfo = user.botInfo, botInfo.flags.contains(.hasForum), botInfo.flags.contains(.forumManagedByUser) {
|
||||
if let message = messages.first {
|
||||
switch message {
|
||||
case let .message(_, _, _, _, _, replyToMessageId, _, _, _, _):
|
||||
if let _ = replyToMessageId {
|
||||
if let replyMessage = strongSelf.presentationInterfaceState.replyMessage {
|
||||
targetThreadId = replyMessage.threadId
|
||||
}
|
||||
} else {
|
||||
targetThreadId = EngineMessage.newTopicThreadId
|
||||
}
|
||||
case let .forward(_, threadId, _, _, _):
|
||||
if let threadId {
|
||||
targetThreadId = threadId
|
||||
} else {
|
||||
targetThreadId = EngineMessage.newTopicThreadId
|
||||
clearMainThreadForward = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if addedTransitions.count > 1 {
|
||||
var transitions: [(Int64, ChatMessageTransitionNodeImpl.Source, () -> Void)] = []
|
||||
for (correlationId, uniqueIds, initiated) in addedTransitions {
|
||||
let addTransitionNodes: () -> Void = {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
if addedTransitions.count > 1 {
|
||||
var transitions: [(Int64, ChatMessageTransitionNodeImpl.Source, () -> Void)] = []
|
||||
for (correlationId, uniqueIds, initiated) in addedTransitions {
|
||||
var source: ChatMessageTransitionNodeImpl.Source?
|
||||
if uniqueIds.count > 1 {
|
||||
source = .groupedMediaInput(ChatMessageTransitionNodeImpl.Source.GroupedMediaInput(extractSnapshots: {
|
||||
return uniqueIds.compactMap({ getAnimatedTransitionSource?($0) })
|
||||
}))
|
||||
} else if let uniqueId = uniqueIds.first {
|
||||
source = .mediaInput(ChatMessageTransitionNodeImpl.Source.MediaInput(extractSnapshot: {
|
||||
return getAnimatedTransitionSource?(uniqueId)
|
||||
}))
|
||||
}
|
||||
if let source = source {
|
||||
transitions.append((correlationId, source, initiated))
|
||||
}
|
||||
}
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.add(grouped: transitions)
|
||||
} else if let (correlationId, uniqueIds, initiated) = addedTransitions.first {
|
||||
var source: ChatMessageTransitionNodeImpl.Source?
|
||||
if uniqueIds.count > 1 {
|
||||
source = .groupedMediaInput(ChatMessageTransitionNodeImpl.Source.GroupedMediaInput(extractSnapshots: {
|
||||
|
|
@ -8704,26 +8868,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
}))
|
||||
}
|
||||
if let source = source {
|
||||
transitions.append((correlationId, source, initiated))
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: source, initiated: {
|
||||
initiated()
|
||||
})
|
||||
}
|
||||
}
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.add(grouped: transitions)
|
||||
} else if let (correlationId, uniqueIds, initiated) = addedTransitions.first {
|
||||
var source: ChatMessageTransitionNodeImpl.Source?
|
||||
if uniqueIds.count > 1 {
|
||||
source = .groupedMediaInput(ChatMessageTransitionNodeImpl.Source.GroupedMediaInput(extractSnapshots: {
|
||||
return uniqueIds.compactMap({ getAnimatedTransitionSource?($0) })
|
||||
}))
|
||||
} else if let uniqueId = uniqueIds.first {
|
||||
source = .mediaInput(ChatMessageTransitionNodeImpl.Source.MediaInput(extractSnapshot: {
|
||||
return getAnimatedTransitionSource?(uniqueId)
|
||||
}))
|
||||
}
|
||||
if let source = source {
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: source, initiated: {
|
||||
initiated()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if case let .customChatContents(customChatContents) = strongSelf.presentationInterfaceState.subject, let messageLimit = customChatContents.messageLimit {
|
||||
|
|
@ -8740,21 +8889,50 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
let messages = strongSelf.transformEnqueueMessages(mappedMessages, silentPosting: silentPosting, scheduleTime: scheduleTime, postpone: postpone)
|
||||
let replyMessageSubject = replyToSubject ?? strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil).withUpdatedPostSuggestionState(nil) }
|
||||
})
|
||||
|
||||
let doSend: (Int64?) -> Void = { [weak strongSelf] overrideThreadId in
|
||||
guard let strongSelf else {
|
||||
return
|
||||
}
|
||||
completionImpl?()
|
||||
}, usedCorrelationId)
|
||||
|
||||
var messages = messages
|
||||
if let overrideThreadId {
|
||||
messages = messages.map { message in
|
||||
return message.withUpdatedThreadId(overrideThreadId)
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
||||
strongSelf.sendMessages(messages.map { $0.withUpdatedReplyToMessageId(replyMessageSubject?.subjectModel) }, media: true)
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil).withUpdatedPostSuggestionState(nil) }
|
||||
})
|
||||
}
|
||||
completionImpl?()
|
||||
}, usedCorrelationId)
|
||||
|
||||
addTransitionNodes()
|
||||
strongSelf.sendMessages(messages.map { $0.withUpdatedReplyToMessageId(replyMessageSubject?.subjectModel) }, media: true)
|
||||
}
|
||||
|
||||
if let targetThreadId {
|
||||
strongSelf.chatDisplayNode.historyNode.stopHistoryUpdates()
|
||||
strongSelf.updateChatLocationThread(threadId: targetThreadId, animationDirection: .right, transferInputState: true, completion: { [weak strongSelf] in
|
||||
guard let strongSelf else {
|
||||
return
|
||||
}
|
||||
doSend(targetThreadId)
|
||||
if clearMainThreadForward, let peerId = strongSelf.chatLocation.peerId {
|
||||
let _ = ChatInterfaceState.update(engine: strongSelf.context.engine, peerId: peerId, threadId: nil, { current in
|
||||
return current.withUpdatedForwardMessageIds(nil)
|
||||
}).startStandalone()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
doSend(nil)
|
||||
}
|
||||
|
||||
if let _ = scheduleTime {
|
||||
completion()
|
||||
|
|
|
|||
|
|
@ -2051,6 +2051,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
messageTransitionNode.transform = previousMessageTransitionNode.transform
|
||||
|
||||
previousMessageTransitionNode.supernode?.insertSubnode(self.messageTransitionNode, aboveSubnode: previousMessageTransitionNode)
|
||||
previousMessageTransitionNode.overlayContainerNode.supernode?.insertSubnode( self.messageTransitionNode.overlayContainerNode, aboveSubnode: previousMessageTransitionNode.overlayContainerNode)
|
||||
|
||||
self.emptyType = nil
|
||||
self.isLoadingValue = false
|
||||
|
|
|
|||
|
|
@ -484,8 +484,13 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||
guard let interfaceInteraction = interfaceInteraction, let controllerInteraction = controllerInteraction else {
|
||||
return .single(ContextController.Items(content: .list([])))
|
||||
}
|
||||
if let message = messages.first, message.id.namespace < 0 {
|
||||
return .single(ContextController.Items(content: .list([])))
|
||||
if let message = messages.first {
|
||||
if message.id.namespace < 0 {
|
||||
return .single(ContextController.Items(content: .list([])))
|
||||
}
|
||||
if message.id.namespace == Namespaces.Message.Local && message.attributes.contains(where: { $0 is TypingDraftMessageAttribute }) {
|
||||
return .single(ContextController.Items(content: .list([])))
|
||||
}
|
||||
}
|
||||
|
||||
var isEmbeddedMode = false
|
||||
|
|
|
|||
|
|
@ -78,6 +78,9 @@ func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Cha
|
|||
}
|
||||
|
||||
func rightNavigationButtonForChatInterfaceState(context: AccountContext, presentationInterfaceState: ChatPresentationInterfaceState, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?, chatInfoNavigationButton: ChatNavigationButton?, moreInfoNavigationButton: ChatNavigationButton?) -> ChatNavigationButton? {
|
||||
if case .standard(.previewing) = presentationInterfaceState.mode {
|
||||
return nil
|
||||
}
|
||||
var hasMessages = false
|
||||
if let chatHistoryState = presentationInterfaceState.chatHistoryState {
|
||||
if case .loaded(false, _) = chatHistoryState {
|
||||
|
|
|
|||
|
|
@ -388,9 +388,9 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran
|
|||
func beginAnimation() {
|
||||
if let portalTargetView = self.portalTargetView {
|
||||
portalTargetView.view.alpha = 0.0
|
||||
portalTargetView.view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15)
|
||||
portalTargetView.view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, delay: 0.15)
|
||||
|
||||
self.portalSourceView.layer.animateAlpha(from: 0.01, to: 1.0, duration: 0.12)
|
||||
self.portalSourceView.layer.animateAlpha(from: 0.01, to: 1.0, duration: 0.12, delay: 0.15)
|
||||
}
|
||||
|
||||
let verticalDuration: Double = ChatMessageTransitionNodeImpl.animationDuration
|
||||
|
|
|
|||
|
|
@ -797,7 +797,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
|
|||
messageText = NSAttributedString(string: foldLineBreaks(textString.string), font: textFont, textColor: message.media.isEmpty || message.media.first is TelegramMediaWebpage ? theme.chat.inputPanel.primaryTextColor : theme.chat.inputPanel.secondaryTextColor)
|
||||
}
|
||||
|
||||
let textConstrainedSize = CGSize(width: width - textLineInset - contentLeftInset - rightInset - textRightInset, height: CGFloat.greatestFiniteMagnitude)
|
||||
let textConstrainedSize = CGSize(width: width - textLineInset - contentLeftInset - rightInset - textRightInset - 10.0, height: CGFloat.greatestFiniteMagnitude)
|
||||
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: messageText, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets(top: 2.0, left: 0.0, bottom: 2.0, right: 0.0)))
|
||||
|
||||
let spoilerTextLayoutAndApply: (TextNodeLayout, (TextNodeWithEntities.Arguments?) -> TextNodeWithEntities)?
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ final class WebSearchGalleryControllerPresentationArguments {
|
|||
}
|
||||
|
||||
class WebSearchGalleryController: ViewController {
|
||||
private static let navigationTheme = NavigationBarTheme(overallDarkAppearance: false, buttonColor: .white, disabledButtonColor: UIColor(rgb: 0x525252), primaryTextColor: .white, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, accentButtonColor: .white, accentForegroundColor: .black)
|
||||
private static let navigationTheme = NavigationBarTheme(overallDarkAppearance: false, buttonColor: .white, disabledButtonColor: UIColor(rgb: 0x525252), primaryTextColor: .white, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, accentButtonColor: .white, accentDisabledButtonColor: .white, accentForegroundColor: .black)
|
||||
|
||||
private var galleryNode: GalleryControllerNode {
|
||||
return self.displayNode as! GalleryControllerNode
|
||||
|
|
|
|||
|
|
@ -3801,6 +3801,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||
badgeStrokeColor: .clear,
|
||||
badgeTextColor: .clear,
|
||||
accentButtonColor: self.presentationData.theme.list.itemCheckColors.fillColor,
|
||||
accentDisabledButtonColor: self.presentationData.theme.chat.inputPanel.panelControlDisabledColor,
|
||||
accentForegroundColor: self.presentationData.theme.list.itemCheckColors.foregroundColor
|
||||
),
|
||||
strings: NavigationBarStrings(back: "", close: "")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"app": "12.6.2",
|
||||
"app": "12.6.3",
|
||||
"xcode": "26.2",
|
||||
"deploy_xcode": "26.2",
|
||||
"bazel": "8.4.2:45e9388abf21d1107e146ea366ad080eb93cb6a5f3a4a3b048f78de0bc3faffa",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue