mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge commit 'ba1c3c09d8' into experimental-3
This commit is contained in:
commit
2f2880b34d
19 changed files with 314 additions and 51 deletions
|
|
@ -8079,3 +8079,4 @@ Sorry for the inconvenience.";
|
|||
|
||||
"PeerInfo.LabelAllReactions" = "All Reactions";
|
||||
|
||||
"TextFormat.Format" = "Format";
|
||||
|
|
|
|||
|
|
@ -1203,4 +1203,12 @@
|
|||
return 0;
|
||||
}
|
||||
|
||||
- (UIMenu *)textView:(UITextView *)textView editMenuForTextInRange:(NSRange)range suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions API_AVAILABLE(ios(16.0)) {
|
||||
if ([_delegate respondsToSelector:@selector(editableTextNodeMenu:forTextRange:suggestedActions:)]) {
|
||||
return [_delegate editableTextNodeMenu:self forTextRange:range suggestedActions:suggestedActions];
|
||||
} else {
|
||||
return [UIMenu menuWithChildren:suggestedActions];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -221,6 +221,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
- (BOOL)editableTextNodeShouldReturn:(ASEditableTextNode *)editableTextNode;
|
||||
- (void)editableTextNodeBackspaceWhileEmpty:(ASEditableTextNode *)editableTextNode;
|
||||
|
||||
|
||||
- (UIMenu *)editableTextNodeMenu:(ASEditableTextNode *)editableTextNode forTextRange:(NSRange)textRange suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions API_AVAILABLE(ios(16.0));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
|||
|
|
@ -1422,13 +1422,17 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
|||
else if action == makeSelectorFromString("_accessibilitySpeakLanguageSelection:") || action == makeSelectorFromString("_accessibilityPauseSpeaking:") || action == makeSelectorFromString("_accessibilitySpeakSentence:") {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
} else if action == makeSelectorFromString("_showTextStyleOptions:") {
|
||||
if case .general = self.inputMenu.state {
|
||||
if let textInputNode = self.textInputNode, textInputNode.attributedText == nil || textInputNode.attributedText!.length == 0 || textInputNode.selectedRange.length == 0 {
|
||||
if #available(iOS 16.0, *) {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
} else {
|
||||
if case .general = self.inputMenu.state {
|
||||
if let textInputNode = self.textInputNode, textInputNode.attributedText == nil || textInputNode.attributedText!.length == 0 || textInputNode.selectedRange.length == 0 {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
}
|
||||
return ASEditableTextNodeTargetForAction(target: self)
|
||||
} else {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
}
|
||||
return ASEditableTextNodeTargetForAction(target: self)
|
||||
} else {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
}
|
||||
} else if action == #selector(self.formatAttributesBold(_:)) || action == #selector(self.formatAttributesItalic(_:)) || action == #selector(self.formatAttributesMonospace(_:)) || action == #selector(self.formatAttributesLink(_:)) || action == #selector(self.formatAttributesStrikethrough(_:)) || action == #selector(self.formatAttributesUnderline(_:)) || action == #selector(self.formatAttributesSpoiler(_:)) {
|
||||
if case .format = self.inputMenu.state {
|
||||
|
|
@ -1443,6 +1447,65 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
|||
return nil
|
||||
}
|
||||
|
||||
@available(iOS 16.0, *)
|
||||
public func editableTextNodeMenu(_ editableTextNode: ASEditableTextNode, forTextRange textRange: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu {
|
||||
var actions = suggestedActions
|
||||
|
||||
if editableTextNode.attributedText == nil || editableTextNode.attributedText!.length == 0 || editableTextNode.selectedRange.length == 0 {
|
||||
|
||||
} else {
|
||||
var children: [UIAction] = [
|
||||
UIAction(title: self.strings?.TextFormat_Bold ?? "Bold", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesBold(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: self.strings?.TextFormat_Italic ?? "Italic", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesItalic(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: self.strings?.TextFormat_Monospace ?? "Monospace", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesMonospace(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: self.strings?.TextFormat_Link ?? "Link", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesLink(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: self.strings?.TextFormat_Strikethrough ?? "Strikethrough", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesStrikethrough(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: self.strings?.TextFormat_Underline ?? "Underline", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesUnderline(strongSelf)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
var hasSpoilers = true
|
||||
if self.presentationInterfaceState?.chatLocation.peerId?.namespace == Namespaces.Peer.SecretChat {
|
||||
hasSpoilers = false
|
||||
}
|
||||
|
||||
if hasSpoilers {
|
||||
children.append(UIAction(title: self.strings?.TextFormat_Spoiler ?? "Spoiler", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesSpoiler(strongSelf)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let formatMenu = UIMenu(title: self.strings?.TextFormat_Format ?? "Format", image: nil, children: children)
|
||||
actions.insert(formatMenu, at: 3)
|
||||
}
|
||||
return UIMenu(children: actions)
|
||||
}
|
||||
|
||||
@objc func _accessibilitySpeak(_ sender: Any) {
|
||||
var text = ""
|
||||
self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
|
||||
|
|
|
|||
|
|
@ -155,8 +155,8 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
|||
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .empty)).start()
|
||||
}
|
||||
})
|
||||
if let splahController = splashController {
|
||||
controller.animateWithSplashController(splahController)
|
||||
if let splashController = splashController {
|
||||
controller.animateWithSplashController(splashController)
|
||||
}
|
||||
controller.accountUpdated = { [weak self] updatedAccount in
|
||||
guard let strongSelf = self else {
|
||||
|
|
@ -1033,6 +1033,11 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
if let validLayout = self.validLayout, case .tablet = validLayout.deviceMetrics.type {
|
||||
previousSplashController = nil
|
||||
}
|
||||
|
||||
controllers.append(self.phoneEntryController(countryCode: countryCode, number: number, splashController: previousSplashController))
|
||||
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty && (previousSplashController == nil || self.viewControllers.count > 2))
|
||||
case let .confirmationCodeEntry(number, type, _, timeout, nextType, _):
|
||||
|
|
|
|||
|
|
@ -426,7 +426,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
|||
}
|
||||
|
||||
self.animationNode.completed = { [weak self] _ in
|
||||
self?.animationNode.isHidden = true
|
||||
self?.animationNode.removeFromSupernode()
|
||||
self?.managedAnimationNode.isHidden = false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1741,7 +1741,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
|
||||
if let _ = updatedTheme {
|
||||
strongSelf.separatorNode.backgroundColor = item.presentationData.theme.chatList.itemSeparatorColor
|
||||
strongSelf.highlightedBackgroundNode.backgroundColor = item.presentationData.theme.chatList.itemHighlightedBackgroundColor
|
||||
}
|
||||
|
||||
let revealOffset = strongSelf.revealOffset
|
||||
|
|
@ -2115,22 +2114,28 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
|
||||
transition.updateFrame(node: strongSelf.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.contentSize.width, height: itemHeight)))
|
||||
let backgroundColor: UIColor
|
||||
let highlightedBackgroundColor: UIColor
|
||||
if item.selected {
|
||||
backgroundColor = theme.itemSelectedBackgroundColor
|
||||
highlightedBackgroundColor = theme.itemHighlightedBackgroundColor
|
||||
} else if item.index.pinningIndex != nil {
|
||||
if case let .groupReference(_, _, _, _, hiddenByDefault) = item.content, hiddenByDefault {
|
||||
backgroundColor = theme.itemBackgroundColor
|
||||
highlightedBackgroundColor = theme.itemHighlightedBackgroundColor
|
||||
} else {
|
||||
backgroundColor = theme.pinnedItemBackgroundColor
|
||||
highlightedBackgroundColor = theme.pinnedItemHighlightedBackgroundColor
|
||||
}
|
||||
} else {
|
||||
backgroundColor = theme.itemBackgroundColor
|
||||
highlightedBackgroundColor = theme.itemHighlightedBackgroundColor
|
||||
}
|
||||
if animated {
|
||||
transition.updateBackgroundColor(node: strongSelf.backgroundNode, color: backgroundColor)
|
||||
} else {
|
||||
strongSelf.backgroundNode.backgroundColor = backgroundColor
|
||||
}
|
||||
strongSelf.highlightedBackgroundNode.backgroundColor = highlightedBackgroundColor
|
||||
let topNegativeInset: CGFloat = 0.0
|
||||
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: layoutOffset - separatorHeight - topNegativeInset), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height + separatorHeight + topNegativeInset))
|
||||
|
||||
|
|
|
|||
|
|
@ -426,14 +426,18 @@ public class CreatePollTextInputItemNode: ListViewItemNode, ASEditableTextNodeDe
|
|||
|
||||
public func editableTextNodeTarget(forAction action: Selector) -> ASEditableTextNodeTargetForAction? {
|
||||
if action == makeSelectorFromString("_showTextStyleOptions:") {
|
||||
if case .general = self.inputMenu.state {
|
||||
if self.textNode.attributedText == nil || self.textNode.attributedText!.length == 0 || self.textNode.selectedRange.length == 0 {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
}
|
||||
return ASEditableTextNodeTargetForAction(target: self)
|
||||
} else {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
}
|
||||
if #available(iOS 16.0, *) {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
} else {
|
||||
if case .general = self.inputMenu.state {
|
||||
if self.textNode.attributedText == nil || self.textNode.attributedText!.length == 0 || self.textNode.selectedRange.length == 0 {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
}
|
||||
return ASEditableTextNodeTargetForAction(target: self)
|
||||
} else {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
}
|
||||
}
|
||||
} else if action == #selector(self.formatAttributesBold(_:)) || action == #selector(self.formatAttributesItalic(_:)) || action == #selector(self.formatAttributesMonospace(_:)) || action == #selector(self.formatAttributesLink(_:)) || action == #selector(self.formatAttributesStrikethrough(_:)) || action == #selector(self.formatAttributesUnderline(_:)) {
|
||||
if case .format = self.inputMenu.state {
|
||||
return ASEditableTextNodeTargetForAction(target: self)
|
||||
|
|
@ -451,6 +455,58 @@ public class CreatePollTextInputItemNode: ListViewItemNode, ASEditableTextNodeDe
|
|||
self.inputMenu.format(view: self.textNode.view, rect: self.textNode.selectionRect.offsetBy(dx: 0.0, dy: -self.textNode.textView.contentOffset.y).insetBy(dx: 0.0, dy: -1.0))
|
||||
}
|
||||
|
||||
@available(iOS 16.0, *)
|
||||
public func editableTextNodeMenu(_ editableTextNode: ASEditableTextNode, forTextRange textRange: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu {
|
||||
var actions = suggestedActions
|
||||
|
||||
if editableTextNode.attributedText == nil || editableTextNode.attributedText!.length == 0 || editableTextNode.selectedRange.length == 0 {
|
||||
|
||||
} else if let strings = self.item?.presentationData.strings {
|
||||
let children: [UIAction] = [
|
||||
UIAction(title: strings.TextFormat_Bold, image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesBold(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: strings.TextFormat_Italic, image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesItalic(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: strings.TextFormat_Monospace, image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesMonospace(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: strings.TextFormat_Link, image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesLink(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: strings.TextFormat_Strikethrough, image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesStrikethrough(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: strings.TextFormat_Underline, image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesUnderline(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: strings.TextFormat_Spoiler, image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesSpoiler(strongSelf)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
let formatMenu = UIMenu(title: strings.TextFormat_Format, image: nil, children: children)
|
||||
actions.insert(formatMenu, at: 3)
|
||||
}
|
||||
|
||||
return UIMenu(children: actions)
|
||||
}
|
||||
|
||||
@objc func formatAttributesBold(_ sender: Any) {
|
||||
self.inputMenu.back()
|
||||
if let item = self.item {
|
||||
|
|
@ -491,6 +547,13 @@ public class CreatePollTextInputItemNode: ListViewItemNode, ASEditableTextNodeDe
|
|||
}
|
||||
}
|
||||
|
||||
@objc func formatAttributesSpoiler(_ sender: Any) {
|
||||
self.inputMenu.back()
|
||||
if let item = self.item {
|
||||
chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.spoiler)
|
||||
}
|
||||
}
|
||||
|
||||
public func editableTextNode(_ editableTextNode: ASEditableTextNode, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||
if let item = self.item {
|
||||
if text.count > 1, let processPaste = item.processPaste {
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||
private var globalOverlayContainerParent: GlobalOverlayContainerParent?
|
||||
public var globalOverlayControllersUpdated: (() -> Void)?
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
public private(set) var validLayout: ContainerViewLayout?
|
||||
private var validStatusBarStyle: NavigationStatusBarStyle?
|
||||
private var validStatusBarHidden: Bool = false
|
||||
|
||||
|
|
@ -1309,6 +1309,18 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||
completion()
|
||||
}
|
||||
|
||||
public func updateContainerPulled(_ pushed: Bool) {
|
||||
guard self.modalContainers.isEmpty else {
|
||||
return
|
||||
}
|
||||
if let rootContainer = self.rootContainer, case let .flat(container) = rootContainer {
|
||||
let scale: CGFloat = pushed ? 1.06 : 1.0
|
||||
|
||||
container.view.layer.transform = CATransform3DMakeScale(scale, scale, 1.0)
|
||||
container.view.layer.animateScale(from: pushed ? 1.0 : 1.06, to: scale, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
}
|
||||
}
|
||||
|
||||
open override func pushViewController(_ viewController: UIViewController, animated: Bool) {
|
||||
var controllers = self.viewControllers
|
||||
controllers.append(viewController)
|
||||
|
|
|
|||
|
|
@ -240,6 +240,8 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
|
||||
self.imageNode.imageUpdated = { [weak self] _ in
|
||||
self?._ready.set(.single(Void()))
|
||||
}
|
||||
|
|
@ -290,6 +292,11 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
return self._ready.get()
|
||||
}
|
||||
|
||||
override func screenFrameUpdated(_ frame: CGRect) {
|
||||
let center = frame.midX - self.frame.width / 2.0
|
||||
self.subnodeTransform = CATransform3DMakeTranslation(-center * 0.16, 0.0, 0.0)
|
||||
}
|
||||
|
||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
|
||||
|
|
|
|||
|
|
@ -814,6 +814,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
|
||||
self.moreBarButton.addTarget(self, action: #selector(self.moreButtonPressed), forControlEvents: .touchUpInside)
|
||||
|
||||
self.footerContentNode.interacting = { [weak self] value in
|
||||
|
|
@ -966,6 +968,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
return self._ready.get()
|
||||
}
|
||||
|
||||
|
||||
override func screenFrameUpdated(_ frame: CGRect) {
|
||||
let center = frame.midX - self.frame.width / 2.0
|
||||
self.subnodeTransform = CATransform3DMakeTranslation(-center * 0.16, 0.0, 0.0)
|
||||
}
|
||||
|
||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
if let _ = self.customUnembedWhenPortrait, layout.size.width < layout.size.height {
|
||||
self.expandIntoCustomPiP()
|
||||
|
|
|
|||
|
|
@ -465,7 +465,8 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati
|
|||
itemSeparatorColor: UIColor(rgb: 0x545458, alpha: 0.55),
|
||||
itemBackgroundColor: UIColor(rgb: 0x000000),
|
||||
pinnedItemBackgroundColor: UIColor(rgb: 0x1c1c1d),
|
||||
itemHighlightedBackgroundColor: UIColor(rgb: 0x191919),
|
||||
itemHighlightedBackgroundColor: UIColor(rgb: 0xffffff, alpha: 0.07),
|
||||
pinnedItemHighlightedBackgroundColor: UIColor(rgb: 0xffffff, alpha: 0.07),
|
||||
itemSelectedBackgroundColor: UIColor(rgb: 0x191919),
|
||||
titleColor: UIColor(rgb: 0xffffff),
|
||||
secretTitleColor: UIColor(rgb: 0x00b12c),
|
||||
|
|
|
|||
|
|
@ -685,6 +685,7 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres
|
|||
itemBackgroundColor: additionalBackgroundColor,
|
||||
pinnedItemBackgroundColor: mainBackgroundColor,
|
||||
itemHighlightedBackgroundColor: mainSelectionColor,
|
||||
pinnedItemHighlightedBackgroundColor: mainSelectionColor,
|
||||
itemSelectedBackgroundColor: mainSelectionColor,
|
||||
titleColor: UIColor(rgb: 0xffffff),
|
||||
secretTitleColor: UIColor(rgb: 0x89df9e),
|
||||
|
|
|
|||
|
|
@ -526,6 +526,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
|||
itemBackgroundColor: UIColor(rgb: 0xffffff),
|
||||
pinnedItemBackgroundColor: UIColor(rgb: 0xf7f7f7),
|
||||
itemHighlightedBackgroundColor: UIColor(rgb: 0xe5e5ea),
|
||||
pinnedItemHighlightedBackgroundColor: UIColor(rgb: 0xe5e5ea),
|
||||
itemSelectedBackgroundColor: UIColor(rgb: 0xe9f0fa),
|
||||
titleColor: UIColor(rgb: 0x000000),
|
||||
secretTitleColor: UIColor(rgb: 0x00b12c),
|
||||
|
|
|
|||
|
|
@ -561,6 +561,7 @@ public final class PresentationThemeChatList {
|
|||
public let itemBackgroundColor: UIColor
|
||||
public let pinnedItemBackgroundColor: UIColor
|
||||
public let itemHighlightedBackgroundColor: UIColor
|
||||
public let pinnedItemHighlightedBackgroundColor: UIColor
|
||||
public let itemSelectedBackgroundColor: UIColor
|
||||
public let titleColor: UIColor
|
||||
public let secretTitleColor: UIColor
|
||||
|
|
@ -597,6 +598,7 @@ public final class PresentationThemeChatList {
|
|||
itemBackgroundColor: UIColor,
|
||||
pinnedItemBackgroundColor: UIColor,
|
||||
itemHighlightedBackgroundColor: UIColor,
|
||||
pinnedItemHighlightedBackgroundColor: UIColor,
|
||||
itemSelectedBackgroundColor: UIColor,
|
||||
titleColor: UIColor,
|
||||
secretTitleColor: UIColor,
|
||||
|
|
@ -632,6 +634,7 @@ public final class PresentationThemeChatList {
|
|||
self.itemBackgroundColor = itemBackgroundColor
|
||||
self.pinnedItemBackgroundColor = pinnedItemBackgroundColor
|
||||
self.itemHighlightedBackgroundColor = itemHighlightedBackgroundColor
|
||||
self.pinnedItemHighlightedBackgroundColor = pinnedItemHighlightedBackgroundColor
|
||||
self.itemSelectedBackgroundColor = itemSelectedBackgroundColor
|
||||
self.titleColor = titleColor
|
||||
self.secretTitleColor = secretTitleColor
|
||||
|
|
@ -669,6 +672,7 @@ public final class PresentationThemeChatList {
|
|||
itemBackgroundColor: UIColor? = nil,
|
||||
pinnedItemBackgroundColor: UIColor? = nil,
|
||||
itemHighlightedBackgroundColor: UIColor? = nil,
|
||||
pinnedItemHighlightedBackgroundColor: UIColor? = nil,
|
||||
itemSelectedBackgroundColor: UIColor? = nil,
|
||||
titleColor: UIColor? = nil,
|
||||
secretTitleColor: UIColor? = nil,
|
||||
|
|
@ -705,6 +709,7 @@ public final class PresentationThemeChatList {
|
|||
itemBackgroundColor: itemBackgroundColor ?? self.itemBackgroundColor,
|
||||
pinnedItemBackgroundColor: pinnedItemBackgroundColor ?? self.pinnedItemBackgroundColor,
|
||||
itemHighlightedBackgroundColor: itemHighlightedBackgroundColor ?? self.itemHighlightedBackgroundColor,
|
||||
pinnedItemHighlightedBackgroundColor: pinnedItemHighlightedBackgroundColor ?? self.pinnedItemHighlightedBackgroundColor,
|
||||
itemSelectedBackgroundColor: itemSelectedBackgroundColor ?? self.itemSelectedBackgroundColor,
|
||||
titleColor: titleColor ?? self.titleColor,
|
||||
secretTitleColor: secretTitleColor ?? self.secretTitleColor,
|
||||
|
|
|
|||
|
|
@ -966,6 +966,7 @@ extension PresentationThemeChatList: Codable {
|
|||
case itemBg
|
||||
case pinnedItemBg
|
||||
case itemHighlightedBg
|
||||
case pinnedItemHighlightedBg
|
||||
case itemSelectedBg
|
||||
case title
|
||||
case secretTitle
|
||||
|
|
@ -1005,6 +1006,7 @@ extension PresentationThemeChatList: Codable {
|
|||
itemBackgroundColor: try decodeColor(values, .itemBg),
|
||||
pinnedItemBackgroundColor: try decodeColor(values, .pinnedItemBg),
|
||||
itemHighlightedBackgroundColor: try decodeColor(values, .itemHighlightedBg),
|
||||
pinnedItemHighlightedBackgroundColor: try decodeColor(values, .pinnedItemHighlightedBg, fallbackKey: "\(codingPath).itemHighlightedBg"),
|
||||
itemSelectedBackgroundColor: try decodeColor(values, .itemSelectedBg),
|
||||
titleColor: try decodeColor(values, .title),
|
||||
secretTitleColor: try decodeColor(values, .secretTitle),
|
||||
|
|
|
|||
|
|
@ -853,7 +853,43 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||
}
|
||||
|
||||
adjustedBoundingSize.width = max(boundingWidth, adjustedBoundingSize.width)
|
||||
|
||||
|
||||
var contentMediaHeight: CGFloat?
|
||||
if let (contentImageSize, _) = contentImageSizeAndApply {
|
||||
contentMediaHeight = contentImageSize.height
|
||||
}
|
||||
|
||||
if let (contentFileSize, _) = contentFileSizeAndApply {
|
||||
contentMediaHeight = contentFileSize.height
|
||||
}
|
||||
|
||||
if let (videoLayout, _) = contentInstantVideoSizeAndApply {
|
||||
contentMediaHeight = videoLayout.contentSize.height
|
||||
}
|
||||
|
||||
var textVerticalOffset: CGFloat = 0.0
|
||||
if let contentMediaHeight = contentMediaHeight, let (_, flags) = mediaAndFlags, flags.contains(.preferMediaBeforeText) {
|
||||
textVerticalOffset = contentMediaHeight + 7.0
|
||||
}
|
||||
let adjustedTextFrame = textFrame.offsetBy(dx: 0.0, dy: textVerticalOffset)
|
||||
|
||||
var statusFrame: CGRect?
|
||||
if let statusSizeAndApply = statusSizeAndApply {
|
||||
var finalStatusFrame = CGRect(origin: CGPoint(x: adjustedTextFrame.minX, y: adjustedTextFrame.maxY), size: statusSizeAndApply.0)
|
||||
if let imageFrame = imageFrame {
|
||||
if finalStatusFrame.maxY < imageFrame.maxY + 10.0 {
|
||||
finalStatusFrame.origin.y = max(finalStatusFrame.minY, imageFrame.maxY + 2.0)
|
||||
if finalStatusFrame.height == 0.0 {
|
||||
finalStatusFrame.origin.y += 14.0
|
||||
|
||||
adjustedBoundingSize.height += 14.0
|
||||
adjustedLineHeight += 14.0
|
||||
}
|
||||
}
|
||||
}
|
||||
statusFrame = finalStatusFrame
|
||||
}
|
||||
|
||||
return (adjustedBoundingSize, { [weak self] animation, synchronousLoads, applyInfo in
|
||||
if let strongSelf = self {
|
||||
strongSelf.context = context
|
||||
|
|
@ -900,12 +936,8 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||
} else if strongSelf.inlineImageNode.supernode != nil {
|
||||
strongSelf.inlineImageNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
var contentMediaHeight: CGFloat?
|
||||
|
||||
|
||||
if let (contentImageSize, contentImageApply) = contentImageSizeAndApply {
|
||||
contentMediaHeight = contentImageSize.height
|
||||
|
||||
let contentImageNode = contentImageApply(animation, synchronousLoads)
|
||||
if strongSelf.contentImageNode !== contentImageNode {
|
||||
strongSelf.contentImageNode = contentImageNode
|
||||
|
|
@ -960,8 +992,6 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||
}
|
||||
|
||||
if let (contentFileSize, contentFileApply) = contentFileSizeAndApply {
|
||||
contentMediaHeight = contentFileSize.height
|
||||
|
||||
let contentFileNode = contentFileApply(synchronousLoads, animation, applyInfo)
|
||||
if strongSelf.contentFileNode !== contentFileNode {
|
||||
strongSelf.contentFileNode = contentFileNode
|
||||
|
|
@ -988,7 +1018,6 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||
}
|
||||
|
||||
if let (videoLayout, apply) = contentInstantVideoSizeAndApply {
|
||||
contentMediaHeight = videoLayout.contentSize.height
|
||||
let contentInstantVideoNode = apply(.unconstrained(width: boundingWidth - insets.left - insets.right), animation)
|
||||
if strongSelf.contentInstantVideoNode !== contentInstantVideoNode {
|
||||
strongSelf.contentInstantVideoNode = contentInstantVideoNode
|
||||
|
|
@ -1003,23 +1032,9 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||
contentInstantVideoNode.removeFromSupernode()
|
||||
strongSelf.contentInstantVideoNode = nil
|
||||
}
|
||||
|
||||
var textVerticalOffset: CGFloat = 0.0
|
||||
if let contentMediaHeight = contentMediaHeight, let (_, flags) = mediaAndFlags, flags.contains(.preferMediaBeforeText) {
|
||||
textVerticalOffset = contentMediaHeight + 7.0
|
||||
}
|
||||
|
||||
strongSelf.textNode.textNode.frame = textFrame.offsetBy(dx: 0.0, dy: textVerticalOffset)
|
||||
if let statusSizeAndApply = statusSizeAndApply {
|
||||
var statusFrame = CGRect(origin: CGPoint(x: strongSelf.textNode.textNode.frame.minX, y: strongSelf.textNode.textNode.frame.maxY), size: statusSizeAndApply.0)
|
||||
if let imageFrame = imageFrame {
|
||||
if statusFrame.maxY < imageFrame.maxY + 10.0 {
|
||||
statusFrame.origin.y = max(statusFrame.minY, imageFrame.maxY + 2.0)
|
||||
if statusFrame.height == 0.0 {
|
||||
statusFrame.origin.y += 14.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.textNode.textNode.frame = adjustedTextFrame
|
||||
if let statusSizeAndApply = statusSizeAndApply, let statusFrame = statusFrame {
|
||||
if strongSelf.statusNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.statusNode)
|
||||
strongSelf.statusNode.frame = statusFrame
|
||||
|
|
|
|||
|
|
@ -2997,13 +2997,17 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||
else if action == makeSelectorFromString("_accessibilitySpeakLanguageSelection:") || action == makeSelectorFromString("_accessibilityPauseSpeaking:") || action == makeSelectorFromString("_accessibilitySpeakSentence:") {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
} else if action == makeSelectorFromString("_showTextStyleOptions:") {
|
||||
if case .general = self.inputMenu.state {
|
||||
if let textInputNode = self.textInputNode, textInputNode.attributedText == nil || textInputNode.attributedText!.length == 0 || textInputNode.selectedRange.length == 0 {
|
||||
if #available(iOS 16.0, *) {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
} else {
|
||||
if case .general = self.inputMenu.state {
|
||||
if let textInputNode = self.textInputNode, textInputNode.attributedText == nil || textInputNode.attributedText!.length == 0 || textInputNode.selectedRange.length == 0 {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
}
|
||||
return ASEditableTextNodeTargetForAction(target: self)
|
||||
} else {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
}
|
||||
return ASEditableTextNodeTargetForAction(target: self)
|
||||
} else {
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
}
|
||||
} else if action == #selector(self.formatAttributesBold(_:)) || action == #selector(self.formatAttributesItalic(_:)) || action == #selector(self.formatAttributesMonospace(_:)) || action == #selector(self.formatAttributesLink(_:)) || action == #selector(self.formatAttributesStrikethrough(_:)) || action == #selector(self.formatAttributesUnderline(_:)) || action == #selector(self.formatAttributesSpoiler(_:)) {
|
||||
if case .format = self.inputMenu.state {
|
||||
|
|
@ -3044,6 +3048,65 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||
return nil
|
||||
}
|
||||
|
||||
@available(iOS 16.0, *)
|
||||
func editableTextNodeMenu(_ editableTextNode: ASEditableTextNode, forTextRange textRange: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu {
|
||||
var actions = suggestedActions
|
||||
|
||||
if editableTextNode.attributedText == nil || editableTextNode.attributedText!.length == 0 || editableTextNode.selectedRange.length == 0 {
|
||||
|
||||
} else {
|
||||
var children: [UIAction] = [
|
||||
UIAction(title: self.strings?.TextFormat_Bold ?? "Bold", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesBold(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: self.strings?.TextFormat_Italic ?? "Italic", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesItalic(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: self.strings?.TextFormat_Monospace ?? "Monospace", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesMonospace(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: self.strings?.TextFormat_Link ?? "Link", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesLink(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: self.strings?.TextFormat_Strikethrough ?? "Strikethrough", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesStrikethrough(strongSelf)
|
||||
}
|
||||
},
|
||||
UIAction(title: self.strings?.TextFormat_Underline ?? "Underline", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesUnderline(strongSelf)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
var hasSpoilers = true
|
||||
if self.presentationInterfaceState?.chatLocation.peerId?.namespace == Namespaces.Peer.SecretChat {
|
||||
hasSpoilers = false
|
||||
}
|
||||
|
||||
if hasSpoilers {
|
||||
children.append(UIAction(title: self.strings?.TextFormat_Spoiler ?? "Spoiler", image: nil) { [weak self] (action) in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formatAttributesSpoiler(strongSelf)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let formatMenu = UIMenu(title: self.strings?.TextFormat_Format ?? "Format", image: nil, children: children)
|
||||
actions.insert(formatMenu, at: 3)
|
||||
}
|
||||
return UIMenu(children: actions)
|
||||
}
|
||||
|
||||
@objc func _accessibilitySpeak(_ sender: Any) {
|
||||
var text = ""
|
||||
self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
|
||||
|
|
|
|||
|
|
@ -745,7 +745,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
|
|||
|
||||
transition.updateAlpha(node: self.coveringBackgroundNode, alpha: expansionFraction)
|
||||
|
||||
self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor
|
||||
self.backgroundColor = presentationData.theme.list.plainBackgroundColor
|
||||
self.coveringBackgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.opaqueBackgroundColor, transition: .immediate)
|
||||
self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
|
||||
self.tabsSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue