Merge branch 'beta'

This commit is contained in:
Ilya Laktyushin 2019-08-10 04:43:55 +03:00
commit cfcfd5e13b
35 changed files with 651 additions and 578 deletions

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>5.10</string>
<string>5.10.1</string>
<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>NSExtension</key>

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>5.10</string>
<string>5.10.1</string>
<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>NSExtension</key>

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>5.10</string>
<string>5.10.1</string>
<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>NSExtension</key>
@ -31,15 +31,15 @@
SUBQUERY (
$extensionItem.attachments,
$attachment,
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO &quot;public.file-url&quot; ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO &quot;public.movie&quot; ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO &quot;public.image&quot; ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO &quot;public.url&quot; ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO &quot;public.text&quot; ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO &quot;public.audio&quot; ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO &quot;public.data&quot; ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO &quot;public.vcard&quot; ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO &quot;com.apple.pkpass&quot;
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.file-url" ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.movie" ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.image" ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url" ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.text" ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.audio" ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.data" ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.vcard" ||
ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "com.apple.pkpass"
).@count == $extensionItem.attachments.@count
).@count &gt; 0</string>
</dict>

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>5.10</string>
<string>5.10.1</string>
<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>NSExtension</key>

View File

@ -185,7 +185,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>5.10</string>
<string>5.10.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>5.10</string>
<string>5.10.1</string>
<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>UISupportedInterfaceOrientations</key>

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>5.10</string>
<string>5.10.1</string>
<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>NSExtension</key>

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>5.10</string>
<string>5.10.1</string>
<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>NSExtension</key>

View File

@ -13,6 +13,7 @@ public class ImmediateTextNode: TextNode {
public var maximumNumberOfLines: Int = 1
public var lineSpacing: CGFloat = 0.0
public var insets: UIEdgeInsets = UIEdgeInsets()
public var textShadowColor: UIColor?
private var tapRecognizer: TapLongTapOrDoubleTapGestureRecognizer?
private var linkHighlightingNode: LinkHighlightingNode?
@ -34,7 +35,7 @@ public class ImmediateTextNode: TextNode {
public func updateLayout(_ constrainedSize: CGSize) -> CGSize {
let makeLayout = TextNode.asyncLayout(self)
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, lineSpacing: self.lineSpacing, cutout: nil, insets: self.insets))
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, lineSpacing: self.lineSpacing, cutout: nil, insets: self.insets, textShadowColor: self.textShadowColor))
let _ = apply()
if layout.numberOfLines > 1 {
self.trailingLineWidth = layout.trailingLineWidth

View File

@ -275,7 +275,14 @@ open class NavigationController: UINavigationController, ContainableController,
return (CGRect(origin: CGPoint(), size: detailFrame.size), ContainerViewLayout(size: CGSize(width: detailWidth, height: layout.size.height), metrics: LayoutMetrics(widthClass: .regular, heightClass: .regular), intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver))
}
case .single:
return (CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: layout.size.height)), ContainerViewLayout(size: CGSize(width: layout.size.width, height: layout.size.height), metrics: LayoutMetrics(widthClass: .compact, heightClass: layout.size.height > 900.0 ? .regular : .compact), intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver))
var heightClass: ContainerViewLayoutSizeClass
if (layout.size.width < 375.0 && layout.size.height > 700.0) || layout.size.height > 900.0 {
heightClass = .regular
} else {
heightClass = .compact
}
return (CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: layout.size.height)), ContainerViewLayout(size: CGSize(width: layout.size.width, height: layout.size.height), metrics: LayoutMetrics(widthClass: .compact, heightClass: heightClass), intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver))
}
}
@ -296,10 +303,7 @@ open class NavigationController: UINavigationController, ContainableController,
self.controllerView.addSubview(self.controllerView.separatorView)
}
//let navigationBackgroundFrame = CGRect(origin: CGPoint(x: masterData.0.maxX, y: 0.0), size: CGSize(width: lastControllerFrameAndLayout.0.width, height: (layout.statusBarHeight ?? 0.0) + 44.0))
if let backgroundDetailsMode = self.backgroundDetailsMode {
switch backgroundDetailsMode {
case let .image(image):
if let detailsBackground = self.controllerView.detailsBackground {
@ -347,7 +351,6 @@ open class NavigationController: UINavigationController, ContainableController,
transition.updateAlpha(node: detailsBackground, alpha: 1.0)
detailsBackground.frame = CGRect(origin: CGPoint(x: masterData.0.maxX, y: 0.0), size: lastControllerFrameAndLayout.0.size)
}
} else {
if let emptyDetailView = self.controllerView.emptyDetailView {
self.controllerView.emptyDetailView = nil

View File

@ -92,8 +92,9 @@ public final class TextNodeLayoutArguments {
public let cutout: TextNodeCutout?
public let insets: UIEdgeInsets
public let lineColor: UIColor?
public let textShadowColor: UIColor?
public init(attributedString: NSAttributedString?, backgroundColor: UIColor? = nil, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, constrainedSize: CGSize, alignment: NSTextAlignment = .natural, lineSpacing: CGFloat = 0.12, cutout: TextNodeCutout? = nil, insets: UIEdgeInsets = UIEdgeInsets(), lineColor: UIColor? = nil) {
public init(attributedString: NSAttributedString?, backgroundColor: UIColor? = nil, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, constrainedSize: CGSize, alignment: NSTextAlignment = .natural, lineSpacing: CGFloat = 0.12, cutout: TextNodeCutout? = nil, insets: UIEdgeInsets = UIEdgeInsets(), lineColor: UIColor? = nil, textShadowColor: UIColor? = nil) {
self.attributedString = attributedString
self.backgroundColor = backgroundColor
self.maximumNumberOfLines = maximumNumberOfLines
@ -104,6 +105,7 @@ public final class TextNodeLayoutArguments {
self.cutout = cutout
self.insets = insets
self.lineColor = lineColor
self.textShadowColor = textShadowColor
}
}
@ -123,9 +125,10 @@ public final class TextNodeLayout: NSObject {
fileprivate let lines: [TextNodeLine]
fileprivate let blockQuotes: [TextNodeBlockQuote]
fileprivate let lineColor: UIColor?
fileprivate let textShadowColor: UIColor?
public let hasRTL: Bool
fileprivate init(attributedString: NSAttributedString?, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, constrainedSize: CGSize, alignment: NSTextAlignment, lineSpacing: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, size: CGSize, truncated: Bool, firstLineOffset: CGFloat, lines: [TextNodeLine], blockQuotes: [TextNodeBlockQuote], backgroundColor: UIColor?, lineColor: UIColor?) {
fileprivate init(attributedString: NSAttributedString?, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, constrainedSize: CGSize, alignment: NSTextAlignment, lineSpacing: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, size: CGSize, truncated: Bool, firstLineOffset: CGFloat, lines: [TextNodeLine], blockQuotes: [TextNodeBlockQuote], backgroundColor: UIColor?, lineColor: UIColor?, textShadowColor: UIColor?) {
self.attributedString = attributedString
self.maximumNumberOfLines = maximumNumberOfLines
self.truncationType = truncationType
@ -141,6 +144,7 @@ public final class TextNodeLayout: NSObject {
self.blockQuotes = blockQuotes
self.backgroundColor = backgroundColor
self.lineColor = lineColor
self.textShadowColor = textShadowColor
var hasRTL = false
for line in lines {
if line.isRTL {
@ -575,7 +579,7 @@ public class TextNode: ASDisplayNode {
}
}
private class func calculateLayout(attributedString: NSAttributedString?, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, backgroundColor: UIColor?, constrainedSize: CGSize, alignment: NSTextAlignment, lineSpacingFactor: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, lineColor: UIColor?) -> TextNodeLayout {
private class func calculateLayout(attributedString: NSAttributedString?, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, backgroundColor: UIColor?, constrainedSize: CGSize, alignment: NSTextAlignment, lineSpacingFactor: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, lineColor: UIColor?, textShadowColor: UIColor?) -> TextNodeLayout {
if let attributedString = attributedString {
let stringLength = attributedString.length
@ -601,7 +605,7 @@ public class TextNode: ASDisplayNode {
var maybeTypesetter: CTTypesetter?
maybeTypesetter = CTTypesetterCreateWithAttributedString(attributedString as CFAttributedString)
if maybeTypesetter == nil {
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, alignment: alignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor)
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, alignment: alignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor)
}
let typesetter = maybeTypesetter!
@ -793,9 +797,9 @@ public class TextNode: ASDisplayNode {
}
}
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, alignment: alignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(width: ceil(layoutSize.width) + insets.left + insets.right, height: ceil(layoutSize.height) + insets.top + insets.bottom), truncated: truncated, firstLineOffset: firstLineOffset, lines: lines, blockQuotes: blockQuotes, backgroundColor: backgroundColor, lineColor: lineColor)
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, alignment: alignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(width: ceil(layoutSize.width) + insets.left + insets.right, height: ceil(layoutSize.height) + insets.top + insets.bottom), truncated: truncated, firstLineOffset: firstLineOffset, lines: lines, blockQuotes: blockQuotes, backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor)
} else {
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, alignment: alignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor)
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, alignment: alignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor)
}
}
@ -828,11 +832,15 @@ public class TextNode: ASDisplayNode {
context.fill(bounds)
}
if let textShadowColor = layout.textShadowColor {
context.setTextDrawingMode(.fill)
context.setShadow(offset: CGSize(width: 0.0, height: 1.0), blur: 0.0, color: textShadowColor.cgColor)
}
let textMatrix = context.textMatrix
let textPosition = context.textPosition
context.textMatrix = CGAffineTransform(scaleX: 1.0, y: -1.0)
let alignment = layout.alignment
let offset = CGPoint(x: layout.insets.left, y: layout.insets.top)
@ -927,11 +935,11 @@ public class TextNode: ASDisplayNode {
if stringMatch {
layout = existingLayout
} else {
layout = TextNode.calculateLayout(attributedString: arguments.attributedString, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor)
layout = TextNode.calculateLayout(attributedString: arguments.attributedString, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor, textShadowColor: arguments.textShadowColor)
updated = true
}
} else {
layout = TextNode.calculateLayout(attributedString: arguments.attributedString, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor)
layout = TextNode.calculateLayout(attributedString: arguments.attributedString, maximumNumberOfLines: arguments.maximumNumberOfLines, truncationType: arguments.truncationType, backgroundColor: arguments.backgroundColor, constrainedSize: arguments.constrainedSize, alignment: arguments.alignment, lineSpacingFactor: arguments.lineSpacing, cutout: arguments.cutout, insets: arguments.insets, lineColor: arguments.lineColor, textShadowColor: arguments.textShadowColor)
updated = true
}

View File

@ -166,6 +166,7 @@ private func chatMessageStickerThumbnailData(postbox: Postbox, file: TelegramMed
return Signal { subscriber in
let fetchThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start()
let disposable = (thumbnailData
|> map { thumbnailData -> Data? in
return thumbnailData.complete ? try? Data(contentsOf: URL(fileURLWithPath: thumbnailData.path)) : nil
@ -230,6 +231,7 @@ private func chatMessageStickerPackThumbnailData(postbox: Postbox, resource: Med
public func chatMessageAnimationData(postbox: Postbox, resource: MediaResource, fitzModifier: EmojiFitzModifier? = nil, width: Int, height: Int, synchronousLoad: Bool) -> Signal<MediaResourceData, NoError> {
let representation = CachedAnimatedStickerRepresentation(width: Int32(width), height: Int32(height), fitzModifier: fitzModifier)
let maybeFetched = postbox.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: false, fetch: false, attemptSynchronously: synchronousLoad)
return maybeFetched
|> take(1)
|> mapToSignal { maybeData in

View File

@ -324,9 +324,13 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
)
}
public let defaultDarkAccentPresentationTheme = makeDarkAccentPresentationTheme(accentColor: UIColor(rgb: 0x2ea6ff), baseColor: .blue, preview: false)
public let defaultDarkAccentColor = UIColor(rgb: 0x2ea6ff)
public let defaultDarkAccentPresentationTheme = makeDarkAccentPresentationTheme(accentColor: UIColor(rgb: 0x2ea6ff), preview: false)
public func makeDarkAccentPresentationTheme(accentColor: UIColor?, baseColor: PresentationThemeBaseColor?, preview: Bool) -> PresentationTheme {
let accentColor = accentColor ?? defaultDayAccentColor
return makeDarkPresentationTheme(accentColor: accentColor, baseColor: baseColor, preview: preview)
public func makeDarkAccentPresentationTheme(accentColor: UIColor?, preview: Bool) -> PresentationTheme {
var accentColor = accentColor ?? defaultDarkAccentColor
if accentColor == PresentationThemeBaseColor.blue.color {
accentColor = defaultDarkAccentColor
}
return makeDarkPresentationTheme(accentColor: accentColor, preview: preview)
}

View File

@ -205,7 +205,6 @@ public final class PrincipalThemeEssentialGraphics {
self.chatMessageBackgroundOutgoingImage = messageBubbleImage(incoming: false, fillColor: outgoing.fill, strokeColor: outgoing.stroke, neighbors: .none, theme: theme, wallpaper: wallpaper, knockout: outgoingKnockout)
self.checkBubbleFullImage = generateCheckImage(partial: false, color: theme.message.outgoingCheckColor)!
self.checkBubblePartialImage = generateCheckImage(partial: true, color: theme.message.outgoingCheckColor)!
self.chatMessageBackgroundIncomingHighlightedImage = emptyImage
self.chatMessageBackgroundIncomingMergedTopImage = emptyImage
self.chatMessageBackgroundIncomingMergedTopHighlightedImage = emptyImage

View File

@ -15,11 +15,6 @@ let colorKeyRegex = try? NSRegularExpression(pattern: "\"k\":\\[[\\d\\.]+\\,[\\d
private func transformedWithFitzModifier(data: Data, fitzModifier: EmojiFitzModifier?) -> Data {
if let fitzModifier = fitzModifier, var string = String(data: data, encoding: .utf8) {
let color1: UIColor
let color2: UIColor
let color3: UIColor
let color4: UIColor
var colors: [UIColor] = [0xf77e41, 0xffb139, 0xffd140, 0xffdf79].map { UIColor(rgb: $0) }
let replacementColors: [UIColor]
switch fitzModifier {

View File

@ -881,7 +881,7 @@ public func channelInfoController(context: AccountContext, peerId: PeerId) -> Vi
}, reportChannel: {
presentControllerImpl?(peerReportOptionsController(context: context, subject: .peer(peerId), present: { c, a in
presentControllerImpl?(c, a)
}), nil)
}, completion: { _ in }), nil)
}, leaveChannel: {
let _ = (context.account.postbox.transaction { transaction -> Peer? in
return transaction.getPeer(peerId)

View File

@ -2748,14 +2748,14 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
if let strongSelf = self, let messageIds = strongSelf.presentationInterfaceState.interfaceState.selectionState?.selectedIds, !messageIds.isEmpty {
strongSelf.present(peerReportOptionsController(context: strongSelf.context, subject: .messages(Array(messageIds).sorted()), present: { c, a in
self?.present(c, in: .window(.root), with: a)
}), in: .window(.root))
}, completion: { _ in }), in: .window(.root))
}
}, reportMessages: { [weak self] messages in
if let strongSelf = self, !messages.isEmpty {
strongSelf.chatDisplayNode.dismissInput()
strongSelf.present(peerReportOptionsController(context: strongSelf.context, subject: .messages(messages.map({ $0.id }).sorted()), present: { c, a in
self?.present(c, in: .window(.root), with: a)
}), in: .window(.root))
}, completion: { _ in }), in: .window(.root))
}
}, deleteMessages: { [weak self] messages in
if let strongSelf = self, !messages.isEmpty {
@ -3443,7 +3443,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
}
if canManagePin {
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Conversation_UnpinMessageAlert, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_No, action: {}), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Yes, action: {
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Conversation_UnpinMessageAlert, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Conversation_Unpin, action: {
if let strongSelf = self {
let disposable: MetaDisposable
if let current = strongSelf.unpinMessageDisposable {
@ -6255,6 +6255,12 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
if let peer = peer as? TelegramChannel, let username = peer.username, !username.isEmpty {
self.present(peerReportOptionsController(context: self.context, subject: .peer(peer.id), present: { [weak self] c, a in
self?.present(c, in: .window(.root))
}, completion: { [weak self] success in
guard let strongSelf = self, success else {
return
}
let _ = removePeerChat(account: strongSelf.context.account, peerId: chatPeer.id, reportChatSpam: false).start()
(strongSelf.navigationController as? NavigationController)?.filterController(strongSelf, animated: true)
}), in: .window(.root))
} else if let _ = peer as? TelegramUser {
let presentationData = self.presentationData

View File

@ -90,7 +90,7 @@ private func updatedContextQueryResultStateForQuery(context: AccountContext, pee
case .installed:
scope = [.installed]
}
return searchStickers(account: context.account, query: query.trimmedEmoji, scope: scope)
return searchStickers(account: context.account, query: query.basicEmoji.0, scope: scope)
|> introduceError(ChatContextQueryError.self)
}
|> map { stickers -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in

View File

@ -172,7 +172,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
private let messageContextDisposable = MetaDisposable()
private var videoFramePreviewNode: ASImageNode?
private var videoFramePreviewNode: (ASImageNode, ImmediateTextNode)?
private var validLayout: (CGSize, LayoutMetrics, CGFloat, CGFloat, CGFloat, CGFloat)?
@ -235,6 +235,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
}
private var scrubbingHandleRelativePosition: CGFloat = 0.0
private var scrubbingVisualTimestamp: Double?
var scrubberView: ChatVideoGalleryItemScrubberView? = nil {
willSet {
@ -245,6 +246,23 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
didSet {
if let scrubberView = self.scrubberView {
self.view.addSubview(scrubberView)
scrubberView.updateScrubbingVisual = { [weak self] value in
guard let strongSelf = self else {
return
}
if let value = value {
strongSelf.scrubbingVisualTimestamp = value
if let (videoFramePreviewNode, videoFrameTextNode) = strongSelf.videoFramePreviewNode {
videoFrameTextNode.attributedText = NSAttributedString(string: stringForDuration(Int32(value)), font: Font.regular(13.0), textColor: .white)
let textSize = videoFrameTextNode.updateLayout(CGSize(width: 100.0, height: 100.0))
let imageFrame = videoFramePreviewNode.frame
let textOffset = (Int((imageFrame.size.width - videoFrameTextNode.bounds.width) / 2) / 2) * 2
videoFrameTextNode.frame = CGRect(origin: CGPoint(x: CGFloat(textOffset), y: imageFrame.size.height - videoFrameTextNode.bounds.height - 5.0), size: textSize)
}
} else {
strongSelf.scrubbingVisualTimestamp = nil
}
}
scrubberView.updateScrubbingHandlePosition = { [weak self] value in
guard let strongSelf = self else {
return
@ -643,15 +661,31 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.dateNode.frame = CGRect(origin: CGPoint(x: floor((width - dateSize.width) / 2.0), y: panelHeight - bottomInset - 44.0 + floor((44.0 - dateSize.height - authorNameSize.height - labelsSpacing) / 2.0) + authorNameSize.height + labelsSpacing), size: dateSize)
}
if let videoFramePreviewNode = self.videoFramePreviewNode {
if let (videoFramePreviewNode, videoFrameTextNode) = self.videoFramePreviewNode {
let intrinsicImageSize = videoFramePreviewNode.image?.size ?? CGSize(width: 320.0, height: 240.0)
let imageSize = intrinsicImageSize.aspectFitted(CGSize(width: 200.0, height: 200.0))
var imageFrame = CGRect(origin: CGPoint(x: leftInset + floor(self.scrubbingHandleRelativePosition * (width - leftInset - rightInset) - imageSize.width / 2.0), y: self.scrollNode.frame.minY - 10.0 - imageSize.height), size: imageSize)
let fitSize: CGSize
if intrinsicImageSize.width < intrinsicImageSize.height {
fitSize = CGSize(width: 90.0, height: 160.0)
} else {
fitSize = CGSize(width: 160.0, height: 90.0)
}
let scrubberInset: CGFloat
if size.width > size.height {
scrubberInset = 58.0
} else {
scrubberInset = 13.0
}
let imageSize = intrinsicImageSize.aspectFitted(fitSize)
var imageFrame = CGRect(origin: CGPoint(x: leftInset + scrubberInset + floor(self.scrubbingHandleRelativePosition * (width - leftInset - rightInset - scrubberInset * 2.0) - imageSize.width / 2.0), y: self.scrollNode.frame.minY - 6.0 - imageSize.height), size: imageSize)
imageFrame.origin.x = min(imageFrame.origin.x, width - rightInset - 10.0 - imageSize.width)
imageFrame.origin.x = max(imageFrame.origin.x, leftInset + 10.0)
videoFramePreviewNode.frame = imageFrame
videoFramePreviewNode.subnodes?.first?.frame = CGRect(origin: CGPoint(), size: imageFrame.size)
let textOffset = (Int((imageFrame.size.width - videoFrameTextNode.bounds.width) / 2) / 2) * 2
videoFrameTextNode.frame = CGRect(origin: CGPoint(x: CGFloat(textOffset), y: imageFrame.size.height - videoFrameTextNode.bounds.height - 5.0), size: videoFrameTextNode.bounds.size)
}
return panelHeight
@ -1028,7 +1062,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
}
func setFramePreviewImageIsLoading() {
if self.videoFramePreviewNode?.image != nil {
if self.videoFramePreviewNode?.0.image != nil {
//self.videoFramePreviewNode?.subnodes?.first?.alpha = 1.0
}
}
@ -1036,17 +1070,34 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
func setFramePreviewImage(image: UIImage?) {
if let image = image {
let videoFramePreviewNode: ASImageNode
let videoFrameTextNode: ImmediateTextNode
var animateIn = false
if let current = self.videoFramePreviewNode {
videoFramePreviewNode = current
videoFramePreviewNode = current.0
videoFrameTextNode = current.1
} else {
videoFramePreviewNode = ASImageNode()
videoFramePreviewNode.displaysAsynchronously = false
videoFramePreviewNode.displayWithoutProcessing = true
videoFramePreviewNode.clipsToBounds = true
videoFramePreviewNode.cornerRadius = 6.0
let dimNode = ASDisplayNode()
dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
videoFramePreviewNode.addSubnode(dimNode)
self.videoFramePreviewNode = videoFramePreviewNode
videoFrameTextNode = ImmediateTextNode()
videoFrameTextNode.displaysAsynchronously = false
videoFrameTextNode.maximumNumberOfLines = 1
videoFrameTextNode.textShadowColor = .black
if let scrubbingVisualTimestamp = self.scrubbingVisualTimestamp {
videoFrameTextNode.attributedText = NSAttributedString(string: stringForDuration(Int32(scrubbingVisualTimestamp)), font: Font.regular(13.0), textColor: .white)
}
let textSize = videoFrameTextNode.updateLayout(CGSize(width: 100.0, height: 100.0))
videoFrameTextNode.frame = CGRect(origin: CGPoint(), size: textSize)
videoFramePreviewNode.addSubnode(videoFrameTextNode)
self.videoFramePreviewNode = (videoFramePreviewNode, videoFrameTextNode)
self.addSubnode(videoFramePreviewNode)
animateIn = true
}
@ -1059,7 +1110,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
if animateIn {
videoFramePreviewNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
}
} else if let videoFramePreviewNode = self.videoFramePreviewNode {
} else if let (videoFramePreviewNode, _) = self.videoFramePreviewNode {
self.videoFramePreviewNode = nil
videoFramePreviewNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak videoFramePreviewNode] _ in
videoFramePreviewNode?.removeFromSupernode()

View File

@ -100,7 +100,6 @@ final class ChatListControllerNode: ASDisplayNode {
if let (layout, navigationHeight, visualNavigationHeight) = strongSelf.containerLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationHeight, visualNavigationHeight: visualNavigationHeight, transition: .immediate)
}
strongSelf.isEmptyUpdated?(true)
}
case .notEmpty(false):

View File

@ -245,7 +245,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
fitzModifier = EmojiFitzModifier(emoji: fitz)
}
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.context.account.postbox, file: emojiFile, small: false, size: dimensions.aspectFilled(CGSize(width: 384.0, height: 384.0)), fitzModifier: fitzModifier, thumbnail: false))
self.disposable.set(freeMediaFileInteractiveFetched(account: item.context.account, fileReference: .message(message: MessageReference(item.message), media: emojiFile)).start())
self.disposable.set(freeMediaFileInteractiveFetched(account: item.context.account, fileReference: .standalone(media: emojiFile)).start())
self.updateVisibility()
}
}
@ -794,7 +794,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|> deliverOnMainQueue
}
if self.item?.message.text == "❤️" {
if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, firstScalar.value == 0x2764 {
let _ = startTime.start(next: { [weak self] time in
guard let strongSelf = self else {
return

View File

@ -43,6 +43,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
}
var updateScrubbing: (Double?) -> Void = { _ in }
var updateScrubbingVisual: (Double?) -> Void = { _ in }
var updateScrubbingHandlePosition: (CGFloat) -> Void = { _ in }
var seek: (Double) -> Void = { _ in }
@ -67,6 +68,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
self.scrubberNode.update = { [weak self] timestamp, position in
self?.updateScrubbing(timestamp)
self?.updateScrubbingVisual(timestamp)
self?.updateScrubbingHandlePosition(position)
}

View File

@ -203,7 +203,7 @@ func galleryItemForEntry(context: AccountContext, presentationData: Presentation
content = SystemVideoContent(url: embedUrl, imageReference: .webPage(webPage: WebpageReference(webpage), media: image), dimensions: webpageContent.embedSize ?? CGSize(width: 640.0, height: 640.0), duration: Int32(webpageContent.duration ?? 0))
}
}
if content == nil, let webEmbedContent = WebEmbedVideoContent(webPage: webpage, webpageContent: webpageContent) {
if content == nil, let webEmbedContent = WebEmbedVideoContent(webPage: webpage, webpageContent: webpageContent, forcedTimestamp: timecode.flatMap(Int.init)) {
content = webEmbedContent
}
}
@ -917,16 +917,13 @@ class GalleryController: ViewController {
if let (media, _) = mediaForMessage(message: message) {
if let presentationArguments = self.presentationArguments as? GalleryControllerPresentationArguments, let transitionArguments = presentationArguments.transitionArguments(message.id, media) {
nodeAnimatesItself = true
centralItemNode.activateAsInitial()
if presentationArguments.animated {
centralItemNode.animateIn(from: transitionArguments.transitionNode, addToTransitionSurface: transitionArguments.addToTransitionSurface)
}
self._hiddenMedia.set(.single((message.id, media)))
} else if self.isPresentedInPreviewingContext() {
centralItemNode.activateAsInitial()
}
centralItemNode.activateAsInitial()
}
}

View File

@ -171,6 +171,8 @@ func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlCon
|> deliverOnMainQueue).start(completed: {
navigationController?.pushViewController(ChatController(context: context, chatLocation: .peer(peerId)))
})
} else {
navigationController?.pushViewController(ChatController(context: context, chatLocation: .peer(peerId), messageId: nil))
}
}

View File

@ -297,7 +297,7 @@ public class PeerMediaCollectionController: TelegramBaseController {
if let strongSelf = self, let messageIds = strongSelf.interfaceState.selectionState?.selectedIds, !messageIds.isEmpty {
strongSelf.present(peerReportOptionsController(context: strongSelf.context, subject: .messages(Array(messageIds).sorted()), present: { c, a in
self?.present(c, in: .window(.root), with: a)
}), in: .window(.root))
}, completion: { _ in }), in: .window(.root))
}
}, reportMessages: { _ in
}, deleteMessages: { _ in

View File

@ -22,7 +22,7 @@ private enum PeerReportOption {
case other
}
func peerReportOptionsController(context: AccountContext, subject: PeerReportSubject, present: @escaping (ViewController, Any?) -> Void) -> ViewController {
func peerReportOptionsController(context: AccountContext, subject: PeerReportSubject, present: @escaping (ViewController, Any?) -> Void, completion: @escaping (Bool) -> Void) -> ViewController {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = ActionSheetController(theme: ActionSheetControllerTheme(presentationTheme: presentationData.theme))
@ -75,15 +75,17 @@ func peerReportOptionsController(context: AccountContext, subject: PeerReportSub
let _ = (reportPeer(account: context.account, peerId: peerId, reason: reportReason)
|> deliverOnMainQueue).start(completed: {
present(textAlertController(context: context, title: nil, text: presentationData.strings.ReportPeer_AlertSuccess, actions: [TextAlertAction(type: TextAlertActionType.defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
completion(true)
})
case let .messages(messageIds):
let _ = (reportPeerMessages(account: context.account, messageIds: messageIds, reason: reportReason)
|> deliverOnMainQueue).start(completed: {
present(textAlertController(context: context, title: nil, text: presentationData.strings.ReportPeer_AlertSuccess, actions: [TextAlertAction.init(type: TextAlertActionType.defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
completion(true)
})
}
} else {
controller?.present(peerReportController(context: context, subject: subject), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
controller?.present(peerReportController(context: context, subject: subject, completion: completion), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
controller?.dismissAnimated()
@ -95,6 +97,7 @@ func peerReportOptionsController(context: AccountContext, subject: PeerReportSub
ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { [weak controller] in
controller?.dismissAnimated()
completion(false)
})
])
])
@ -187,7 +190,7 @@ private func peerReportControllerEntries(presentationData: PresentationData, sta
return entries
}
private func peerReportController(context: AccountContext, subject: PeerReportSubject) -> ViewController {
private func peerReportController(context: AccountContext, subject: PeerReportSubject, completion: @escaping (Bool) -> Void) -> ViewController {
var dismissImpl: (() -> Void)?
var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
@ -228,6 +231,7 @@ private func peerReportController(context: AccountContext, subject: PeerReportSu
let completed: () -> Void = {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.ReportPeer_AlertSuccess, actions: [TextAlertAction.init(type: TextAlertActionType.defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
completion(true)
dismissImpl?()
}
switch subject {
@ -248,6 +252,7 @@ private func peerReportController(context: AccountContext, subject: PeerReportSu
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.ReportPeer_ReasonOther_Title), leftNavigationButton: ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
dismissImpl?()
completion(false)
}), rightNavigationButton: rightButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
let listState = ItemListNodeState(entries: peerReportControllerEntries(presentationData: presentationData, state: state), style: .blocks, focusItemTag: PeerReportControllerEntryTag.text)

View File

@ -271,8 +271,7 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
let query = text.trimmingCharacters(in: .whitespacesAndNewlines)
if query.isSingleEmoji {
signals = .single([searchStickers(account: account, query: text.trimmedEmoji)
//|> take(1)
signals = .single([searchStickers(account: account, query: text.basicEmoji.0)
|> map { (nil, $0) }])
} else if query.count > 1, let languageCode = languageCode, !languageCode.isEmpty && languageCode != "emoji" {
var signal = searchEmojiKeywords(postbox: account.postbox, inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3)
@ -294,7 +293,7 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
var signals: [Signal<(String?, [FoundStickerItem]), NoError>] = []
let emoticons = keywords.flatMap { $0.emoticons }
for emoji in emoticons {
signals.append(searchStickers(account: self.context.account, query: emoji.trimmedEmoji)
signals.append(searchStickers(account: self.context.account, query: emoji.basicEmoji.0)
|> take(1)
|> map { (emoji, $0) })
}

View File

@ -1164,7 +1164,7 @@ public func userInfoController(context: AccountContext, peerId: PeerId, mode: Us
}, report: {
presentControllerImpl?(peerReportOptionsController(context: context, subject: .peer(peerId), present: { c, a in
presentControllerImpl?(c, a)
}), nil)
}, completion: { _ in }), nil)
})
let deviceContacts: Signal<[(DeviceContactStableId, DeviceContactBasicData)], NoError> = peerView.get()

View File

@ -33,11 +33,9 @@ enum WebEmbedType {
}
}
func webEmbedType(content: TelegramMediaWebpageLoadedContent) -> WebEmbedType {
func webEmbedType(content: TelegramMediaWebpageLoadedContent, forcedTimestamp: Int? = nil) -> WebEmbedType {
if let (videoId, timestamp) = extractYoutubeVideoIdAndTimestamp(url: content.url) {
return .youtube(videoId: videoId, timestamp: timestamp)
// } else if let (videoId, timestamp) = extractVimeoVideoIdAndTimestamp(url: content.url) {
// return .vimeo(videoId: videoId, timestamp: timestamp)
return .youtube(videoId: videoId, timestamp: forcedTimestamp ?? timestamp)
} else {
return .iframe(url: content.embedUrl ?? content.url)
}

View File

@ -16,8 +16,9 @@ final class WebEmbedVideoContent: UniversalVideoContent {
let webpageContent: TelegramMediaWebpageLoadedContent
let dimensions: CGSize
let duration: Int32
let forcedTimestamp: Int?
init?(webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent) {
init?(webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent, forcedTimestamp: Int? = nil) {
guard let embedUrl = webpageContent.embedUrl else {
return nil
}
@ -26,10 +27,11 @@ final class WebEmbedVideoContent: UniversalVideoContent {
self.webpageContent = webpageContent
self.dimensions = webpageContent.embedSize ?? CGSize(width: 128.0, height: 128.0)
self.duration = Int32(webpageContent.duration ?? (0 as Int))
self.forcedTimestamp = forcedTimestamp
}
func makeContentNode(postbox: Postbox, audioSession: ManagedAudioSession) -> UniversalVideoContentNode & ASDisplayNode {
return WebEmbedVideoContentNode(postbox: postbox, audioSessionManager: audioSession, webPage: self.webPage, webpageContent: self.webpageContent)
return WebEmbedVideoContentNode(postbox: postbox, audioSessionManager: audioSession, webPage: self.webPage, webpageContent: self.webpageContent, forcedTimestamp: self.forcedTimestamp)
}
}
@ -62,7 +64,7 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte
private var readyDisposable = MetaDisposable()
init(postbox: Postbox, audioSessionManager: ManagedAudioSession, webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent) {
init(postbox: Postbox, audioSessionManager: ManagedAudioSession, webPage: TelegramMediaWebpage, webpageContent: TelegramMediaWebpageLoadedContent, forcedTimestamp: Int? = nil) {
self.webpageContent = webpageContent
if let embedSize = webpageContent.embedSize {
@ -73,7 +75,7 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte
self.imageNode = TransformImageNode()
let embedType = webEmbedType(content: webpageContent)
let embedType = webEmbedType(content: webpageContent, forcedTimestamp: forcedTimestamp)
let embedImpl = webEmbedImplementation(for: embedType)
self.playerNode = WebEmbedPlayerNode(impl: embedImpl, intrinsicDimensions: self.intrinsicDimensions)