diff --git a/Telegram-iOS/en.lproj/Localizable.strings b/Telegram-iOS/en.lproj/Localizable.strings index 309387a67b..796126ed7a 100644 --- a/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram-iOS/en.lproj/Localizable.strings @@ -4474,3 +4474,27 @@ Any member of this group will be able to see messages in the channel."; "StickerPacksSettings.AnimatedStickers" = "Loop Animated Stickers"; "StickerPacksSettings.AnimatedStickersInfo" = "Animated stickers in a chat will play continuously."; + +"Appearance.ThemePreview.ChatList.1.Name" = "Eva Summer"; +"Appearance.ThemePreview.ChatList.1.Text" = "Text"; + +"Appearance.ThemePreview.ChatList.2.Name" = "Your inner Competition"; +"Appearance.ThemePreview.ChatList.2.Text" = "Hey"; + +"Appearance.ThemePreview.ChatList.3.Name" = "Mike Apple"; +"Appearance.ThemePreview.ChatList.3.Text" = "Mike Apple"; + +"Appearance.ThemePreview.ChatList.4.Name" = "Paul Newman"; +"Appearance.ThemePreview.ChatList.4.Text" = "Any ideas?"; + +"Appearance.ThemePreview.ChatList.5.Name" = "Old Pirates"; +"Appearance.ThemePreview.ChatList.5.Text" = "Yo-ho-ho"; + +"Appearance.ThemePreview.ChatList.6.Name" = "Kate Bright"; +"Appearance.ThemePreview.ChatList.6.Text" = "Hola!"; + +"Appearance.ThemePreview.ChatList.7.Name" = "What"; +"Appearance.ThemePreview.ChatList.7.Text" = "Hola!"; + +"Appearance.ThemePreview.ChatList.8.Name" = "What"; +"Appearance.ThemePreview.ChatList.8.Text" = "Hola!"; diff --git a/submodules/BuildConfig/Sources/BuildConfig.m b/submodules/BuildConfig/Sources/BuildConfig.m index 599ba43722..e5f81f5642 100644 --- a/submodules/BuildConfig/Sources/BuildConfig.m +++ b/submodules/BuildConfig/Sources/BuildConfig.m @@ -362,6 +362,7 @@ API_AVAILABLE(ios(10)) } if (signature.data != nil) { _dataDict[@"data"] = [MTSha1(signature.data) base64EncodedStringWithOptions:0]; + _dataDict[@"data1"] = [signature.data base64EncodedStringWithOptions:0]; } } return self; diff --git a/submodules/Display/Display/TextNode.swift b/submodules/Display/Display/TextNode.swift index b70b5400fa..a00c22c472 100644 --- a/submodules/Display/Display/TextNode.swift +++ b/submodules/Display/Display/TextNode.swift @@ -5,6 +5,14 @@ import CoreText private let defaultFont = UIFont.systemFont(ofSize: 15.0) +private final class TextNodeStrikethrough { + let frame: CGRect + + init(frame: CGRect) { + self.frame = frame + } +} + private final class TextNodeLine { let line: CTLine let frame: CGRect @@ -21,7 +29,7 @@ private final class TextNodeLine { } } -private final class TextNodeStrikethrough { +private final class TextNodeBlockQuote { let frame: CGRect init(frame: CGRect) { @@ -83,8 +91,9 @@ public final class TextNodeLayoutArguments { public let lineSpacing: CGFloat public let cutout: TextNodeCutout? public let insets: UIEdgeInsets + public let lineColor: 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()) { + 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) { self.attributedString = attributedString self.backgroundColor = backgroundColor self.maximumNumberOfLines = maximumNumberOfLines @@ -94,6 +103,7 @@ public final class TextNodeLayoutArguments { self.lineSpacing = lineSpacing self.cutout = cutout self.insets = insets + self.lineColor = lineColor } } @@ -111,9 +121,11 @@ public final class TextNodeLayout: NSObject { public let truncated: Bool fileprivate let firstLineOffset: CGFloat fileprivate let lines: [TextNodeLine] + fileprivate let blockQuotes: [TextNodeBlockQuote] + fileprivate let lineColor: 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], backgroundColor: 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?) { self.attributedString = attributedString self.maximumNumberOfLines = maximumNumberOfLines self.truncationType = truncationType @@ -126,7 +138,9 @@ public final class TextNodeLayout: NSObject { self.truncated = truncated self.firstLineOffset = firstLineOffset self.lines = lines + self.blockQuotes = blockQuotes self.backgroundColor = backgroundColor + self.lineColor = lineColor var hasRTL = false for line in lines { if line.isRTL { @@ -561,7 +575,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) -> 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?) -> TextNodeLayout { if let attributedString = attributedString { let stringLength = attributedString.length @@ -582,11 +596,12 @@ public class TextNode: ASDisplayNode { let fontLineSpacing = floor(fontLineHeight * lineSpacingFactor) var lines: [TextNodeLine] = [] + var blockQuotes: [TextNodeBlockQuote] = [] 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: [], backgroundColor: backgroundColor) + 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) } let typesetter = maybeTypesetter! @@ -682,11 +697,28 @@ public class TextNode: ASDisplayNode { truncated = true } + var headIndent: CGFloat = 0.0 + attributedString.enumerateAttributes(in: NSMakeRange(lineRange.location, lineRange.length), options: []) { attributes, range, _ in + if let _ = attributes[NSAttributedStringKey.strikethroughStyle] { + let lowerX = floor(CTLineGetOffsetForStringIndex(coreTextLine, range.location, nil)) + let upperX = ceil(CTLineGetOffsetForStringIndex(coreTextLine, range.location + range.length, nil)) + let x = lowerX < upperX ? lowerX : upperX + strikethroughs.append(TextNodeStrikethrough(frame: CGRect(x: x, y: 0.0, width: abs(upperX - lowerX), height: fontLineHeight))) + } else if let paragraphStyle = attributes[NSAttributedStringKey.paragraphStyle] as? NSParagraphStyle { + headIndent = paragraphStyle.headIndent + + } + } + let lineWidth = min(constrainedSize.width, ceil(CGFloat(CTLineGetTypographicBounds(coreTextLine, nil, nil, nil) - CTLineGetTrailingWhitespaceWidth(coreTextLine)))) - let lineFrame = CGRect(x: lineCutoutOffset, y: lineOriginY, width: lineWidth, height: fontLineHeight) + let lineFrame = CGRect(x: lineCutoutOffset + headIndent, y: lineOriginY, width: lineWidth, height: fontLineHeight) layoutSize.height += fontLineHeight + fontLineSpacing layoutSize.width = max(layoutSize.width, lineWidth + lineAdditionalWidth) + if headIndent > 0.0 { + blockQuotes.append(TextNodeBlockQuote(frame: lineFrame)) + } + var isRTL = false let glyphRuns = CTLineGetGlyphRuns(coreTextLine) as NSArray if glyphRuns.count != 0 { @@ -696,16 +728,7 @@ public class TextNode: ASDisplayNode { } } - attributedString.enumerateAttributes(in: NSMakeRange(lineRange.location, lineRange.length), options: []) { attributes, range, _ in - if let _ = attributes[NSAttributedStringKey.strikethroughStyle] { - let lowerX = floor(CTLineGetOffsetForStringIndex(coreTextLine, range.location, nil)) - let upperX = ceil(CTLineGetOffsetForStringIndex(coreTextLine, range.location + range.length, nil)) - let x = lowerX < upperX ? lowerX : upperX - strikethroughs.append(TextNodeStrikethrough(frame: CGRect(x: x, y: 0.0, width: abs(upperX - lowerX), height: fontLineHeight))) - } - } lines.append(TextNodeLine(line: coreTextLine, frame: lineFrame, range: NSMakeRange(lineRange.location, lineRange.length), isRTL: isRTL, strikethroughs: strikethroughs)) - break } else { if lineCharacterCount > 0 { @@ -719,11 +742,27 @@ public class TextNode: ASDisplayNode { let coreTextLine = CTTypesetterCreateLineWithOffset(typesetter, lineRange, 100.0) lastLineCharacterIndex += lineCharacterCount + var headIndent: CGFloat = 0.0 + attributedString.enumerateAttributes(in: NSMakeRange(lineRange.location, lineRange.length), options: []) { attributes, range, _ in + if let _ = attributes[NSAttributedStringKey.strikethroughStyle] { + let lowerX = floor(CTLineGetOffsetForStringIndex(coreTextLine, range.location, nil)) + let upperX = ceil(CTLineGetOffsetForStringIndex(coreTextLine, range.location + range.length, nil)) + let x = lowerX < upperX ? lowerX : upperX + strikethroughs.append(TextNodeStrikethrough(frame: CGRect(x: x, y: 0.0, width: abs(upperX - lowerX), height: fontLineHeight))) + } else if let paragraphStyle = attributes[NSAttributedStringKey.paragraphStyle] as? NSParagraphStyle { + headIndent = paragraphStyle.headIndent + } + } + let lineWidth = ceil(CGFloat(CTLineGetTypographicBounds(coreTextLine, nil, nil, nil) - CTLineGetTrailingWhitespaceWidth(coreTextLine))) - let lineFrame = CGRect(x: lineCutoutOffset, y: lineOriginY, width: lineWidth, height: fontLineHeight) + let lineFrame = CGRect(x: lineCutoutOffset + headIndent, y: lineOriginY, width: lineWidth, height: fontLineHeight) layoutSize.height += fontLineHeight layoutSize.width = max(layoutSize.width, lineWidth + lineAdditionalWidth) + if headIndent > 0.0 { + blockQuotes.append(TextNodeBlockQuote(frame: lineFrame)) + } + var isRTL = false let glyphRuns = CTLineGetGlyphRuns(coreTextLine) as NSArray if glyphRuns.count != 0 { @@ -733,14 +772,6 @@ public class TextNode: ASDisplayNode { } } - attributedString.enumerateAttributes(in: NSMakeRange(lineRange.location, lineRange.length), options: []) { attributes, range, _ in - if let _ = attributes[NSAttributedStringKey.strikethroughStyle] { - let lowerX = floor(CTLineGetOffsetForStringIndex(coreTextLine, range.location, nil)) - let upperX = ceil(CTLineGetOffsetForStringIndex(coreTextLine, range.location + range.length, nil)) - let x = lowerX < upperX ? lowerX : upperX - strikethroughs.append(TextNodeStrikethrough(frame: CGRect(x: x, y: 0.0, width: abs(upperX - lowerX), height: fontLineHeight))) - } - } lines.append(TextNodeLine(line: coreTextLine, frame: lineFrame, range: NSMakeRange(lineRange.location, lineRange.length), isRTL: isRTL, strikethroughs: strikethroughs)) } else { if !lines.isEmpty { @@ -762,9 +793,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, backgroundColor: backgroundColor) + 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) } 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: [], backgroundColor: backgroundColor) + 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) } } @@ -799,11 +830,8 @@ public class TextNode: ASDisplayNode { let textMatrix = context.textMatrix let textPosition = context.textPosition - //CGContextSaveGState(context) - context.textMatrix = CGAffineTransform(scaleX: 1.0, y: -1.0) - //let clipRect = CGContextGetClipBoundingBox(context) let alignment = layout.alignment let offset = CGPoint(x: layout.insets.left, y: layout.insets.top) @@ -832,7 +860,34 @@ public class TextNode: ASDisplayNode { } } - //CGContextRestoreGState(context) + var blockQuoteFrames: [CGRect] = [] + var currentBlockQuoteFrame: CGRect? + for blockQuote in layout.blockQuotes { + if let frame = currentBlockQuoteFrame { + if blockQuote.frame.minY - frame.maxY < 20.0 { + currentBlockQuoteFrame = frame.union(blockQuote.frame) + } else { + blockQuoteFrames.append(frame) + currentBlockQuoteFrame = frame + } + } else { + currentBlockQuoteFrame = blockQuote.frame + } + } + + if let frame = currentBlockQuoteFrame { + blockQuoteFrames.append(frame) + } + + for frame in blockQuoteFrames { + if let lineColor = layout.lineColor { + context.setFillColor(lineColor.cgColor) + } + let rect = UIBezierPath(roundedRect: CGRect(x: frame.minX - 9.0, y: frame.minY - 14.0, width: 2.0, height: frame.height), cornerRadius: 1.0) + context.addPath(rect.cgPath) + context.fillPath() + } + context.textMatrix = textMatrix context.textPosition = CGPoint(x: textPosition.x, y: textPosition.y) } @@ -872,11 +927,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) + 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) 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) + 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) updated = true } diff --git a/submodules/MediaPlayer/Sources/FFMpegMediaFrameSourceContext.swift b/submodules/MediaPlayer/Sources/FFMpegMediaFrameSourceContext.swift index 3c4187814a..e70d62a4f4 100644 --- a/submodules/MediaPlayer/Sources/FFMpegMediaFrameSourceContext.swift +++ b/submodules/MediaPlayer/Sources/FFMpegMediaFrameSourceContext.swift @@ -238,12 +238,12 @@ private func seekCallback(userData: UnsafeMutableRawPointer?, offset: Int64, whe if streamable { if context.tempFilePath == nil { let fetchRange: Range = context.readingOffset ..< Int(Int32.max) - context.fetchedDataDisposable.set(fetchedMediaResource(postbox: postbox, reference: resourceReference, range: (fetchRange, .elevated), statsCategory: statsCategory, preferBackgroundReferenceRevalidation: streamable).start()) + context.fetchedDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, range: (fetchRange, .elevated), statsCategory: statsCategory, preferBackgroundReferenceRevalidation: streamable).start()) } } else if !context.requestedCompleteFetch && context.fetchAutomatically { context.requestedCompleteFetch = true if context.tempFilePath == nil { - context.fetchedDataDisposable.set(fetchedMediaResource(postbox: postbox, reference: resourceReference, statsCategory: statsCategory, preferBackgroundReferenceRevalidation: streamable).start()) + context.fetchedDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, statsCategory: statsCategory, preferBackgroundReferenceRevalidation: streamable).start()) } } } @@ -330,12 +330,12 @@ final class FFMpegMediaFrameSourceContext: NSObject { if streamable { if self.tempFilePath == nil { - self.fetchedDataDisposable.set(fetchedMediaResource(postbox: postbox, reference: resourceReference, range: (0 ..< Int(Int32.max), .elevated), statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start()) + self.fetchedDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, range: (0 ..< Int(Int32.max), .elevated), statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start()) } } else if !self.requestedCompleteFetch && self.fetchAutomatically { self.requestedCompleteFetch = true if self.tempFilePath == nil { - self.fetchedFullDataDisposable.set(fetchedMediaResource(postbox: postbox, reference: resourceReference, statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start()) + self.fetchedFullDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start()) } } @@ -437,7 +437,7 @@ final class FFMpegMediaFrameSourceContext: NSObject { if streamable { if self.tempFilePath == nil { - self.fetchedFullDataDisposable.set(fetchedMediaResource(postbox: postbox, reference: resourceReference, range: (0 ..< Int(Int32.max), .default), statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start()) + self.fetchedFullDataDisposable.set(fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, range: (0 ..< Int(Int32.max), .default), statsCategory: self.statsCategory ?? .generic, preferBackgroundReferenceRevalidation: streamable).start()) } self.requestedCompleteFetch = true } diff --git a/submodules/MediaPlayer/Sources/FFMpegMediaVideoFrameDecoder.swift b/submodules/MediaPlayer/Sources/FFMpegMediaVideoFrameDecoder.swift index 29c84c0193..0bfdb1731f 100644 --- a/submodules/MediaPlayer/Sources/FFMpegMediaVideoFrameDecoder.swift +++ b/submodules/MediaPlayer/Sources/FFMpegMediaVideoFrameDecoder.swift @@ -1,9 +1,22 @@ import CoreMedia import Accelerate import FFMpeg +import Accelerate private let bufferCount = 32 +private let deviceColorSpace: CGColorSpace = { + if #available(iOSApplicationExtension 9.3, iOS 9.3, *) { + if let colorSpace = CGColorSpace(name: CGColorSpace.displayP3) { + return colorSpace + } else { + return CGColorSpaceCreateDeviceRGB() + } + } else { + return CGColorSpaceCreateDeviceRGB() + } +}() + public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder { private let codecContext: FFMpegAVCodecContext @@ -63,6 +76,17 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder { return nil } + public func render(frame: MediaTrackDecodableFrame) -> UIImage? { + let status = frame.packet.send(toDecoder: self.codecContext) + if status == 0 { + if self.codecContext.receive(into: self.videoFrame) { + return convertVideoFrameToImage(self.videoFrame) + } + } + + return nil + } + public func takeRemainingFrame() -> MediaTrackFrame? { if !self.delayedFrames.isEmpty { var minFrameIndex = 0 @@ -79,6 +103,53 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder { } } + private func convertVideoFrameToImage(_ frame: FFMpegAVFrame) -> UIImage? { + var info = vImage_YpCbCrToARGB() + + var pixelRange: vImage_YpCbCrPixelRange + switch frame.colorRange { + case .full: + pixelRange = vImage_YpCbCrPixelRange(Yp_bias: 0, CbCr_bias: 128, YpRangeMax: 255, CbCrRangeMax: 255, YpMax: 255, YpMin: 0, CbCrMax: 255, CbCrMin: 0) + default: + pixelRange = vImage_YpCbCrPixelRange(Yp_bias: 16, CbCr_bias: 128, YpRangeMax: 235, CbCrRangeMax: 240, YpMax: 255, YpMin: 0, CbCrMax: 255, CbCrMin: 0) + } + var result = kvImageNoError + result = vImageConvert_YpCbCrToARGB_GenerateConversion(kvImage_YpCbCrToARGBMatrix_ITU_R_709_2, &pixelRange, &info, kvImage420Yp8_Cb8_Cr8, kvImageARGB8888, 0) + if result != kvImageNoError { + return nil + } + + var srcYp = vImage_Buffer(data: frame.data[0], height: vImagePixelCount(frame.height), width: vImagePixelCount(frame.width), rowBytes: Int(frame.lineSize[0])) + var srcCb = vImage_Buffer(data: frame.data[1], height: vImagePixelCount(frame.height), width: vImagePixelCount(frame.width / 2), rowBytes: Int(frame.lineSize[1])) + var srcCr = vImage_Buffer(data: frame.data[2], height: vImagePixelCount(frame.height), width: vImagePixelCount(frame.width / 2), rowBytes: Int(frame.lineSize[2])) + + let argbBytesPerRow = (4 * Int(frame.width) + 15) & (~15) + let argbLength = argbBytesPerRow * Int(frame.height) + let argb = malloc(argbLength)! + guard let provider = CGDataProvider(dataInfo: argb, data: argb, size: argbLength, releaseData: { bytes, _, _ in + free(bytes) + }) else { + return nil + } + + var dst = vImage_Buffer(data: argb, height: vImagePixelCount(frame.height), width: vImagePixelCount(frame.width), rowBytes: argbBytesPerRow) + + var permuteMap: [UInt8] = [3, 2, 1, 0] + + result = vImageConvert_420Yp8_Cb8_Cr8ToARGB8888(&srcYp, &srcCb, &srcCr, &dst, &info, &permuteMap, 0x00, 0) + if result != kvImageNoError { + return nil + } + + let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.noneSkipFirst.rawValue) + + guard let image = CGImage(width: Int(frame.width), height: Int(frame.height), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: argbBytesPerRow, space: deviceColorSpace, bitmapInfo: bitmapInfo, provider: provider, decode: nil, shouldInterpolate: false, intent: .defaultIntent) else { + return nil + } + + return UIImage(cgImage: image, scale: 1.0, orientation: .up) + } + private func convertVideoFrame(_ frame: FFMpegAVFrame, pts: CMTime, dts: CMTime, duration: CMTime) -> MediaTrackFrame? { if frame.data[0] == nil { return nil @@ -100,9 +171,6 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder { ioSurfaceProperties["IOSurfaceIsGlobal"] = true as NSNumber var options: [String: Any] = [kCVPixelBufferBytesPerRowAlignmentKey as String: frame.lineSize[0] as NSNumber] - /*if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { - options[kCVPixelBufferOpenGLESTextureCacheCompatibilityKey as String] = true as NSNumber - }*/ options[kCVPixelBufferIOSurfacePropertiesKey as String] = ioSurfaceProperties CVPixelBufferCreate(kCFAllocatorDefault, diff --git a/submodules/MediaPlayer/Sources/MediaPlayerFramePreview.swift b/submodules/MediaPlayer/Sources/MediaPlayerFramePreview.swift new file mode 100644 index 0000000000..1abdc20c9c --- /dev/null +++ b/submodules/MediaPlayer/Sources/MediaPlayerFramePreview.swift @@ -0,0 +1,141 @@ +import Foundation +import SwiftSignalKit +import Postbox +import TelegramCore +import FFMpeg + +private final class FramePreviewContext { + let source: UniversalSoftwareVideoSource + + init(source: UniversalSoftwareVideoSource) { + self.source = source + } +} + +private func initializedPreviewContext(queue: Queue, postbox: Postbox, fileReference: FileMediaReference) -> Signal, NoError> { + return Signal { subscriber in + let source = UniversalSoftwareVideoSource(mediaBox: postbox.mediaBox, fileReference: fileReference) + let readyDisposable = (source.ready + |> filter { $0 }).start(next: { _ in + subscriber.putNext(QueueLocalObject(queue: queue, generate: { + return FramePreviewContext(source: source) + })) + }) + + return ActionDisposable { + readyDisposable.dispose() + } + } +} + +public enum MediaPlayerFramePreviewResult { + case image(UIImage) + case waitingForData +} + +private final class MediaPlayerFramePreviewImpl { + private let queue: Queue + private let context: Promise> + private let currentFrameDisposable = MetaDisposable() + private var currentFrameTimestamp: Double? + private var nextFrameTimestamp: Double? + fileprivate let framePipe = ValuePipe() + + init(queue: Queue, postbox: Postbox, fileReference: FileMediaReference) { + self.queue = queue + self.context = Promise() + self.context.set(initializedPreviewContext(queue: queue, postbox: postbox, fileReference: fileReference)) + } + + deinit { + assert(self.queue.isCurrent()) + self.currentFrameDisposable.dispose() + } + + func generateFrame(at timestamp: Double) { + if self.currentFrameTimestamp != nil { + self.nextFrameTimestamp = timestamp + return + } + self.currentFrameTimestamp = timestamp + + let queue = self.queue + let takeDisposable = MetaDisposable() + let disposable = (self.context.get() + |> take(1)).start(next: { [weak self] context in + queue.async { + guard context.queue === queue else { + return + } + context.with { context in + let disposable = context.source.takeFrame(at: timestamp).start(next: { result in + guard let strongSelf = self else { + return + } + switch result { + case .waitingForData: + strongSelf.framePipe.putNext(.waitingForData) + case let .image(image): + if let image = image { + strongSelf.framePipe.putNext(.image(image)) + } + strongSelf.currentFrameTimestamp = nil + if let nextFrameTimestamp = strongSelf.nextFrameTimestamp { + strongSelf.nextFrameTimestamp = nil + strongSelf.generateFrame(at: nextFrameTimestamp) + } + } + }) + takeDisposable.set(disposable) + } + } + }) + self.currentFrameDisposable.set(ActionDisposable { + takeDisposable.dispose() + disposable.dispose() + }) + } + + func cancelPendingFrames() { + self.nextFrameTimestamp = nil + self.currentFrameTimestamp = nil + self.currentFrameDisposable.set(nil) + } +} + +public final class MediaPlayerFramePreview { + private let queue: Queue + private let impl: QueueLocalObject + + public var generatedFrames: Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.framePipe.signal().start(next: { result in + subscriber.putNext(result) + })) + } + return disposable + } + } + + public init(postbox: Postbox, fileReference: FileMediaReference) { + let queue = Queue() + self.queue = queue + self.impl = QueueLocalObject(queue: queue, generate: { + return MediaPlayerFramePreviewImpl(queue: queue, postbox: postbox, fileReference: fileReference) + }) + } + + public func generateFrame(at timestamp: Double) { + self.impl.with { impl in + impl.generateFrame(at: timestamp) + } + } + + public func cancelPendingFrames() { + self.impl.with { impl in + impl.cancelPendingFrames() + } + } +} diff --git a/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift b/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift index e5efcb136c..d7de8daf3e 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift @@ -188,6 +188,7 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode { public var playbackStatusUpdated: ((MediaPlayerPlaybackStatus?) -> Void)? public var playerStatusUpdated: ((MediaPlayerStatus?) -> Void)? public var seek: ((Double) -> Void)? + public var update: ((Double?, CGFloat) -> Void)? private let _scrubbingTimestamp = Promise(nil) public var scrubbingTimestamp: Signal { @@ -378,6 +379,7 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode { strongSelf.scrubbingBeginTimestamp = statusValue.timestamp strongSelf.scrubbingTimestampValue = statusValue.timestamp strongSelf._scrubbingTimestamp.set(.single(strongSelf.scrubbingTimestampValue)) + strongSelf.update?(strongSelf.scrubbingTimestampValue, CGFloat(statusValue.timestamp / statusValue.duration)) strongSelf.updateProgressAnimations() } } @@ -385,8 +387,10 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode { handleNodeContainer.updateScrubbing = { [weak self] addedFraction in if let strongSelf = self { if let statusValue = strongSelf.statusValue, let scrubbingBeginTimestamp = strongSelf.scrubbingBeginTimestamp, Double(0.0).isLess(than: statusValue.duration) { - strongSelf.scrubbingTimestampValue = max(0.0, min(statusValue.duration, scrubbingBeginTimestamp + statusValue.duration * Double(addedFraction))) + let timestampValue = max(0.0, min(statusValue.duration, scrubbingBeginTimestamp + statusValue.duration * Double(addedFraction))) + strongSelf.scrubbingTimestampValue = timestampValue strongSelf._scrubbingTimestamp.set(.single(strongSelf.scrubbingTimestampValue)) + strongSelf.update?(timestampValue, CGFloat(timestampValue / statusValue.duration)) strongSelf.updateProgressAnimations() } } @@ -408,6 +412,7 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode { } strongSelf.seek?(scrubbingTimestampValue) } + strongSelf.update?(nil, 0.0) strongSelf.updateProgressAnimations() } } diff --git a/submodules/TelegramUI/TelegramUI/SoftwareVideoSource.swift b/submodules/MediaPlayer/Sources/SoftwareVideoSource.swift similarity index 79% rename from submodules/TelegramUI/TelegramUI/SoftwareVideoSource.swift rename to submodules/MediaPlayer/Sources/SoftwareVideoSource.swift index f90e8c727c..4c8976df32 100644 --- a/submodules/TelegramUI/TelegramUI/SoftwareVideoSource.swift +++ b/submodules/MediaPlayer/Sources/SoftwareVideoSource.swift @@ -3,7 +3,6 @@ import UIKit import CoreMedia import SwiftSignalKit import FFMpeg -import UniversalMediaPlayer private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: UnsafeMutablePointer?, bufferSize: Int32) -> Int32 { let context = Unmanaged.fromOpaque(userData!).takeUnretainedValue() @@ -46,7 +45,7 @@ private final class SoftwareVideoStream { } } -final class SoftwareVideoSource { +public final class SoftwareVideoSource { private var readingError = false private var videoStream: SoftwareVideoStream? private var avIoContext: FFMpegAVIOContext? @@ -55,7 +54,7 @@ final class SoftwareVideoSource { fileprivate let fd: Int32? fileprivate let size: Int32 - init(path: String) { + public init(path: String) { let _ = FFMpegMediaFrameSourceContextHelpers.registerFFMpegGlobals var s = stat() @@ -102,10 +101,10 @@ final class SoftwareVideoSource { let codecId = avFormatContext.codecId(atStreamIndex: streamIndex) - let fpsAndTimebase = avFormatContext.fpsAndTimebase(forStreamIndex: streamIndex, defaultTimeBase: CMTimeMake(1, 40000)) + let fpsAndTimebase = avFormatContext.fpsAndTimebase(forStreamIndex: streamIndex, defaultTimeBase: CMTimeMake(value: 1, timescale: 40000)) let (fps, timebase) = (fpsAndTimebase.fps, fpsAndTimebase.timebase) - let duration = CMTimeMake(avFormatContext.duration(atStreamIndex: streamIndex), timebase.timescale) + let duration = CMTimeMake(value: avFormatContext.duration(atStreamIndex: streamIndex), timescale: timebase.timescale) let metrics = avFormatContext.metricsForStream(at: streamIndex) @@ -154,14 +153,14 @@ final class SoftwareVideoSource { if let videoStream = videoStream, Int(packet.streamIndex) == videoStream.index { let packetPts = packet.pts - let pts = CMTimeMake(packetPts, videoStream.timebase.timescale) - let dts = CMTimeMake(packet.dts, videoStream.timebase.timescale) + let pts = CMTimeMake(value: packetPts, timescale: videoStream.timebase.timescale) + let dts = CMTimeMake(value: packet.dts, timescale: videoStream.timebase.timescale) let duration: CMTime let frameDuration = packet.duration if frameDuration != 0 { - duration = CMTimeMake(frameDuration * videoStream.timebase.value, videoStream.timebase.timescale) + duration = CMTimeMake(value: frameDuration * videoStream.timebase.value, timescale: videoStream.timebase.timescale) } else { duration = videoStream.fps } @@ -193,7 +192,7 @@ final class SoftwareVideoSource { return (frames.first, endOfStream) } - func readFrame(maxPts: CMTime?) -> (MediaTrackFrame?, CGFloat, CGFloat, Bool) { + public func readFrame(maxPts: CMTime?) -> (MediaTrackFrame?, CGFloat, CGFloat, Bool) { if let videoStream = self.videoStream { let (decodableFrame, loop) = self.readDecodableFrame() if let decodableFrame = decodableFrame { @@ -209,4 +208,28 @@ final class SoftwareVideoSource { return (nil, 0.0, 1.0, false) } } + + public func readImage() -> (UIImage?, CGFloat, CGFloat, Bool) { + if let videoStream = self.videoStream { + for _ in 0 ..< 10 { + let (decodableFrame, loop) = self.readDecodableFrame() + if let decodableFrame = decodableFrame { + if let renderedFrame = videoStream.decoder.render(frame: decodableFrame) { + return (renderedFrame, CGFloat(videoStream.rotationAngle), CGFloat(videoStream.aspect), loop) + } + } + } + return (nil, CGFloat(videoStream.rotationAngle), CGFloat(videoStream.aspect), true) + } else { + return (nil, 0.0, 1.0, false) + } + } + + public func seek(timestamp: Double) { + if let stream = self.videoStream, let avFormatContext = self.avFormatContext { + let pts = CMTimeMakeWithSeconds(timestamp, preferredTimescale: stream.timebase.timescale) + avFormatContext.seekFrame(forStreamIndex: Int32(stream.index), pts: pts.value) + stream.decoder.reset() + } + } } diff --git a/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift b/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift new file mode 100644 index 0000000000..9eefce0a6b --- /dev/null +++ b/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift @@ -0,0 +1,395 @@ +import Foundation +import SwiftSignalKit +import Postbox +import TelegramCore +import FFMpeg + +private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: UnsafeMutablePointer?, bufferSize: Int32) -> Int32 { + let context = Unmanaged.fromOpaque(userData!).takeUnretainedValue() + let data: Signal + + let resourceSize: Int = context.size + let readCount = min(resourceSize - context.readingOffset, Int(bufferSize)) + let requestRange: Range = context.readingOffset ..< (context.readingOffset + readCount) + + context.currentNumberOfReads += 1 + context.currentReadBytes += readCount + + let semaphore = DispatchSemaphore(value: 0) + data = context.mediaBox.resourceData(context.fileReference.media.resource, size: context.size, in: requestRange, mode: .partial) + let requiredDataIsNotLocallyAvailable = context.requiredDataIsNotLocallyAvailable + var fetchedData: Data? + let disposable = data.start(next: { data in + if data.count == readCount { + fetchedData = data + semaphore.signal() + } else { + requiredDataIsNotLocallyAvailable?() + } + }) + let cancelDisposable = context.cancelRead.start(next: { value in + if value { + semaphore.signal() + } + }) + var fetchDisposable: Disposable? + if context.videoStream != nil { + fetchDisposable = fetchedMediaResource(mediaBox: context.mediaBox, reference: context.fileReference.resourceReference(context.fileReference.media.resource), ranges: [(requestRange, .elevated)]).start() + } + semaphore.wait() + + disposable.dispose() + cancelDisposable.dispose() + fetchDisposable?.dispose() + + if let fetchedData = fetchedData { + fetchedData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(buffer, bytes, fetchedData.count) + } + let fetchedCount = Int32(fetchedData.count) + context.readingOffset += Int(fetchedCount) + return fetchedCount + } else { + return 0 + } +} + +private func seekCallback(userData: UnsafeMutableRawPointer?, offset: Int64, whence: Int32) -> Int64 { + let context = Unmanaged.fromOpaque(userData!).takeUnretainedValue() + if (whence & FFMPEG_AVSEEK_SIZE) != 0 { + return Int64(context.size) + } else { + context.readingOffset = Int(offset) + return offset + } +} + +private final class SoftwareVideoStream { + let index: Int + let fps: CMTime + let timebase: CMTime + let duration: CMTime + let decoder: FFMpegMediaVideoFrameDecoder + let rotationAngle: Double + let aspect: Double + + init(index: Int, fps: CMTime, timebase: CMTime, duration: CMTime, decoder: FFMpegMediaVideoFrameDecoder, rotationAngle: Double, aspect: Double) { + self.index = index + self.fps = fps + self.timebase = timebase + self.duration = duration + self.decoder = decoder + self.rotationAngle = rotationAngle + self.aspect = aspect + } +} + +private final class UniversalSoftwareVideoSourceImpl { + fileprivate let mediaBox: MediaBox + fileprivate let fileReference: FileMediaReference + fileprivate let size: Int + + fileprivate let state: ValuePromise + + fileprivate var avIoContext: FFMpegAVIOContext! + fileprivate var avFormatContext: FFMpegAVFormatContext! + fileprivate var videoStream: SoftwareVideoStream! + + fileprivate var readingOffset: Int = 0 + + fileprivate var cancelRead: Signal + fileprivate var requiredDataIsNotLocallyAvailable: (() -> Void)? + fileprivate var currentNumberOfReads: Int = 0 + fileprivate var currentReadBytes: Int = 0 + + init?(mediaBox: MediaBox, fileReference: FileMediaReference, state: ValuePromise, cancelInitialization: Signal) { + guard let size = fileReference.media.size else { + return nil + } + + self.mediaBox = mediaBox + self.fileReference = fileReference + self.size = size + + self.state = state + state.set(.initializing) + + self.cancelRead = cancelInitialization + + let ioBufferSize = 64 * 1024 + + guard let avIoContext = FFMpegAVIOContext(bufferSize: Int32(ioBufferSize), opaqueContext: Unmanaged.passUnretained(self).toOpaque(), readPacket: readPacketCallback, seek: seekCallback) else { + return nil + } + self.avIoContext = avIoContext + + let avFormatContext = FFMpegAVFormatContext() + avFormatContext.setIO(avIoContext) + + if !avFormatContext.openInput() { + return nil + } + + if !avFormatContext.findStreamInfo() { + return nil + } + + self.avFormatContext = avFormatContext + + var videoStream: SoftwareVideoStream? + + for streamIndexNumber in avFormatContext.streamIndices(for: FFMpegAVFormatStreamTypeVideo) { + let streamIndex = streamIndexNumber.int32Value + if avFormatContext.isAttachedPic(atStreamIndex: streamIndex) { + continue + } + + let codecId = avFormatContext.codecId(atStreamIndex: streamIndex) + + let fpsAndTimebase = avFormatContext.fpsAndTimebase(forStreamIndex: streamIndex, defaultTimeBase: CMTimeMake(value: 1, timescale: 40000)) + let (fps, timebase) = (fpsAndTimebase.fps, fpsAndTimebase.timebase) + + let duration = CMTimeMake(value: avFormatContext.duration(atStreamIndex: streamIndex), timescale: timebase.timescale) + + let metrics = avFormatContext.metricsForStream(at: streamIndex) + + let rotationAngle: Double = metrics.rotationAngle + let aspect = Double(metrics.width) / Double(metrics.height) + + if let codec = FFMpegAVCodec.find(forId: codecId) { + let codecContext = FFMpegAVCodecContext(codec: codec) + if avFormatContext.codecParams(atStreamIndex: streamIndex, to: codecContext) { + if codecContext.open() { + videoStream = SoftwareVideoStream(index: Int(streamIndex), fps: fps, timebase: timebase, duration: duration, decoder: FFMpegMediaVideoFrameDecoder(codecContext: codecContext), rotationAngle: rotationAngle, aspect: aspect) + break + } + } + } + } + + if let videoStream = videoStream { + self.videoStream = videoStream + } else { + return nil + } + + state.set(.ready) + } + + private func readPacketInternal() -> FFMpegPacket? { + guard let avFormatContext = self.avFormatContext else { + return nil + } + + let packet = FFMpegPacket() + if avFormatContext.readFrame(into: packet) { + return packet + } else { + return nil + } + } + + func readDecodableFrame() -> (MediaTrackDecodableFrame?, Bool) { + var frames: [MediaTrackDecodableFrame] = [] + var endOfStream = false + + while frames.isEmpty { + if let packet = self.readPacketInternal() { + if let videoStream = videoStream, Int(packet.streamIndex) == videoStream.index { + let packetPts = packet.pts + + let pts = CMTimeMake(value: packetPts, timescale: videoStream.timebase.timescale) + let dts = CMTimeMake(value: packet.dts, timescale: videoStream.timebase.timescale) + + let duration: CMTime + + let frameDuration = packet.duration + if frameDuration != 0 { + duration = CMTimeMake(value: frameDuration * videoStream.timebase.value, timescale: videoStream.timebase.timescale) + } else { + duration = videoStream.fps + } + + let frame = MediaTrackDecodableFrame(type: .video, packet: packet, pts: pts, dts: dts, duration: duration) + frames.append(frame) + } + } else { + if endOfStream { + break + } else { + if let avFormatContext = self.avFormatContext, let videoStream = self.videoStream { + endOfStream = true + avFormatContext.seekFrame(forStreamIndex: Int32(videoStream.index), pts: 0) + } else { + endOfStream = true + break + } + } + } + } + + if endOfStream { + if let videoStream = self.videoStream { + videoStream.decoder.reset() + } + } + + return (frames.first, endOfStream) + } + + func readImage() -> (UIImage?, CGFloat, CGFloat, Bool) { + if let videoStream = self.videoStream { + self.currentNumberOfReads = 0 + self.currentReadBytes = 0 + for i in 0 ..< 10 { + let (decodableFrame, loop) = self.readDecodableFrame() + if let decodableFrame = decodableFrame { + if let renderedFrame = videoStream.decoder.render(frame: decodableFrame) { + print("Frame rendered in \(self.currentNumberOfReads) reads, \(self.currentReadBytes) bytes, total frames read: \(i + 1)") + return (renderedFrame, CGFloat(videoStream.rotationAngle), CGFloat(videoStream.aspect), loop) + } + } + } + return (nil, CGFloat(videoStream.rotationAngle), CGFloat(videoStream.aspect), true) + } else { + return (nil, 0.0, 1.0, false) + } + } + + public func seek(timestamp: Double) { + if let stream = self.videoStream, let avFormatContext = self.avFormatContext { + let pts = CMTimeMakeWithSeconds(timestamp, preferredTimescale: stream.timebase.timescale) + avFormatContext.seekFrame(forStreamIndex: Int32(stream.index), pts: pts.value) + stream.decoder.reset() + } + } +} + +private enum UniversalSoftwareVideoSourceState { + case initializing + case failed + case ready + case generatingFrame +} + +private final class UniversalSoftwareVideoSourceThreadParams: NSObject { + let mediaBox: MediaBox + let fileReference: FileMediaReference + let state: ValuePromise + let cancelInitialization: Signal + + init(mediaBox: MediaBox, fileReference: FileMediaReference, state: ValuePromise, cancelInitialization: Signal) { + self.mediaBox = mediaBox + self.fileReference = fileReference + self.state = state + self.cancelInitialization = cancelInitialization + } +} + +private final class UniversalSoftwareVideoSourceTakeFrameParams: NSObject { + let timestamp: Double + let completion: (UIImage?) -> Void + let cancel: Signal + let requiredDataIsNotLocallyAvailable: () -> Void + + init(timestamp: Double, completion: @escaping (UIImage?) -> Void, cancel: Signal, requiredDataIsNotLocallyAvailable: @escaping () -> Void) { + self.timestamp = timestamp + self.completion = completion + self.cancel = cancel + self.requiredDataIsNotLocallyAvailable = requiredDataIsNotLocallyAvailable + } +} + +private final class UniversalSoftwareVideoSourceThread: NSObject { + @objc static func entryPoint(_ params: UniversalSoftwareVideoSourceThreadParams) { + let runLoop = RunLoop.current + + let timer = Timer(fireAt: .distantFuture, interval: 0.0, target: UniversalSoftwareVideoSourceThread.self, selector: #selector(UniversalSoftwareVideoSourceThread.none), userInfo: nil, repeats: false) + runLoop.add(timer, forMode: .common) + + let source = UniversalSoftwareVideoSourceImpl(mediaBox: params.mediaBox, fileReference: params.fileReference, state: params.state, cancelInitialization: params.cancelInitialization) + Thread.current.threadDictionary["source"] = source + + while true { + runLoop.run(mode: .default, before: .distantFuture) + if Thread.current.threadDictionary["UniversalSoftwareVideoSourceThread_stop"] != nil { + break + } + } + + Thread.current.threadDictionary.removeObject(forKey: "source") + } + + @objc static func none() { + } + + @objc static func stop() { + Thread.current.threadDictionary["UniversalSoftwareVideoSourceThread_stop"] = "true" + } + + @objc static func takeFrame(_ params: UniversalSoftwareVideoSourceTakeFrameParams) { + guard let source = Thread.current.threadDictionary["source"] as? UniversalSoftwareVideoSourceImpl else { + params.completion(nil) + return + } + source.cancelRead = params.cancel + source.requiredDataIsNotLocallyAvailable = params.requiredDataIsNotLocallyAvailable + source.state.set(.generatingFrame) + let startTime = CFAbsoluteTimeGetCurrent() + source.seek(timestamp: params.timestamp) + let image = source.readImage().0 + params.completion(image) + source.state.set(.ready) + print("take frame: \(CFAbsoluteTimeGetCurrent() - startTime) s") + } +} + +enum UniversalSoftwareVideoSourceTakeFrameResult { + case waitingForData + case image(UIImage?) +} + +final class UniversalSoftwareVideoSource { + private let thread: Thread + private let stateValue: ValuePromise = ValuePromise(.initializing, ignoreRepeated: true) + private let cancelInitialization: ValuePromise = ValuePromise(false) + + var ready: Signal { + return self.stateValue.get() + |> map { value -> Bool in + switch value { + case .ready: + return true + default: + return false + } + } + } + + init(mediaBox: MediaBox, fileReference: FileMediaReference) { + self.thread = Thread(target: UniversalSoftwareVideoSourceThread.self, selector: #selector(UniversalSoftwareVideoSourceThread.entryPoint(_:)), object: UniversalSoftwareVideoSourceThreadParams(mediaBox: mediaBox, fileReference: fileReference, state: self.stateValue, cancelInitialization: self.cancelInitialization.get())) + self.thread.name = "UniversalSoftwareVideoSource" + self.thread.start() + } + + deinit { + UniversalSoftwareVideoSourceThread.self.perform(#selector(UniversalSoftwareVideoSourceThread.stop), on: self.thread, with: nil, waitUntilDone: false) + self.cancelInitialization.set(true) + } + + public func takeFrame(at timestamp: Double) -> Signal { + return Signal { subscriber in + let cancel = ValuePromise(false) + UniversalSoftwareVideoSourceThread.self.perform(#selector(UniversalSoftwareVideoSourceThread.takeFrame(_:)), on: self.thread, with: UniversalSoftwareVideoSourceTakeFrameParams(timestamp: timestamp, completion: { image in + subscriber.putNext(.image(image)) + subscriber.putCompletion() + }, cancel: cancel.get(), requiredDataIsNotLocallyAvailable: { + subscriber.putNext(.waitingForData) + }), waitUntilDone: false) + + return ActionDisposable { + cancel.set(true) + } + } + } +} diff --git a/submodules/MediaPlayer/UniversalMediaPlayer_Xcode.xcodeproj/project.pbxproj b/submodules/MediaPlayer/UniversalMediaPlayer_Xcode.xcodeproj/project.pbxproj index 41bf15175f..9c8083ab4a 100644 --- a/submodules/MediaPlayer/UniversalMediaPlayer_Xcode.xcodeproj/project.pbxproj +++ b/submodules/MediaPlayer/UniversalMediaPlayer_Xcode.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + D03B054022D8866A0000BE1A /* MediaPlayerFramePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B053F22D8866A0000BE1A /* MediaPlayerFramePreview.swift */; }; + D03B054222D888A00000BE1A /* SoftwareVideoSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B054122D888A00000BE1A /* SoftwareVideoSource.swift */; }; D0750C6E22B28E6600BE5F6E /* RingBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = D0750C6B22B28E6500BE5F6E /* RingBuffer.m */; }; D0750C6F22B28E6600BE5F6E /* RingByteBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0750C6C22B28E6600BE5F6E /* RingByteBuffer.swift */; }; D0750C7022B28E6600BE5F6E /* RingBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = D0750C6D22B28E6600BE5F6E /* RingBuffer.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -37,9 +39,12 @@ D0AE325B22B286A70058D3BC /* MediaTrackDecodableFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE324922B286A70058D3BC /* MediaTrackDecodableFrame.swift */; }; D0AE325C22B286A70058D3BC /* MediaTrackFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE324A22B286A70058D3BC /* MediaTrackFrame.swift */; }; D0AE325E22B286C30058D3BC /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0AE325D22B286C30058D3BC /* AVFoundation.framework */; }; + D0E8B10C22D8B7E800C82570 /* UniversalSoftwareVideoSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8B10B22D8B7E800C82570 /* UniversalSoftwareVideoSource.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + D03B053F22D8866A0000BE1A /* MediaPlayerFramePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlayerFramePreview.swift; sourceTree = ""; }; + D03B054122D888A00000BE1A /* SoftwareVideoSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SoftwareVideoSource.swift; sourceTree = ""; }; D0750C6B22B28E6500BE5F6E /* RingBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RingBuffer.m; sourceTree = ""; }; D0750C6C22B28E6600BE5F6E /* RingByteBuffer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RingByteBuffer.swift; sourceTree = ""; }; D0750C6D22B28E6600BE5F6E /* RingBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RingBuffer.h; sourceTree = ""; }; @@ -72,6 +77,7 @@ D0AE324922B286A70058D3BC /* MediaTrackDecodableFrame.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaTrackDecodableFrame.swift; sourceTree = ""; }; D0AE324A22B286A70058D3BC /* MediaTrackFrame.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaTrackFrame.swift; sourceTree = ""; }; D0AE325D22B286C30058D3BC /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; + D0E8B10B22D8B7E800C82570 /* UniversalSoftwareVideoSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalSoftwareVideoSource.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -135,7 +141,10 @@ D0AE323E22B286A60058D3BC /* MediaTrackFrameBuffer.swift */, D0AE324222B286A60058D3BC /* MediaTrackFrameDecoder.swift */, D0AE323C22B286A50058D3BC /* VideoPlayerProxy.swift */, + D03B054122D888A00000BE1A /* SoftwareVideoSource.swift */, + D03B053F22D8866A0000BE1A /* MediaPlayerFramePreview.swift */, D0AE322222B285F70058D3BC /* UniversalMediaPlayer.h */, + D0E8B10B22D8B7E800C82570 /* UniversalSoftwareVideoSource.swift */, ); path = Sources; sourceTree = ""; @@ -241,6 +250,7 @@ D0AE325A22B286A70058D3BC /* FFMpegMediaVideoFrameDecoder.swift in Sources */, D0750C6E22B28E6600BE5F6E /* RingBuffer.m in Sources */, D0AE325422B286A70058D3BC /* MediaTrackFrameDecoder.swift in Sources */, + D0E8B10C22D8B7E800C82570 /* UniversalSoftwareVideoSource.swift in Sources */, D0AE325322B286A70058D3BC /* MediaPlayerNode.swift in Sources */, D0AE325122B286A70058D3BC /* MediaPlayer.swift in Sources */, D0AE325722B286A70058D3BC /* MediaPlaybackData.swift in Sources */, @@ -251,11 +261,13 @@ D0AE325222B286A70058D3BC /* FFMpegMediaFrameSourceContext.swift in Sources */, D0AE324E22B286A70058D3BC /* VideoPlayerProxy.swift in Sources */, D0AE325022B286A70058D3BC /* MediaTrackFrameBuffer.swift in Sources */, + D03B054022D8866A0000BE1A /* MediaPlayerFramePreview.swift in Sources */, D0AE325C22B286A70058D3BC /* MediaTrackFrame.swift in Sources */, D0AE324F22B286A70058D3BC /* MediaPlayerTimeTextNode.swift in Sources */, D0750C6F22B28E6600BE5F6E /* RingByteBuffer.swift in Sources */, D0AE325822B286A70058D3BC /* FFMpegMediaPassthroughVideoFrameDecoder.swift in Sources */, D0AE325B22B286A70058D3BC /* MediaTrackDecodableFrame.swift in Sources */, + D03B054222D888A00000BE1A /* SoftwareVideoSource.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/submodules/MtProtoKit/MTBackupAddressSignals.m b/submodules/MtProtoKit/MTBackupAddressSignals.m index 7f65721991..7eb4ee1c85 100644 --- a/submodules/MtProtoKit/MTBackupAddressSignals.m +++ b/submodules/MtProtoKit/MTBackupAddressSignals.m @@ -79,7 +79,7 @@ static NSData *base64_decode(NSString *str) { NSMutableArray *signals = [[NSMutableArray alloc] init]; for (NSString *host in hosts) { - MTSignal *signal = [[[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:[NSString stringWithFormat:@"https://%@/resolve?name=%@&type=16", host, isTesting ? @"tapv2.stel.com" : @"apv2.stel.com"]] headers:headers] mapToSignal:^MTSignal *(NSData *data) { + MTSignal *signal = [[[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:[NSString stringWithFormat:@"https://%@/resolve?name=%@&type=16", host, isTesting ? @"tapv3.stel.com" : @"apv3.stel.com"]] headers:headers] mapToSignal:^MTSignal *(NSData *data) { NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; if ([dict respondsToSelector:@selector(objectForKey:)]) { NSArray *answer = dict[@"Answer"]; diff --git a/submodules/Postbox/Postbox/MediaBox.swift b/submodules/Postbox/Postbox/MediaBox.swift index 9408d33f2f..9cd04f3ef1 100644 --- a/submodules/Postbox/Postbox/MediaBox.swift +++ b/submodules/Postbox/Postbox/MediaBox.swift @@ -561,7 +561,7 @@ public final class MediaBox { case .incremental: break case .partial: - break + subscriber.putNext(Data()) } } } diff --git a/submodules/SSignalKit/SwiftSignalKit/QueueLocalObject.swift b/submodules/SSignalKit/SwiftSignalKit/QueueLocalObject.swift index c30d0f4bee..9bdca6434f 100644 --- a/submodules/SSignalKit/SwiftSignalKit/QueueLocalObject.swift +++ b/submodules/SSignalKit/SwiftSignalKit/QueueLocalObject.swift @@ -1,7 +1,7 @@ import Foundation public final class QueueLocalObject { - private let queue: Queue + public let queue: Queue private var valueRef: Unmanaged? public init(queue: Queue, generate: @escaping () -> T) { diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 32af363d3a..48f6783946 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -10,7 +10,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-206066487] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) } dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) } dict[461151667] = { return Api.ChatFull.parse_chatFull($0) } - dict[277964371] = { return Api.ChatFull.parse_channelFull($0) } + dict[763976820] = { return Api.ChatFull.parse_channelFull($0) } dict[1465219162] = { return Api.PollResults.parse_pollResults($0) } dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) } dict[-636267638] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) } @@ -101,8 +101,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[997055186] = { return Api.PollAnswerVoters.parse_pollAnswerVoters($0) } dict[-1705233435] = { return Api.account.PasswordSettings.parse_passwordSettings($0) } dict[-288727837] = { return Api.LangPackLanguage.parse_langPackLanguage($0) } - dict[497489295] = { return Api.help.AppUpdate.parse_appUpdate($0) } dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) } + dict[497489295] = { return Api.help.AppUpdate.parse_appUpdate($0) } dict[-209337866] = { return Api.LangPackDifference.parse_langPackDifference($0) } dict[-1590738760] = { return Api.WallPaperSettings.parse_wallPaperSettings($0) } dict[1152191385] = { return Api.EmojiURL.parse_EmojiURL($0) } @@ -383,6 +383,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1129042607] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangePhoto($0) } dict[-1569748965] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeLinkedChat($0) } dict[241923758] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeLocation($0) } + dict[1401984889] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionToggleSlowMode($0) } dict[-526508104] = { return Api.help.ProxyData.parse_proxyDataEmpty($0) } dict[737668643] = { return Api.help.ProxyData.parse_proxyDataPromo($0) } dict[-543777747] = { return Api.auth.ExportedAuthorization.parse_exportedAuthorization($0) } diff --git a/submodules/TelegramApi/Sources/Api1.swift b/submodules/TelegramApi/Sources/Api1.swift index 47da8f6c43..ec550c5be8 100644 --- a/submodules/TelegramApi/Sources/Api1.swift +++ b/submodules/TelegramApi/Sources/Api1.swift @@ -51,7 +51,7 @@ public extension Api { } public enum ChatFull: TypeConstructorDescription { case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?) - case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, pts: Int32) + case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, pts: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -74,9 +74,9 @@ public extension Api { if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} break - case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let pts): + case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let pts): if boxed { - buffer.appendInt32(277964371) + buffer.appendInt32(763976820) } serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false) @@ -105,6 +105,8 @@ public extension Api { if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 14) != 0 {serializeInt32(linkedChatId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 15) != 0 {location!.serialize(buffer, true)} + if Int(flags) & Int(1 << 17) != 0 {serializeInt32(slowmodeSeconds!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 18) != 0 {serializeInt32(slowmodeNextSendDate!, buffer: buffer, boxed: false)} serializeInt32(pts, buffer: buffer, boxed: false) break } @@ -114,8 +116,8 @@ public extension Api { switch self { case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId): return ("chatFull", [("flags", flags), ("id", id), ("about", about), ("participants", participants), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("folderId", folderId)]) - case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let pts): - return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("location", location), ("pts", pts)]) + case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let pts): + return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("location", location), ("slowmodeSeconds", slowmodeSeconds), ("slowmodeNextSendDate", slowmodeNextSendDate), ("pts", pts)]) } } @@ -227,7 +229,11 @@ public extension Api { _23 = Api.parse(reader, signature: signature) as? Api.ChannelLocation } } var _24: Int32? - _24 = reader.readInt32() + if Int(_1!) & Int(1 << 17) != 0 {_24 = reader.readInt32() } + var _25: Int32? + if Int(_1!) & Int(1 << 18) != 0 {_25 = reader.readInt32() } + var _26: Int32? + _26 = reader.readInt32() let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil @@ -251,9 +257,11 @@ public extension Api { let _c21 = (Int(_1!) & Int(1 << 11) == 0) || _21 != nil let _c22 = (Int(_1!) & Int(1 << 14) == 0) || _22 != nil let _c23 = (Int(_1!) & Int(1 << 15) == 0) || _23 != nil - let _c24 = _24 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 { - return Api.ChatFull.channelFull(flags: _1!, id: _2!, about: _3!, participantsCount: _4, adminsCount: _5, kickedCount: _6, bannedCount: _7, onlineCount: _8, readInboxMaxId: _9!, readOutboxMaxId: _10!, unreadCount: _11!, chatPhoto: _12!, notifySettings: _13!, exportedInvite: _14!, botInfo: _15!, migratedFromChatId: _16, migratedFromMaxId: _17, pinnedMsgId: _18, stickerset: _19, availableMinId: _20, folderId: _21, linkedChatId: _22, location: _23, pts: _24!) + let _c24 = (Int(_1!) & Int(1 << 17) == 0) || _24 != nil + let _c25 = (Int(_1!) & Int(1 << 18) == 0) || _25 != nil + let _c26 = _26 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 { + return Api.ChatFull.channelFull(flags: _1!, id: _2!, about: _3!, participantsCount: _4, adminsCount: _5, kickedCount: _6, bannedCount: _7, onlineCount: _8, readInboxMaxId: _9!, readOutboxMaxId: _10!, unreadCount: _11!, chatPhoto: _12!, notifySettings: _13!, exportedInvite: _14!, botInfo: _15!, migratedFromChatId: _16, migratedFromMaxId: _17, pinnedMsgId: _18, stickerset: _19, availableMinId: _20, folderId: _21, linkedChatId: _22, location: _23, slowmodeSeconds: _24, slowmodeNextSendDate: _25, pts: _26!) } else { return nil @@ -3949,7 +3957,6 @@ public extension Api { case updateUserStatus(userId: Int32, status: Api.UserStatus) case updateUserName(userId: Int32, firstName: String, lastName: String, username: String) case updateUserPhoto(userId: Int32, date: Int32, photo: Api.UserProfilePhoto, previous: Api.Bool) - case updateContactLink(userId: Int32, myLink: Api.ContactLink, foreignLink: Api.ContactLink) case updateNewEncryptedMessage(message: Api.EncryptedMessage, qts: Int32) case updateEncryptedChatTyping(chatId: Int32) case updateEncryption(chat: Api.EncryptedChat, date: Int32) @@ -4088,14 +4095,6 @@ public extension Api { photo.serialize(buffer, true) previous.serialize(buffer, true) break - case .updateContactLink(let userId, let myLink, let foreignLink): - if boxed { - buffer.appendInt32(-1657903163) - } - serializeInt32(userId, buffer: buffer, boxed: false) - myLink.serialize(buffer, true) - foreignLink.serialize(buffer, true) - break case .updateNewEncryptedMessage(let message, let qts): if boxed { buffer.appendInt32(314359194) @@ -4644,8 +4643,6 @@ public extension Api { return ("updateUserName", [("userId", userId), ("firstName", firstName), ("lastName", lastName), ("username", username)]) case .updateUserPhoto(let userId, let date, let photo, let previous): return ("updateUserPhoto", [("userId", userId), ("date", date), ("photo", photo), ("previous", previous)]) - case .updateContactLink(let userId, let myLink, let foreignLink): - return ("updateContactLink", [("userId", userId), ("myLink", myLink), ("foreignLink", foreignLink)]) case .updateNewEncryptedMessage(let message, let qts): return ("updateNewEncryptedMessage", [("message", message), ("qts", qts)]) case .updateEncryptedChatTyping(let chatId): @@ -4933,27 +4930,6 @@ public extension Api { return nil } } - public static func parse_updateContactLink(_ reader: BufferReader) -> Update? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Api.ContactLink? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.ContactLink - } - var _3: Api.ContactLink? - if let signature = reader.readInt32() { - _3 = Api.parse(reader, signature: signature) as? Api.ContactLink - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.Update.updateContactLink(userId: _1!, myLink: _2!, foreignLink: _3!) - } - else { - return nil - } - } public static func parse_updateNewEncryptedMessage(_ reader: BufferReader) -> Update? { var _1: Api.EncryptedMessage? if let signature = reader.readInt32() { @@ -9232,6 +9208,7 @@ public extension Api { case channelAdminLogEventActionChangePhoto(prevPhoto: Api.Photo, newPhoto: Api.Photo) case channelAdminLogEventActionChangeLinkedChat(prevValue: Int32, newValue: Int32) case channelAdminLogEventActionChangeLocation(prevValue: Api.ChannelLocation, newValue: Api.ChannelLocation) + case channelAdminLogEventActionToggleSlowMode(prevValue: Int32, newValue: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -9366,6 +9343,13 @@ public extension Api { prevValue.serialize(buffer, true) newValue.serialize(buffer, true) break + case .channelAdminLogEventActionToggleSlowMode(let prevValue, let newValue): + if boxed { + buffer.appendInt32(1401984889) + } + serializeInt32(prevValue, buffer: buffer, boxed: false) + serializeInt32(newValue, buffer: buffer, boxed: false) + break } } @@ -9411,6 +9395,8 @@ public extension Api { return ("channelAdminLogEventActionChangeLinkedChat", [("prevValue", prevValue), ("newValue", newValue)]) case .channelAdminLogEventActionChangeLocation(let prevValue, let newValue): return ("channelAdminLogEventActionChangeLocation", [("prevValue", prevValue), ("newValue", newValue)]) + case .channelAdminLogEventActionToggleSlowMode(let prevValue, let newValue): + return ("channelAdminLogEventActionToggleSlowMode", [("prevValue", prevValue), ("newValue", newValue)]) } } @@ -9693,6 +9679,20 @@ public extension Api { return nil } } + public static func parse_channelAdminLogEventActionToggleSlowMode(_ reader: BufferReader) -> ChannelAdminLogEventAction? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChannelAdminLogEventAction.channelAdminLogEventActionToggleSlowMode(prevValue: _1!, newValue: _2!) + } + else { + return nil + } + } } public enum SecurePlainData: TypeConstructorDescription { @@ -17844,56 +17844,6 @@ public extension Api { } } - } - public enum ContactLink: TypeConstructorDescription { - case contactLinkUnknown - case contactLinkNone - case contactLinkContact - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .contactLinkUnknown: - if boxed { - buffer.appendInt32(1599050311) - } - - break - case .contactLinkNone: - if boxed { - buffer.appendInt32(-17968211) - } - - break - case .contactLinkContact: - if boxed { - buffer.appendInt32(-721239344) - } - - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .contactLinkUnknown: - return ("contactLinkUnknown", []) - case .contactLinkNone: - return ("contactLinkNone", []) - case .contactLinkContact: - return ("contactLinkContact", []) - } - } - - public static func parse_contactLinkUnknown(_ reader: BufferReader) -> ContactLink? { - return Api.ContactLink.contactLinkUnknown - } - public static func parse_contactLinkNone(_ reader: BufferReader) -> ContactLink? { - return Api.ContactLink.contactLinkNone - } - public static func parse_contactLinkContact(_ reader: BufferReader) -> ContactLink? { - return Api.ContactLink.contactLinkContact - } - } public enum WebDocument: TypeConstructorDescription { case webDocumentNoProxy(url: String, size: Int32, mimeType: String, attributes: [Api.DocumentAttribute]) diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index 1c9403deff..7df19d0089 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -1295,11 +1295,17 @@ public struct contacts { public extension Api { public struct help { public enum AppUpdate: TypeConstructorDescription { - case appUpdate(flags: Int32, id: Int32, version: String, text: String, entities: [Api.MessageEntity], document: Api.Document?, url: String?) case noAppUpdate + case appUpdate(flags: Int32, id: Int32, version: String, text: String, entities: [Api.MessageEntity], document: Api.Document?, url: String?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { + case .noAppUpdate: + if boxed { + buffer.appendInt32(-1000708810) + } + + break case .appUpdate(let flags, let id, let version, let text, let entities, let document, let url): if boxed { buffer.appendInt32(497489295) @@ -1315,25 +1321,22 @@ public struct help { } if Int(flags) & Int(1 << 1) != 0 {document!.serialize(buffer, true)} if Int(flags) & Int(1 << 2) != 0 {serializeString(url!, buffer: buffer, boxed: false)} - break - case .noAppUpdate: - if boxed { - buffer.appendInt32(-1000708810) - } - break } } public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .appUpdate(let flags, let id, let version, let text, let entities, let document, let url): - return ("appUpdate", [("flags", flags), ("id", id), ("version", version), ("text", text), ("entities", entities), ("document", document), ("url", url)]) case .noAppUpdate: return ("noAppUpdate", []) + case .appUpdate(let flags, let id, let version, let text, let entities, let document, let url): + return ("appUpdate", [("flags", flags), ("id", id), ("version", version), ("text", text), ("entities", entities), ("document", document), ("url", url)]) } } + public static func parse_noAppUpdate(_ reader: BufferReader) -> AppUpdate? { + return Api.help.AppUpdate.noAppUpdate + } public static func parse_appUpdate(_ reader: BufferReader) -> AppUpdate? { var _1: Int32? _1 = reader.readInt32() @@ -1367,9 +1370,6 @@ public struct help { return nil } } - public static func parse_noAppUpdate(_ reader: BufferReader) -> AppUpdate? { - return Api.help.AppUpdate.noAppUpdate - } } public enum PassportConfig: TypeConstructorDescription { diff --git a/submodules/TelegramApi/Sources/Api3.swift b/submodules/TelegramApi/Sources/Api3.swift index 7c38bd5aea..86116c0e3f 100644 --- a/submodules/TelegramApi/Sources/Api3.swift +++ b/submodules/TelegramApi/Sources/Api3.swift @@ -2922,6 +2922,20 @@ public extension Api { }) } + public static func hidePeerSettingsBar(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1336717624) + peer.serialize(buffer, true) + return (FunctionDescription(name: "messages.hidePeerSettingsBar", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + public static func searchGlobal(flags: Int32, folderId: Int32?, q: String, offsetRate: Int32, offsetPeer: Api.InputPeer, offsetId: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() buffer.appendInt32(-1083038300) @@ -2941,20 +2955,6 @@ public extension Api { return result }) } - - public static func hidePeerSettingsBar(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(1336717624) - peer.serialize(buffer, true) - return (FunctionDescription(name: "messages.hidePeerSettingsBar", parameters: [("peer", peer)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in - let reader = BufferReader(buffer) - var result: Api.Bool? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.Bool - } - return result - }) - } } public struct channels { public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { @@ -3505,6 +3505,21 @@ public extension Api { return result }) } + + public static func toggleSlowMode(channel: Api.InputChannel, seconds: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-304832784) + channel.serialize(buffer, true) + serializeInt32(seconds, buffer: buffer, boxed: false) + return (FunctionDescription(name: "channels.toggleSlowMode", parameters: [("channel", channel), ("seconds", seconds)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } } public struct payments { public static func getPaymentForm(msgId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { @@ -4265,20 +4280,6 @@ public extension Api { }) } - public static func getAppUpdate() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(-1372724842) - - return (FunctionDescription(name: "help.getAppUpdate", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.AppUpdate? in - let reader = BufferReader(buffer) - var result: Api.help.AppUpdate? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.help.AppUpdate - } - return result - }) - } - public static func getInviteText() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() buffer.appendInt32(1295590211) @@ -4479,6 +4480,20 @@ public extension Api { return result }) } + + public static func getAppUpdate(source: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1378703997) + serializeString(source, buffer: buffer, boxed: false) + return (FunctionDescription(name: "help.getAppUpdate", parameters: [("source", source)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.AppUpdate? in + let reader = BufferReader(buffer) + var result: Api.help.AppUpdate? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.help.AppUpdate + } + return result + }) + } } public struct updates { public static func getState() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { diff --git a/submodules/TelegramApi/TelegramApi_Xcode.xcodeproj/project.pbxproj b/submodules/TelegramApi/TelegramApi_Xcode.xcodeproj/project.pbxproj index 7dc67ed056..876fdfbd41 100644 --- a/submodules/TelegramApi/TelegramApi_Xcode.xcodeproj/project.pbxproj +++ b/submodules/TelegramApi/TelegramApi_Xcode.xcodeproj/project.pbxproj @@ -19,6 +19,7 @@ D035734722B5C9BF00F0920D /* SecretApiLayer46.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035734422B5C9BF00F0920D /* SecretApiLayer46.swift */; }; D035734822B5C9BF00F0920D /* SecretApiLayer8.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035734522B5C9BF00F0920D /* SecretApiLayer8.swift */; }; D035734922B5C9BF00F0920D /* SecretApiLayer73.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035734622B5C9BF00F0920D /* SecretApiLayer73.swift */; }; + D05FDC3A22CA453E0060BFE3 /* SecretApiLayer101.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09E9601A22C2BE4900B13673 /* SecretApiLayer101.swift */; }; D0CC4AC422BA46F30088F36D /* TelegramApi.h in Headers */ = {isa = PBXBuildFile; fileRef = D035732222B5C1FC00F0920D /* TelegramApi.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0CC4AC622BA46F30088F36D /* SecretApiLayer46.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035734422B5C9BF00F0920D /* SecretApiLayer46.swift */; }; D0CC4AC722BA46F30088F36D /* Api1.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035733222B5C29900F0920D /* Api1.swift */; }; @@ -47,9 +48,7 @@ D035734422B5C9BF00F0920D /* SecretApiLayer46.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretApiLayer46.swift; sourceTree = ""; }; D035734522B5C9BF00F0920D /* SecretApiLayer8.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretApiLayer8.swift; sourceTree = ""; }; D035734622B5C9BF00F0920D /* SecretApiLayer73.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretApiLayer73.swift; sourceTree = ""; }; - D0CC4AC122BA468D0088F36D /* TelegramApi copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "TelegramApi copy-Info.plist"; path = "/Users/keepcoder/Dropbox/Telegram-multi-acc/submodules/telegram-ios/submodules/TelegramApi/TelegramApi copy-Info.plist"; sourceTree = ""; }; D0CC4AD922BA46F30088F36D /* TelegramApiMac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TelegramApiMac.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - D0CC4ADA22BA46F40088F36D /* TelegramApi copy2-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "TelegramApi copy2-Info.plist"; path = "/Users/keepcoder/Dropbox/Telegram-multi-acc/submodules/telegram-ios/submodules/TelegramApi/TelegramApi copy2-Info.plist"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -76,8 +75,6 @@ D035732322B5C1FC00F0920D /* Info.plist */, D035732122B5C1FC00F0920D /* Sources */, D035732022B5C1FC00F0920D /* Products */, - D0CC4AC122BA468D0088F36D /* TelegramApi copy-Info.plist */, - D0CC4ADA22BA46F40088F36D /* TelegramApi copy2-Info.plist */, ); sourceTree = ""; }; @@ -241,6 +238,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D05FDC3A22CA453E0060BFE3 /* SecretApiLayer101.swift in Sources */, D0CC4AC622BA46F30088F36D /* SecretApiLayer46.swift in Sources */, D0CC4AC722BA46F30088F36D /* Api1.swift in Sources */, D0CC4AC822BA46F30088F36D /* Api0.swift in Sources */, @@ -257,6 +255,242 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ + D0276B8422C17FAA003155D8 /* ReleaseAppStore */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = ReleaseAppStore; + }; + D0276B8522C17FAA003155D8 /* ReleaseAppStore */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramApi; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = ReleaseAppStore; + }; + D0276B8622C17FAA003155D8 /* ReleaseAppStore */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramApi; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = macosx; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = ReleaseAppStore; + }; + D0276B8722C17FB2003155D8 /* ReleaseHockeyapp */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = ReleaseHockeyapp; + }; + D0276B8822C17FB2003155D8 /* ReleaseHockeyapp */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramApi; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = ReleaseHockeyapp; + }; + D0276B8922C17FB2003155D8 /* ReleaseHockeyapp */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = org.telegram.TelegramApi; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = macosx; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = ReleaseHockeyapp; + }; D035732522B5C1FC00F0920D /* DebugHockeyapp */ = { isa = XCBuildConfiguration; buildSettings = { @@ -818,7 +1052,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "TelegramApi copy2-Info.plist"; + INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -850,7 +1084,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "TelegramApi copy2-Info.plist"; + INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -882,7 +1116,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "TelegramApi copy2-Info.plist"; + INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -914,7 +1148,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "TelegramApi copy2-Info.plist"; + INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -946,7 +1180,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "TelegramApi copy2-Info.plist"; + INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -977,7 +1211,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = "TelegramApi copy2-Info.plist"; + INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -1009,6 +1243,8 @@ D035732A22B5C23200F0920D /* DebugAppStoreLLC */, D035732622B5C1FC00F0920D /* ReleaseHockeyappInternal */, D035732C22B5C24100F0920D /* ReleaseAppStoreLLC */, + D0276B8422C17FAA003155D8 /* ReleaseAppStore */, + D0276B8722C17FB2003155D8 /* ReleaseHockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = ReleaseHockeyappInternal; @@ -1022,6 +1258,8 @@ D035732B22B5C23200F0920D /* DebugAppStoreLLC */, D035732922B5C1FC00F0920D /* ReleaseHockeyappInternal */, D035732D22B5C24100F0920D /* ReleaseAppStoreLLC */, + D0276B8522C17FAA003155D8 /* ReleaseAppStore */, + D0276B8822C17FB2003155D8 /* ReleaseHockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = ReleaseHockeyappInternal; @@ -1035,6 +1273,8 @@ D0CC4AD622BA46F30088F36D /* DebugAppStoreLLC */, D0CC4AD722BA46F30088F36D /* ReleaseHockeyappInternal */, D0CC4AD822BA46F30088F36D /* ReleaseAppStoreLLC */, + D0276B8622C17FAA003155D8 /* ReleaseAppStore */, + D0276B8922C17FB2003155D8 /* ReleaseHockeyapp */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = ReleaseHockeyappInternal; diff --git a/submodules/TelegramCore/TelegramCore/AccountManager.swift b/submodules/TelegramCore/TelegramCore/AccountManager.swift index 2bd1d676a7..6a342249c7 100644 --- a/submodules/TelegramCore/TelegramCore/AccountManager.swift +++ b/submodules/TelegramCore/TelegramCore/AccountManager.swift @@ -137,6 +137,7 @@ private var declaredEncodables: Void = { declareEncodable(TelegramMediaPoll.self, f: { TelegramMediaPoll(decoder: $0) }) declareEncodable(TelegramMediaUnsupported.self, f: { TelegramMediaUnsupported(decoder: $0) }) declareEncodable(ContactsSettings.self, f: { ContactsSettings(decoder: $0) }) + declareEncodable(SecretChatSettings.self, f: { SecretChatSettings(decoder: $0) }) declareEncodable(EmojiKeywordCollectionInfo.self, f: { EmojiKeywordCollectionInfo(decoder: $0) }) declareEncodable(EmojiKeywordItem.self, f: { EmojiKeywordItem(decoder: $0) }) declareEncodable(SynchronizeEmojiKeywordsOperation.self, f: { SynchronizeEmojiKeywordsOperation(decoder: $0) }) diff --git a/submodules/TelegramCore/TelegramCore/AccountStateManagementUtils.swift b/submodules/TelegramCore/TelegramCore/AccountStateManagementUtils.swift index 11a193fa6d..6b70dacb3f 100644 --- a/submodules/TelegramCore/TelegramCore/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/TelegramCore/AccountStateManagementUtils.swift @@ -2075,6 +2075,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP var isContactUpdates: [(PeerId, Bool)] = [] var stickerPackOperations: [AccountStateUpdateStickerPacksOperation] = [] var recentlyUsedStickers: [MediaId: (MessageIndex, TelegramMediaFile)] = [:] + var slowModeLastMessageTimeouts:[PeerId : Int32] = [:] var recentlyUsedGifs: [MediaId: (MessageIndex, TelegramMediaFile)] = [:] var syncRecentGifs = false var langPackDifferences: [String: [Api.LangPackDifference]] = [:] @@ -2181,6 +2182,11 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP } } } + if !message.flags.contains(.Incoming) && !message.flags.contains(.Unsent) { + if message.id.peerId.namespace == Namespaces.Peer.CloudChannel { + slowModeLastMessageTimeouts[message.id.peerId] = max(slowModeLastMessageTimeouts[message.id.peerId] ?? 0, message.timestamp) + } + } if !message.flags.contains(.Incoming), message.forwardInfo == nil { inner: for media in message.media { @@ -2713,6 +2719,22 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP } } + if !slowModeLastMessageTimeouts.isEmpty { + var peerIds:Set = Set() + var cachedDatas:[PeerId : CachedChannelData] = [:] + for (peerId, timeout) in slowModeLastMessageTimeouts { + var cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData ?? CachedChannelData() + if let slowModeTimeout = cachedData.slowModeTimeout { + cachedData = cachedData.withUpdatedSlowModeValidUntilTimestamp(slowModeValidUntilTimestamp: timeout + slowModeTimeout) + peerIds.insert(peerId) + cachedDatas[peerId] = cachedData + } + } + transaction.updatePeerCachedData(peerIds: peerIds, update: { peerId, current in + return cachedDatas[peerId] ?? current + }) + } + if syncRecentGifs { addSynchronizeSavedGifsOperation(transaction: transaction, operation: .sync) } else { diff --git a/submodules/TelegramCore/TelegramCore/ApiGroupOrChannel.swift b/submodules/TelegramCore/TelegramCore/ApiGroupOrChannel.swift index 0999f89c2f..66a729e1ff 100644 --- a/submodules/TelegramCore/TelegramCore/ApiGroupOrChannel.swift +++ b/submodules/TelegramCore/TelegramCore/ApiGroupOrChannel.swift @@ -96,6 +96,9 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? { if (flags & Int32(1 << 19)) != 0 { channelFlags.insert(.isScam) } + if (flags & Int32(1 << 21)) != 0 { + channelFlags.insert(.hasGeo) + } let restrictionInfo: PeerAccessRestrictionInfo? if let restrictionReason = restrictionReason { diff --git a/submodules/TelegramCore/TelegramCore/AppUpdate.swift b/submodules/TelegramCore/TelegramCore/AppUpdate.swift index 0806e9e602..41cb4ae90f 100644 --- a/submodules/TelegramCore/TelegramCore/AppUpdate.swift +++ b/submodules/TelegramCore/TelegramCore/AppUpdate.swift @@ -37,7 +37,7 @@ extension AppUpdateInfo { } func managedAppUpdateInfo(network: Network, stateManager: AccountStateManager) -> Signal { - let poll = network.request(Api.functions.help.getAppUpdate()) + let poll = network.request(Api.functions.help.getAppUpdate(source: "")) |> retryRequest |> mapToSignal { [weak stateManager] result -> Signal in let updated = AppUpdateInfo(apiAppUpdate: result) diff --git a/submodules/TelegramCore/TelegramCore/ApplyUpdateMessage.swift b/submodules/TelegramCore/TelegramCore/ApplyUpdateMessage.swift index 48bb0cb376..cc3125d507 100644 --- a/submodules/TelegramCore/TelegramCore/ApplyUpdateMessage.swift +++ b/submodules/TelegramCore/TelegramCore/ApplyUpdateMessage.swift @@ -165,6 +165,20 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes let (tags, globalTags) = tagsForStoreMessage(incoming: currentMessage.flags.contains(.Incoming), attributes: attributes, media: media, textEntities: entitiesAttribute?.entities) + if currentMessage.id.peerId.namespace == Namespaces.Peer.CloudChannel, !currentMessage.flags.contains(.Incoming) { + let peerId = currentMessage.id.peerId + transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, current in + var cachedData = current as? CachedChannelData ?? CachedChannelData() + if let slowModeTimeout = cachedData.slowModeTimeout { + cachedData = cachedData.withUpdatedSlowModeValidUntilTimestamp(slowModeValidUntilTimestamp: currentMessage.timestamp + slowModeTimeout) + return cachedData + } else { + return current + } + }) + } + + return .update(StoreMessage(id: updatedId, globallyUniqueId: nil, groupingKey: currentMessage.groupingKey, timestamp: updatedTimestamp ?? currentMessage.timestamp, flags: [], tags: tags, globalTags: globalTags, localTags: currentMessage.localTags, forwardInfo: forwardInfo, authorId: currentMessage.author?.id, text: text, attributes: attributes, media: media)) }) for file in sentStickers { @@ -173,6 +187,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes for file in sentGifs { transaction.addOrMoveToFirstPositionOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudRecentGifs, item: OrderedItemListEntry(id: RecentMediaItemId(file.fileId).rawValue, contents: RecentMediaItem(file)), removeTailIfCountExceeds: 200) } + stateManager.addUpdates(result) } } diff --git a/submodules/TelegramCore/TelegramCore/CachedChannelData.swift b/submodules/TelegramCore/TelegramCore/CachedChannelData.swift index 90f775e22d..37a13fa5da 100644 --- a/submodules/TelegramCore/TelegramCore/CachedChannelData.swift +++ b/submodules/TelegramCore/TelegramCore/CachedChannelData.swift @@ -170,6 +170,8 @@ public final class CachedChannelData: CachedPeerData { public let migrationReference: ChannelMigrationReference? public let linkedDiscussionPeerId: PeerId? public let peerGeoLocation: PeerGeoLocation? + public let slowModeTimeout: Int32? + public let slowModeValidUntilTimestamp: Int32? public let peerIds: Set public let messageIds: Set @@ -193,9 +195,11 @@ public final class CachedChannelData: CachedPeerData { self.migrationReference = nil self.linkedDiscussionPeerId = nil self.peerGeoLocation = nil + self.slowModeTimeout = nil + self.slowModeValidUntilTimestamp = nil } - init(isNotAccessible: Bool, flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?, minAvailableMessageId: MessageId?, migrationReference: ChannelMigrationReference?, linkedDiscussionPeerId: PeerId?, peerGeoLocation: PeerGeoLocation?) { + init(isNotAccessible: Bool, flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?, minAvailableMessageId: MessageId?, migrationReference: ChannelMigrationReference?, linkedDiscussionPeerId: PeerId?, peerGeoLocation: PeerGeoLocation?, slowModeTimeout: Int32?, slowModeValidUntilTimestamp: Int32?) { self.isNotAccessible = isNotAccessible self.flags = flags self.about = about @@ -209,6 +213,8 @@ public final class CachedChannelData: CachedPeerData { self.migrationReference = migrationReference self.linkedDiscussionPeerId = linkedDiscussionPeerId self.peerGeoLocation = peerGeoLocation + self.slowModeTimeout = slowModeTimeout + self.slowModeValidUntilTimestamp = slowModeValidUntilTimestamp var peerIds = Set() for botInfo in botInfos { @@ -229,55 +235,63 @@ public final class CachedChannelData: CachedPeerData { } func withUpdatedIsNotAccessible(_ isNotAccessible: Bool) -> CachedChannelData { - return CachedChannelData(isNotAccessible: isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation) + return CachedChannelData(isNotAccessible: isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) } func withUpdatedFlags(_ flags: CachedChannelFlags) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) } func withUpdatedAbout(_ about: String?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) } func withUpdatedParticipantsSummary(_ participantsSummary: CachedChannelParticipantsSummary) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) } func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) } func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) } func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) } func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) } func withUpdatedStickerPack(_ stickerPack: StickerPackCollectionInfo?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) } func withUpdatedMinAvailableMessageId(_ minAvailableMessageId: MessageId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) } func withUpdatedMigrationReference(_ migrationReference: ChannelMigrationReference?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) } func withUpdatedLinkedDiscussionPeerId(_ linkedDiscussionPeerId: PeerId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) } func withUpdatedPeerGeoLocation(peerGeoLocation: PeerGeoLocation?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: peerGeoLocation) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) + } + + func withUpdatedSlowModeTimeout(slowModeTimeout: Int32?) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp) + } + + func withUpdatedSlowModeValidUntilTimestamp(slowModeValidUntilTimestamp: Int32?) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: slowModeValidUntilTimestamp) } public init(decoder: PostboxDecoder) { @@ -329,6 +343,9 @@ public final class CachedChannelData: CachedPeerData { self.peerGeoLocation = nil } + self.slowModeTimeout = decoder.decodeOptionalInt32ForKey("smt") + self.slowModeValidUntilTimestamp = decoder.decodeOptionalInt32ForKey("smv") + if let linkedDiscussionPeerId = self.linkedDiscussionPeerId { peerIds.insert(linkedDiscussionPeerId) } @@ -400,6 +417,17 @@ public final class CachedChannelData: CachedPeerData { } else { encoder.encodeNil(forKey: "pgl") } + + if let slowModeTimeout = self.slowModeTimeout { + encoder.encodeInt32(slowModeTimeout, forKey: "smt") + } else { + encoder.encodeNil(forKey: "smt") + } + if let slowModeValidUntilTimestamp = self.slowModeValidUntilTimestamp { + encoder.encodeInt32(slowModeValidUntilTimestamp, forKey: "smv") + } else { + encoder.encodeNil(forKey: "smv") + } } public func isEqual(to: CachedPeerData) -> Bool { @@ -459,6 +487,14 @@ public final class CachedChannelData: CachedPeerData { return false } + if other.slowModeTimeout != self.slowModeTimeout { + return false + } + + if other.slowModeValidUntilTimestamp != self.slowModeValidUntilTimestamp { + return false + } + return true } } diff --git a/submodules/TelegramCore/TelegramCore/ChannelAdminEventLogs.swift b/submodules/TelegramCore/TelegramCore/ChannelAdminEventLogs.swift index 82886b9bc2..a169b27cc7 100644 --- a/submodules/TelegramCore/TelegramCore/ChannelAdminEventLogs.swift +++ b/submodules/TelegramCore/TelegramCore/ChannelAdminEventLogs.swift @@ -218,6 +218,8 @@ public func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: Pe action = .linkedPeerUpdated(previous: prevValue == 0 ? nil : peers[PeerId(namespace: Namespaces.Peer.CloudChannel, id: prevValue)], updated: newValue == 0 ? nil : peers[PeerId(namespace: Namespaces.Peer.CloudChannel, id: newValue)]) case let .channelAdminLogEventActionChangeLocation(prevValue, newValue): action = .changeGeoLocation(previous: PeerGeoLocation(apiLocation: prevValue), updated: PeerGeoLocation(apiLocation: newValue)) + case let .channelAdminLogEventActionToggleSlowMode(prevValue, newValue): + break } let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) if let action = action { diff --git a/submodules/TelegramCore/TelegramCore/Fetch.swift b/submodules/TelegramCore/TelegramCore/Fetch.swift index f26389e16b..95f4a430ad 100644 --- a/submodules/TelegramCore/TelegramCore/Fetch.swift +++ b/submodules/TelegramCore/TelegramCore/Fetch.swift @@ -9,6 +9,21 @@ import SwiftSignalKit import Photos #endif +private final class MediaResourceDataCopyFile : MediaResourceDataFetchCopyLocalItem { + let path: String + init(path: String) { + self.path = path + } + func copyTo(url: URL) -> Bool { + do { + try FileManager.default.copyItem(at: URL(fileURLWithPath: self.path), to: url) + return true + } catch { + return false + } + } +} + private func fetchCloudMediaLocation(account: Account, resource: TelegramMediaResource, datacenterId: Int, size: Int?, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?) -> Signal { return multipartFetch(postbox: account.postbox, network: account.network, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, resource: resource, datacenterId: datacenterId, size: size, intervals: intervals, parameters: parameters) } @@ -19,12 +34,8 @@ private func fetchLocalFileResource(path: String, move: Bool) -> Signal, MediaBoxFetchPriority)? = nil, statsCategory: MediaResourceStatsCategory = .generic, reportResultStatus: Bool = false, preferBackgroundReferenceRevalidation: Bool = false, continueInBackground: Bool = false) -> Signal { - return fetchedMediaResource(postbox: postbox, reference: reference, ranges: range.flatMap({ [$0] }), statsCategory: statsCategory, reportResultStatus: reportResultStatus, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground) +public func fetchedMediaResource(mediaBox: MediaBox, reference: MediaResourceReference, range: (Range, MediaBoxFetchPriority)? = nil, statsCategory: MediaResourceStatsCategory = .generic, reportResultStatus: Bool = false, preferBackgroundReferenceRevalidation: Bool = false, continueInBackground: Bool = false) -> Signal { + return fetchedMediaResource(mediaBox: mediaBox, reference: reference, ranges: range.flatMap({ [$0] }), statsCategory: statsCategory, reportResultStatus: reportResultStatus, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground) } -public func fetchedMediaResource(postbox: Postbox, reference: MediaResourceReference, ranges: [(Range, MediaBoxFetchPriority)]?, statsCategory: MediaResourceStatsCategory = .generic, reportResultStatus: Bool = false, preferBackgroundReferenceRevalidation: Bool = false, continueInBackground: Bool = false) -> Signal { +public func fetchedMediaResource(mediaBox: MediaBox, reference: MediaResourceReference, ranges: [(Range, MediaBoxFetchPriority)]?, statsCategory: MediaResourceStatsCategory = .generic, reportResultStatus: Bool = false, preferBackgroundReferenceRevalidation: Bool = false, continueInBackground: Bool = false) -> Signal { if let ranges = ranges { let signals = ranges.map { (range, priority) -> Signal in - return postbox.mediaBox.fetchedResourceData(reference.resource, in: range, priority: priority, parameters: MediaResourceFetchParameters(tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground))) + return mediaBox.fetchedResourceData(reference.resource, in: range, priority: priority, parameters: MediaResourceFetchParameters(tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground))) } return combineLatest(signals) |> ignoreValues |> map { _ -> FetchResourceSourceType in .local } |> then(.single(.local)) } else { - return postbox.mediaBox.fetchedResource(reference.resource, parameters: MediaResourceFetchParameters(tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground)), implNext: reportResultStatus) + return mediaBox.fetchedResource(reference.resource, parameters: MediaResourceFetchParameters(tag: TelegramMediaResourceFetchTag(statsCategory: statsCategory), info: TelegramCloudMediaResourceFetchInfo(reference: reference, preferBackgroundReferenceRevalidation: preferBackgroundReferenceRevalidation, continueInBackground: continueInBackground)), implNext: reportResultStatus) } } diff --git a/submodules/TelegramCore/TelegramCore/MultipartUpload.swift b/submodules/TelegramCore/TelegramCore/MultipartUpload.swift index d402a559ff..4f006c7ab9 100644 --- a/submodules/TelegramCore/TelegramCore/MultipartUpload.swift +++ b/submodules/TelegramCore/TelegramCore/MultipartUpload.swift @@ -328,15 +328,29 @@ private final class MultipartUploadManager { if nextOffset < resourceData.size && partSize > 0 && (resourceData.complete || partSize == self.defaultPartSize) { let partIndex = partOffset / self.defaultPartSize - let fileData: Data? + let partData: Data? switch resourceData { case let .resourceData(data): - fileData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: [.alwaysMapped]) + if let file = ManagedFile(queue: nil, path: data.path, mode: .read) { + file.seek(position: Int64(partOffset)) + let data = file.readData(count: partSize) + if data.count == partSize { + partData = data + } else { + partData = nil + } + } else { + partData = nil + } case let .data(data): - fileData = data + if data.count >= partOffset + partSize { + partData = data.subdata(in: partOffset ..< (partOffset + partSize)) + } else { + partData = nil + } } - if let fileData = fileData, fileData.count >= partOffset + partSize { - let partData = self.state.transform(data: fileData.subdata(in: partOffset ..< (partOffset + partSize))) + if let partData = partData { + let partData = self.state.transform(data: partData) var currentBigTotalParts = self.bigTotalParts if self.bigParts && resourceData.complete && partOffset + partSize == resourceData.size { currentBigTotalParts = (resourceData.size / self.defaultPartSize) + (resourceData.size % self.defaultPartSize == 0 ? 0 : 1) @@ -416,7 +430,7 @@ func multipartUpload(network: Network, postbox: Postbox, source: MultipartUpload case let .resource(resource): dataSignal = postbox.mediaBox.resourceData(resource.resource, option: .incremental(waitUntilFetchStatus: true)) |> map { MultipartUploadData.resourceData($0) } headerSize = resource.resource.headerSize - fetchedResource = fetchedMediaResource(postbox: postbox, reference: resource) + fetchedResource = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resource) |> map { _ in } case let .data(data): dataSignal = .single(.data(data)) diff --git a/submodules/TelegramCore/TelegramCore/Namespaces.swift b/submodules/TelegramCore/TelegramCore/Namespaces.swift index 15007d023b..76df73b2ee 100644 --- a/submodules/TelegramCore/TelegramCore/Namespaces.swift +++ b/submodules/TelegramCore/TelegramCore/Namespaces.swift @@ -153,6 +153,7 @@ private enum PreferencesKeyValues: Int32 { case appConfiguration = 14 case searchBotsConfiguration = 15 case contactsSettings = 16 + case secretChatSettings = 17 } public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey { @@ -245,6 +246,11 @@ public struct PreferencesKeys { key.setInt32(0, value: PreferencesKeyValues.contactsSettings.rawValue) return key }() + public static let secretChatSettings: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.secretChatSettings.rawValue) + return key + }() } private enum SharedDataKeyValues: Int32 { diff --git a/submodules/TelegramCore/TelegramCore/SecretChatSettings.swift b/submodules/TelegramCore/TelegramCore/SecretChatSettings.swift new file mode 100644 index 0000000000..10c9e50f9d --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SecretChatSettings.swift @@ -0,0 +1,34 @@ +import Foundation +#if os(macOS) +import PostboxMac +#else +import Postbox +#endif + +public struct SecretChatSettings: Equatable, PreferencesEntry { + public private(set) var acceptOnThisDevice: Bool + + public static var defaultSettings: SecretChatSettings { + return SecretChatSettings(acceptOnThisDevice: true) + } + + public init(acceptOnThisDevice: Bool) { + self.acceptOnThisDevice = acceptOnThisDevice + } + + public init(decoder: PostboxDecoder) { + self.acceptOnThisDevice = decoder.decodeInt32ForKey("acceptOnThisDevice", orElse: 1) != 0 + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.acceptOnThisDevice ? 1 : 0, forKey: "acceptOnThisDevice") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? SecretChatSettings { + return self == to + } else { + return false + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/Serialization.swift b/submodules/TelegramCore/TelegramCore/Serialization.swift index f1cb480ddc..2a78e8b6c2 100644 --- a/submodules/TelegramCore/TelegramCore/Serialization.swift +++ b/submodules/TelegramCore/TelegramCore/Serialization.swift @@ -220,7 +220,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 103 + return 104 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/submodules/TelegramCore/TelegramCore/SlowMode.swift b/submodules/TelegramCore/TelegramCore/SlowMode.swift new file mode 100644 index 0000000000..8bb61e5154 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/SlowMode.swift @@ -0,0 +1,40 @@ +#if os(macOS) +import PostboxMac +import SwiftSignalKitMac +import TelegramApiMac +#else +import Postbox +import TelegramApi +import SwiftSignalKit +#endif + +public enum UpdateChannelSlowModeError { + case generic +} + +public func updateChannelSlowModeInteractively(postbox: Postbox, network: Network, accountStateManager: AccountStateManager, peerId: PeerId, timeout: Int32?) -> Signal { + return postbox.transaction { transaction -> Peer? in + return transaction.getPeer(peerId) + } + |> introduceError(UpdateChannelSlowModeError.self) + |> mapToSignal { peer in + guard let peer = peer, let inputChannel = apiInputChannel(peer) else { + return .fail(.generic) + } + + return network.request(Api.functions.channels.toggleSlowMode(channel: inputChannel, seconds: timeout ?? 0)) + |> `catch` { _ -> Signal in + return .fail(.generic) + } + |> mapToSignal { updates -> Signal in + accountStateManager.addUpdates(updates) + return postbox.transaction { transaction -> Void in + transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, currentData in + let currentData = currentData as? CachedChannelData ?? CachedChannelData() + return currentData.withUpdatedSlowModeTimeout(slowModeTimeout: timeout) + }) + } + |> introduceError(UpdateChannelSlowModeError.self) + } + } +} diff --git a/submodules/TelegramCore/TelegramCore/StickerManagement.swift b/submodules/TelegramCore/TelegramCore/StickerManagement.swift index b4e594340d..f38cd1a46b 100644 --- a/submodules/TelegramCore/TelegramCore/StickerManagement.swift +++ b/submodules/TelegramCore/TelegramCore/StickerManagement.swift @@ -46,7 +46,7 @@ func updatedFeaturedStickerPacks(network: Network, postbox: Postbox) -> Signal retryRequest |> mapToSignal { result -> Signal in return postbox.transaction { transaction -> Void in diff --git a/submodules/TelegramCore/TelegramCore/TelegramChannel.swift b/submodules/TelegramCore/TelegramCore/TelegramChannel.swift index 0ccf6f3f62..ee405845eb 100644 --- a/submodules/TelegramCore/TelegramCore/TelegramChannel.swift +++ b/submodules/TelegramCore/TelegramCore/TelegramChannel.swift @@ -144,6 +144,7 @@ public struct TelegramChannelFlags: OptionSet { public static let isVerified = TelegramChannelFlags(rawValue: 1 << 0) public static let isCreator = TelegramChannelFlags(rawValue: 1 << 1) public static let isScam = TelegramChannelFlags(rawValue: 1 << 2) + public static let hasGeo = TelegramChannelFlags(rawValue: 1 << 3) } public final class TelegramChannel: Peer { diff --git a/submodules/TelegramCore/TelegramCore/TelegramMediaFile.swift b/submodules/TelegramCore/TelegramCore/TelegramMediaFile.swift index f9006150bd..143062cdfe 100644 --- a/submodules/TelegramCore/TelegramCore/TelegramMediaFile.swift +++ b/submodules/TelegramCore/TelegramCore/TelegramMediaFile.swift @@ -330,7 +330,7 @@ public final class TelegramMediaFile: Media, Equatable { public var isSticker: Bool { for attribute in self.attributes { if case .Sticker = attribute { - return true + return !isAnimatedSticker } } return false @@ -365,10 +365,13 @@ public final class TelegramMediaFile: Media, Equatable { public var isAnimatedSticker: Bool { if let _ = self.fileName, self.mimeType == "application/x-tgsticker" { - return true - } else { - return false + for attribute in self.attributes { + if case .Sticker = attribute { + return true + } + } } + return false } public var isMusic: Bool { diff --git a/submodules/TelegramCore/TelegramCore/UpdateCachedPeerData.swift b/submodules/TelegramCore/TelegramCore/UpdateCachedPeerData.swift index 6d13805ae1..46d1bfeb4f 100644 --- a/submodules/TelegramCore/TelegramCore/UpdateCachedPeerData.swift +++ b/submodules/TelegramCore/TelegramCore/UpdateCachedPeerData.swift @@ -280,7 +280,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI } switch fullChat { - case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, _, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, folderId, linkedChatId, location, pts): + case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, _, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, folderId, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, pts): var channelFlags = CachedChannelFlags() if (flags & (1 << 3)) != 0 { channelFlags.insert(.canDisplayParticipants) @@ -403,6 +403,8 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI .withUpdatedMigrationReference(migrationReference) .withUpdatedLinkedDiscussionPeerId(linkedDiscussionPeerId) .withUpdatedPeerGeoLocation(peerGeoLocation: peerGeoLocation) + .withUpdatedSlowModeTimeout(slowModeTimeout: slowmodeSeconds) + .withUpdatedSlowModeValidUntilTimestamp(slowModeValidUntilTimestamp: slowmodeNextSendDate) }) if let minAvailableMessageId = minAvailableMessageId, minAvailableMessageIdUpdated { diff --git a/submodules/TelegramCore/TelegramCore/UpdateSecretChat.swift b/submodules/TelegramCore/TelegramCore/UpdateSecretChat.swift index feb89aa59f..5231ea66bf 100644 --- a/submodules/TelegramCore/TelegramCore/UpdateSecretChat.swift +++ b/submodules/TelegramCore/TelegramCore/UpdateSecretChat.swift @@ -24,6 +24,7 @@ struct SecretChatRequestData { func updateSecretChat(accountPeerId: PeerId, transaction: Transaction, chat: Api.EncryptedChat, requestData: SecretChatRequestData?) { let currentPeer = transaction.getPeer(chat.peerId) as? TelegramSecretChat let currentState = transaction.getPeerChatState(chat.peerId) as? SecretChatState + let settings = transaction.getPreferencesEntry(key: PreferencesKeys.secretChatSettings) as? SecretChatSettings ?? SecretChatSettings.defaultSettings assert((currentPeer == nil) == (currentState == nil)) switch chat { case let .encryptedChat(_, _, _, adminId, _, gAOrB, remoteKeyFingerprint): @@ -61,7 +62,7 @@ func updateSecretChat(accountPeerId: PeerId, transaction: Transaction, chat: Api updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(SecretChatSequenceBasedLayerState(layerNegotiationState: SecretChatLayerNegotiationState(activeLayer: .layer46, locallyRequestedLayer: nil, remotelyRequestedLayer: nil), rekeyState: nil, baseIncomingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: currentPeer.id, tag: OperationLogTags.SecretIncomingDecrypted), baseOutgoingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: currentPeer.id, tag: OperationLogTags.SecretOutgoing), topProcessedCanonicalIncomingOperationIndex: nil))) updatedState = updatedState.withUpdatedKeyFingerprint(SecretChatKeyFingerprint(sha1: SecretChatKeySha1Fingerprint(digest: sha1Digest(key)), sha256: SecretChatKeySha256Fingerprint(digest: sha256Digest(key)))) - + updatedState = secretChatAddReportCurrentLayerSupportOperationAndUpdateRequestedLayer(transaction: transaction, peerId: currentPeer.id, state: updatedState) transaction.setPeerChatState(currentPeer.id, state: updatedState) @@ -88,25 +89,31 @@ func updateSecretChat(accountPeerId: PeerId, transaction: Transaction, chat: Api break case let .encryptedChatRequested(_, accessHash, date, adminId, participantId, gA): if currentPeer == nil && participantId == accountPeerId.id { - let state = SecretChatState(role: .participant, embeddedState: .handshake(.accepting), keychain: SecretChatKeychain(keys: []), keyFingerprint: nil, messageAutoremoveTimeout: nil) - - let bBytes = malloc(256)! - let randomStatus = SecRandomCopyBytes(nil, 256, bBytes.assumingMemoryBound(to: UInt8.self)) - let b = MemoryBuffer(memory: bBytes, capacity: 256, length: 256, freeWhenDone: true) - if randomStatus == 0 { - let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: chat.peerId, operation: .initialHandshakeAccept(gA: MemoryBuffer(gA), accessHash: accessHash, b: b), state: state) - transaction.setPeerChatState(chat.peerId, state: updatedState) + if settings.acceptOnThisDevice { + let state = SecretChatState(role: .participant, embeddedState: .handshake(.accepting), keychain: SecretChatKeychain(keys: []), keyFingerprint: nil, messageAutoremoveTimeout: nil) - let peer = TelegramSecretChat(id: chat.peerId, creationDate: date, regularPeerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: adminId), accessHash: accessHash, role: updatedState.role, embeddedState: updatedState.embeddedState.peerState, messageAutoremoveTimeout: nil) - updatePeers(transaction: transaction, peers: [peer], update: { _, updated in return updated }) - transaction.resetIncomingReadStates([peer.id: [ - Namespaces.Message.SecretIncoming: .indexBased(maxIncomingReadIndex: MessageIndex.lowerBound(peerId: peer.id), maxOutgoingReadIndex: MessageIndex.lowerBound(peerId: peer.id), count: 0, markedUnread: false), - Namespaces.Message.Local: .indexBased(maxIncomingReadIndex: MessageIndex.lowerBound(peerId: peer.id), maxOutgoingReadIndex: MessageIndex.lowerBound(peerId: peer.id), count: 0, markedUnread: false) - ] - ]) + let bBytes = malloc(256)! + let randomStatus = SecRandomCopyBytes(nil, 256, bBytes.assumingMemoryBound(to: UInt8.self)) + let b = MemoryBuffer(memory: bBytes, capacity: 256, length: 256, freeWhenDone: true) + if randomStatus == 0 { + let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: chat.peerId, operation: .initialHandshakeAccept(gA: MemoryBuffer(gA), accessHash: accessHash, b: b), state: state) + transaction.setPeerChatState(chat.peerId, state: updatedState) + + let peer = TelegramSecretChat(id: chat.peerId, creationDate: date, regularPeerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: adminId), accessHash: accessHash, role: updatedState.role, embeddedState: updatedState.embeddedState.peerState, messageAutoremoveTimeout: nil) + updatePeers(transaction: transaction, peers: [peer], update: { _, updated in return updated }) + transaction.resetIncomingReadStates([peer.id: [ + Namespaces.Message.SecretIncoming: .indexBased(maxIncomingReadIndex: MessageIndex.lowerBound(peerId: peer.id), maxOutgoingReadIndex: MessageIndex.lowerBound(peerId: peer.id), count: 0, markedUnread: false), + Namespaces.Message.Local: .indexBased(maxIncomingReadIndex: MessageIndex.lowerBound(peerId: peer.id), maxOutgoingReadIndex: MessageIndex.lowerBound(peerId: peer.id), count: 0, markedUnread: false) + ] + ]) + } else { + assertionFailure() + } } else { - assertionFailure() + Logger.shared.log("State", "accepting secret chats disabled on this device") } + + } else { Logger.shared.log("State", "got encryptedChatRequested, but peer already exists or this account is creator") } diff --git a/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.pbxproj b/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.pbxproj index 7f330b1143..8c1f72db21 100644 --- a/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.pbxproj +++ b/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.pbxproj @@ -413,6 +413,7 @@ D05A32E81E6F0B5C002760B4 /* RecentAccountSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05A32E61E6F0B5C002760B4 /* RecentAccountSession.swift */; }; D05D8B372192F8AF0064586F /* LocalizationListState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05D8B362192F8AF0064586F /* LocalizationListState.swift */; }; D05D8B382192F8AF0064586F /* LocalizationListState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05D8B362192F8AF0064586F /* LocalizationListState.swift */; }; + D05FDC3922CA45070060BFE3 /* AppUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EC0DE822C6825D00E7185B /* AppUpdate.swift */; }; D0613FCA1E60440600202CDB /* InvitationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FC91E60440600202CDB /* InvitationLinks.swift */; }; D0613FCB1E60440600202CDB /* InvitationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FC91E60440600202CDB /* InvitationLinks.swift */; }; D0613FCF1E60520700202CDB /* ChannelMembers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0613FCE1E60520700202CDB /* ChannelMembers.swift */; }; @@ -427,6 +428,8 @@ D0642EFA1F3E05D700792790 /* EarliestUnseenPersonalMentionMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0642EF81F3E05D700792790 /* EarliestUnseenPersonalMentionMessage.swift */; }; D067066C1D512ADB00DED3E3 /* Postbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D06706671D512ADB00DED3E3 /* Postbox.framework */; }; D067066D1D512ADB00DED3E3 /* SwiftSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D06706681D512ADB00DED3E3 /* SwiftSignalKit.framework */; }; + D069257122D8B526002FC021 /* SecretChatSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D069257022D8B526002FC021 /* SecretChatSettings.swift */; }; + D069257222D8B526002FC021 /* SecretChatSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D069257022D8B526002FC021 /* SecretChatSettings.swift */; }; D06CA13522772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06CA13422772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift */; }; D06CA13622772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06CA13422772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift */; }; D06ECFC820B810D300C576C2 /* TermsOfService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06ECFC720B810D300C576C2 /* TermsOfService.swift */; }; @@ -677,6 +680,8 @@ D0CC4ADC22BA47280088F36D /* TelegramApiMac.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0CC4ADB22BA47280088F36D /* TelegramApiMac.framework */; }; D0D1026C2212FE52003ADA5E /* AccountSortOrderAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D1026B2212FE52003ADA5E /* AccountSortOrderAttribute.swift */; }; D0D1026D2212FE52003ADA5E /* AccountSortOrderAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D1026B2212FE52003ADA5E /* AccountSortOrderAttribute.swift */; }; + D0D376E622DCCFD600FA7D7C /* SlowMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D376E522DCCFD600FA7D7C /* SlowMode.swift */; }; + D0D376E722DCCFD600FA7D7C /* SlowMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D376E522DCCFD600FA7D7C /* SlowMode.swift */; }; D0D748021E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D748011E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift */; }; D0D748031E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D748011E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift */; }; D0DA1D321F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DA1D311F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift */; }; @@ -1045,6 +1050,7 @@ D06706671D512ADB00DED3E3 /* Postbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Postbox.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D06706681D512ADB00DED3E3 /* SwiftSignalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SwiftSignalKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D067066E1D512AEB00DED3E3 /* MtProtoKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MtProtoKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D069257022D8B526002FC021 /* SecretChatSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecretChatSettings.swift; sourceTree = ""; }; D06CA13422772EB20094E707 /* ManagedNotificationSettingsBehaviors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedNotificationSettingsBehaviors.swift; sourceTree = ""; }; D06ECFC720B810D300C576C2 /* TermsOfService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TermsOfService.swift; sourceTree = ""; }; D07047B31F3DF1FE00F6A8D4 /* ConsumablePersonalMentionMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsumablePersonalMentionMessageAttribute.swift; sourceTree = ""; }; @@ -1186,6 +1192,7 @@ D0CC4AA322BA44960088F36D /* TelegramApi.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TelegramApi.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D0CC4ADB22BA47280088F36D /* TelegramApiMac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TelegramApiMac.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D0D1026B2212FE52003ADA5E /* AccountSortOrderAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSortOrderAttribute.swift; sourceTree = ""; }; + D0D376E522DCCFD600FA7D7C /* SlowMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SlowMode.swift; sourceTree = ""; }; D0D748011E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerPackInteractiveOperations.swift; sourceTree = ""; }; D0DA1D311F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedPendingPeerNotificationSettings.swift; sourceTree = ""; }; D0DB7F021F43030C00591D48 /* InstallInteractiveReadMessagesAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstallInteractiveReadMessagesAction.swift; sourceTree = ""; }; @@ -1730,6 +1737,7 @@ D033873F223BD48B007A2CE4 /* ContactsSettings.swift */, D099E221229420D600561B75 /* BlockedPeersContext.swift */, D098907E22942E3B0053F151 /* ActiveSessionsContext.swift */, + D069257022D8B526002FC021 /* SecretChatSettings.swift */, ); name = Settings; sourceTree = ""; @@ -1993,6 +2001,7 @@ D076F8882296D8E9004F895A /* ManageChannelDiscussionGroup.swift */, 090E778222A9862100CD99F5 /* ChannelOwnershipTransfer.swift */, 090E778F22AAABC600CD99F5 /* PeersNearby.swift */, + D0D376E522DCCFD600FA7D7C /* SlowMode.swift */, ); name = Peers; sourceTree = ""; @@ -2282,6 +2291,7 @@ D03B0D441D6319F900955575 /* CloudFileMediaResource.swift in Sources */, D018D3371E648ACF00C5E089 /* ChannelCreation.swift in Sources */, D01AC9211DD5E7E500E8160F /* RequestEditMessage.swift in Sources */, + D069257122D8B526002FC021 /* SecretChatSettings.swift in Sources */, D0AF32221FAC95C20097362B /* StandaloneUploadedMedia.swift in Sources */, D0F53BE91E784A4800117362 /* ChangeAccountPhoneNumber.swift in Sources */, D0E35A0E1DE4953E00BC6096 /* FetchHttpResource.swift in Sources */, @@ -2343,6 +2353,7 @@ D0DA1D321F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift in Sources */, D099D7491EEF418D00A3128C /* HistoryViewChannelStateValidation.swift in Sources */, C23BC3871E9BE3CA00D79F92 /* ImportContact.swift in Sources */, + D0D376E622DCCFD600FA7D7C /* SlowMode.swift in Sources */, D00422D321677F4500719B67 /* ManagedAccountPresence.swift in Sources */, D03B0D0A1D62255C00955575 /* Holes.swift in Sources */, D05464972073872C002ECC1E /* SecureIdBankStatementValue.swift in Sources */, @@ -2598,6 +2609,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D05FDC3922CA45070060BFE3 /* AppUpdate.swift in Sources */, D014193922AE6B85008667CB /* ChannelOwnershipTransfer.swift in Sources */, D014193A22AE6B85008667CB /* PeersNearby.swift in Sources */, D076F88A2296D8F6004F895A /* ManageChannelDiscussionGroup.swift in Sources */, @@ -2857,9 +2869,11 @@ D0FA8BB11E1FEC7E001E855B /* SecretChatEncryptionConfig.swift in Sources */, D0B418AA1D7E0597004562A4 /* Download.swift in Sources */, D001F3F41E128A1C007A8C60 /* UpdatesApiUtils.swift in Sources */, + D0D376E722DCCFD600FA7D7C /* SlowMode.swift in Sources */, D015E00F225CA61100CB9E8A /* FindChannelById.swift in Sources */, D04D8FF5209A4B0700865719 /* NetworkSettings.swift in Sources */, D05464982073872C002ECC1E /* SecureIdBankStatementValue.swift in Sources */, + D069257222D8B526002FC021 /* SecretChatSettings.swift in Sources */, D0B4188E1D7E0578004562A4 /* StoreMessage_Telegram.swift in Sources */, D0B844461DAB91FD005F29E1 /* RecentPeers.swift in Sources */, D0E412E2206AB24700BEE4A2 /* SecureFileMediaResource.swift in Sources */, diff --git a/submodules/TelegramPresentationData/Sources/ComponentsThemes.swift b/submodules/TelegramPresentationData/Sources/ComponentsThemes.swift index 16d556faed..f4e050c63c 100644 --- a/submodules/TelegramPresentationData/Sources/ComponentsThemes.swift +++ b/submodules/TelegramPresentationData/Sources/ComponentsThemes.swift @@ -26,6 +26,10 @@ public extension NavigationBarPresentationData { convenience public init(presentationData: PresentationData) { self.init(theme: NavigationBarTheme(rootControllerTheme: presentationData.theme), strings: NavigationBarStrings(presentationStrings: presentationData.strings)) } + + convenience public init(presentationTheme: PresentationTheme, presentationStrings: PresentationStrings) { + self.init(theme: NavigationBarTheme(rootControllerTheme: presentationTheme), strings: NavigationBarStrings(presentationStrings: presentationStrings)) + } } public extension ActionSheetControllerTheme { @@ -59,7 +63,4 @@ public extension NavigationControllerTheme { convenience init(presentationTheme: PresentationTheme) { self.init(navigationBar: NavigationBarTheme(rootControllerTheme: presentationTheme), emptyAreaColor: presentationTheme.chatList.backgroundColor) } -// convenience public init(presentationTheme: PresentationTheme) { -// self.init(navigationBar: NavigationBarTheme(rootControllerTheme: presentationTheme), emptyAreaColor: presentationTheme.chatList.backgroundColor, emptyDetailIcon: generateTintedImage(image: UIImage(named: "Chat List/EmptyMasterDetailIcon", in: Bundle(for: PresentationTheme.self), compatibleWith: nil), color: presentationTheme.chatList.messageTextColor.withAlphaComponent(0.2))) -// } } diff --git a/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift index cb9a2440ea..278ef12555 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift @@ -4,7 +4,21 @@ import UIKit private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationTheme { let destructiveColor: UIColor = UIColor(rgb: 0xeb5545) let constructiveColor: UIColor = UIColor(rgb: 0x08a723) - let secretColor: UIColor = UIColor(rgb: 0x00B12C) + let secretColor: UIColor = UIColor(rgb: 0x00b12c) + + let badgeTextColor: UIColor + let outgoingBubbleFillColor: UIColor + let outgoingBubbleHighlightedFillColor: UIColor + + if accentColor.rgb == UIColor.white.rgb { + badgeTextColor = .black + outgoingBubbleFillColor = UIColor(rgb: 0x313131) + outgoingBubbleHighlightedFillColor = UIColor(rgb: 0x464646) + } else { + outgoingBubbleFillColor = accentColor + badgeTextColor = .white + outgoingBubbleHighlightedFillColor = accentColor.withMultipliedBrightnessBy(1.421) + } let rootTabBar = PresentationThemeRootTabBar( backgroundColor: UIColor(rgb: 0x1c1c1d), @@ -13,7 +27,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem selectedIconColor: accentColor, textColor: UIColor(rgb: 0x828282), selectedTextColor: accentColor, - badgeBackgroundColor: UIColor(rgb: 0xeb5545), + badgeBackgroundColor: destructiveColor, badgeStrokeColor: UIColor(rgb: 0x1c1c1d), badgeTextColor: UIColor(rgb: 0xffffff) ) @@ -27,7 +41,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem accentTextColor: accentColor, backgroundColor: UIColor(rgb: 0x1c1c1d), separatorColor: UIColor(rgb: 0x3d3d40), - badgeBackgroundColor: UIColor(rgb: 0xeb5545), + badgeBackgroundColor: destructiveColor, badgeStrokeColor: UIColor(rgb: 0x1c1c1d), badgeTextColor: UIColor(rgb: 0xffffff) ) @@ -63,8 +77,8 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem let switchColors = PresentationThemeSwitch( frameColor: UIColor(rgb: 0x5a5a5e), handleColor: UIColor(rgb: 0x121212), - contentColor: UIColor(rgb: 0xb2b2b2), - positiveColor: UIColor(rgb: 0x000000), + contentColor: UIColor(rgb: 0x77d572), + positiveColor: constructiveColor, negativeColor: destructiveColor ) @@ -101,7 +115,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem itemCheckColors: PresentationThemeFillStrokeForeground( fillColor: accentColor, strokeColor: UIColor(rgb: 0xffffff, alpha: 0.5), - foregroundColor: .white + foregroundColor: badgeTextColor ), controlSecondaryColor: UIColor(rgb: 0xffffff, alpha: 0.5), freeInputField: PresentationInputFieldTheme( @@ -136,34 +150,23 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem failedForegroundColor: .white, muteIconColor: UIColor(rgb: 0x8e8e92), unreadBadgeActiveBackgroundColor: accentColor, - unreadBadgeActiveTextColor: .white, + unreadBadgeActiveTextColor: badgeTextColor, unreadBadgeInactiveBackgroundColor: UIColor(rgb: 0x666666), unreadBadgeInactiveTextColor:UIColor(rgb: 0x000000), pinnedBadgeColor: UIColor(rgb: 0x767677), pinnedSearchBarColor: UIColor(rgb: 0x272728), regularSearchBarColor: UIColor(rgb: 0x272728), - sectionHeaderFillColor: UIColor(rgb: 0x1C1C1D), + sectionHeaderFillColor: UIColor(rgb: 0x1c1c1d), sectionHeaderTextColor: UIColor(rgb: 0xffffff), searchBarKeyboardColor: .dark, verifiedIconFillColor: accentColor, - verifiedIconForegroundColor: .white, + verifiedIconForegroundColor: badgeTextColor, secretIconColor: secretColor, pinnedArchiveAvatarColor: PresentationThemeArchiveAvatarColors(backgroundColors: PresentationThemeGradientColors(topColor: UIColor(rgb: 0x72d5fd), bottomColor: UIColor(rgb: 0x2a9ef1)), foregroundColor: .white), unpinnedArchiveAvatarColor: PresentationThemeArchiveAvatarColors(backgroundColors: PresentationThemeGradientColors(topColor: UIColor(rgb: 0x666666), bottomColor: UIColor(rgb: 0x666666)), foregroundColor: .black), onlineDotColor: UIColor(rgb: 0x4cc91f) ) - let outgoingBubbleFillColor: UIColor - let outgoingBubbleHighlightedFillColor: UIColor - - if accentColor.rgb == UIColor.white.rgb { - outgoingBubbleFillColor = UIColor(rgb: 0x313131) - outgoingBubbleHighlightedFillColor = UIColor(rgb: 0x464646) - } else { - outgoingBubbleFillColor = accentColor - outgoingBubbleHighlightedFillColor = accentColor.withMultipliedBrightnessBy(1.421) - } - let message = PresentationThemeChatMessage( incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x262628), highlightedFill: UIColor(rgb: 0x353539), stroke: UIColor(rgb: 0x262628)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x262628), highlightedFill: UIColor(rgb: 0x353539), stroke: UIColor(rgb: 0x262628))), primaryTextColor: .white, secondaryTextColor: UIColor(rgb: 0xffffff, alpha: 0.5), linkTextColor: accentColor, linkHighlightColor: accentColor.withAlphaComponent(0.5), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xffe438), accentTextColor: accentColor, accentControlColor: accentColor, mediaActiveControlColor: accentColor, mediaInactiveControlColor: accentColor.withAlphaComponent(0.4), pendingActivityColor: UIColor(rgb: 0xffffff, alpha: 0.5), fileTitleColor: accentColor, fileDescriptionColor: UIColor(rgb: 0xffffff, alpha: 0.5), fileDurationColor: UIColor(rgb: 0xffffff, alpha: 0.5), mediaPlaceholderColor: UIColor(rgb: 0x1f1f1f).mixedWith(.white, alpha: 0.05), polls: PresentationThemeChatBubblePolls(radioButton: UIColor(rgb: 0x737373), radioProgress: accentColor, highlight: accentColor.withAlphaComponent(0.12), separator: UIColor(rgb: 0x000000), bar: accentColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0x000000, alpha: 0.5), withoutWallpaper: UIColor(rgb: 0x000000, alpha: 0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xb2b2b2, alpha: 0.18)), actionButtonsTextColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xffffff))), outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, highlightedFill: outgoingBubbleHighlightedFillColor, stroke: outgoingBubbleFillColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, highlightedFill: outgoingBubbleHighlightedFillColor, stroke: outgoingBubbleFillColor)), primaryTextColor: .white, secondaryTextColor: UIColor(rgb: 0xffffff, alpha: 0.5), linkTextColor: .white, linkHighlightColor: UIColor.white.withAlphaComponent(0.5), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xffe438), accentTextColor: .white, accentControlColor: .white, mediaActiveControlColor: .white, mediaInactiveControlColor: UIColor(rgb: 0xffffff, alpha: 0.3), pendingActivityColor: UIColor(rgb: 0xffffff, alpha: 0.5), fileTitleColor: .white, fileDescriptionColor: UIColor(rgb: 0xffffff, alpha: 0.5), fileDurationColor: UIColor(rgb: 0xffffff, alpha: 0.5), mediaPlaceholderColor: UIColor(rgb: 0x313131).mixedWith(.white, alpha: 0.05), polls: PresentationThemeChatBubblePolls(radioButton: .white, radioProgress: .white, highlight: UIColor(white: 1.0, alpha: 0.12), separator: UIColor(white: 1.0, alpha: 0.3), bar: .white), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0x000000, alpha: 0.5), withoutWallpaper: UIColor(rgb: 0x000000, alpha: 0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xb2b2b2, alpha: 0.18)), actionButtonsTextColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xffffff))), @@ -177,7 +180,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem shareButtonStrokeColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0xb2b2b2, alpha: 0.18), withoutWallpaper: UIColor(rgb: 0xb2b2b2, alpha: 0.18)), shareButtonForegroundColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0xb2b2b2), withoutWallpaper: UIColor(rgb: 0xb2b2b2)), mediaOverlayControlColors: PresentationThemeFillForeground(fillColor: UIColor(rgb: 0x000000, alpha: 0.6), foregroundColor: .white), - selectionControlColors: PresentationThemeFillStrokeForeground(fillColor: accentColor, strokeColor: .white, foregroundColor: .white), + selectionControlColors: PresentationThemeFillStrokeForeground(fillColor: accentColor, strokeColor: .white, foregroundColor: badgeTextColor), deliveryFailedColors: PresentationThemeFillForeground(fillColor: destructiveColor, foregroundColor: .white), mediaHighlightOverlayColor: UIColor(white: 1.0, alpha: 0.6) ) @@ -250,6 +253,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem ) let chat = PresentationThemeChat( + defaultWallpaper: .color(0x000000), message: message, serviceMessage: serviceMessage, inputPanel: inputPanel, @@ -296,7 +300,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem ) return PresentationTheme( - name: .builtin(.nightGrayscale), + name: .builtin(.night), author: "Telegram", overallDarkAppearance: true, intro: intro, @@ -310,15 +314,9 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem ) } -public let defaultDarkPresentationTheme = makeDarkPresentationTheme(accentColor: 0x2EA6FF) +public let defaultDarkPresentationTheme = makeDarkPresentationTheme(accentColor: UIColor(rgb: 0x2ea6ff)) -public func makeDarkPresentationTheme(accentColor: Int32?) -> PresentationTheme { - let color: UIColor - if let accentColor = accentColor { - color = UIColor(rgb: UInt32(bitPattern: accentColor)) - } else { - color = UIColor(rgb: UInt32(bitPattern: defaultDayAccentColor)) - } - return makeDarkPresentationTheme(accentColor: color) +public func makeDarkPresentationTheme(accentColor: UIColor?) -> PresentationTheme { + let accentColor = accentColor ?? defaultDayAccentColor + return makeDarkPresentationTheme(accentColor: accentColor) } - diff --git a/submodules/TelegramPresentationData/Sources/DefaultDarkAccentPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDarkTintedPresentationTheme.swift similarity index 97% rename from submodules/TelegramPresentationData/Sources/DefaultDarkAccentPresentationTheme.swift rename to submodules/TelegramPresentationData/Sources/DefaultDarkTintedPresentationTheme.swift index 7a60a156f9..df94bd83bf 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDarkAccentPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDarkTintedPresentationTheme.swift @@ -2,9 +2,9 @@ import Foundation import UIKit private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationTheme { - let destructiveColor: UIColor = UIColor(rgb: 0xFF6767) + let destructiveColor: UIColor = UIColor(rgb: 0xff6767) let constructiveColor: UIColor = UIColor(rgb: 0x08a723) - let secretColor: UIColor = UIColor(rgb: 0x89DF9E) + let secretColor: UIColor = UIColor(rgb: 0x89df9e) let mainBackgroundColor = accentColor.withMultiplied(hue: 1.024, saturation: 0.585, brightness: 0.25) let mainSelectionColor = accentColor.withMultiplied(hue: 1.03, saturation: 0.585, brightness: 0.12) @@ -83,7 +83,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem frameColor: mainSecondaryTextColor.withAlphaComponent(0.5), handleColor: UIColor(rgb: 0x121212), contentColor: accentColor, - positiveColor: accentColor, + positiveColor: constructiveColor, negativeColor: destructiveColor ) @@ -260,6 +260,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem ) let chat = PresentationThemeChat( + defaultWallpaper: .color(Int32(bitPattern: accentColor.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18).rgb)), message: message, serviceMessage: serviceMessage, inputPanel: inputPanel, @@ -320,14 +321,9 @@ private func makeDarkPresentationTheme(accentColor: UIColor) -> PresentationThem ) } -public let defaultDarkAccentPresentationTheme = makeDarkAccentPresentationTheme(accentColor: 0x2ea6ff) +public let defaultDarkAccentPresentationTheme = makeDarkAccentPresentationTheme(accentColor: UIColor(rgb: 0x2ea6ff)) -public func makeDarkAccentPresentationTheme(accentColor: Int32?) -> PresentationTheme { - let color: UIColor - if let accentColor = accentColor { - color = UIColor(rgb: UInt32(bitPattern: accentColor)) - } else { - color = UIColor(rgb: UInt32(bitPattern: defaultDayAccentColor)) - } - return makeDarkPresentationTheme(accentColor: color) +public func makeDarkAccentPresentationTheme(accentColor: UIColor?) -> PresentationTheme { + let accentColor = accentColor ?? defaultDayAccentColor + return makeDarkPresentationTheme(accentColor: accentColor) } diff --git a/submodules/TelegramPresentationData/Sources/DefaultPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift similarity index 95% rename from submodules/TelegramPresentationData/Sources/DefaultPresentationTheme.swift rename to submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift index a19c06c646..a3c049cdda 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift @@ -1,7 +1,8 @@ import Foundation import UIKit +import TelegramCore -private func makeDefaultPresentationTheme(accentColor: UIColor, serviceBackgroundColor: UIColor, day: Bool) -> PresentationTheme { +private func makeDefaultDayPresentationTheme(accentColor: UIColor, serviceBackgroundColor: UIColor, day: Bool) -> PresentationTheme { let destructiveColor: UIColor = UIColor(rgb: 0xff3b30) let constructiveColor: UIColor = UIColor(rgb: 0x00c900) let secretColor: UIColor = UIColor(rgb: 0x00b12c) @@ -63,8 +64,8 @@ private func makeDefaultPresentationTheme(accentColor: UIColor, serviceBackgroun let switchColors = PresentationThemeSwitch( frameColor: UIColor(rgb: 0xe0e0e0), handleColor: UIColor(rgb: 0xffffff), - contentColor: UIColor(rgb: 0x42d451), - positiveColor: UIColor(rgb: 0x00B12C), + contentColor: UIColor(rgb: 0x77d572), + positiveColor: constructiveColor, negativeColor: destructiveColor ) @@ -265,6 +266,7 @@ private func makeDefaultPresentationTheme(accentColor: UIColor, serviceBackgroun ) let chat = PresentationThemeChat( + defaultWallpaper: day ? .color(0xffffff) : .builtin(WallpaperSettings()), message: day ? messageDay : message, serviceMessage: day ? serviceMessageDay : serviceMessage, inputPanel: inputPanel, @@ -325,21 +327,12 @@ private func makeDefaultPresentationTheme(accentColor: UIColor, serviceBackgroun ) } -public let defaultPresentationTheme = makeDefaultPresentationTheme(accentColor: UIColor(rgb: 0x007ee5), serviceBackgroundColor: defaultServiceBackgroundColor, day: false) +public let defaultPresentationTheme = makeDefaultDayPresentationTheme(accentColor: UIColor(rgb: 0x007ee5), serviceBackgroundColor: defaultServiceBackgroundColor, day: false) -public let defaultDayAccentColor: Int32 = 0x007ee5 -public let defaultServiceBackgroundColor: UIColor = UIColor(rgb: 0x000000, alpha: 0.3) +public let defaultDayAccentColor = UIColor(rgb: 0x007ee5) +public let defaultServiceBackgroundColor = UIColor(rgb: 0x000000, alpha: 0.3) -public func makeDefaultPresentationTheme(serviceBackgroundColor: UIColor?) -> PresentationTheme { - return makeDefaultPresentationTheme(accentColor: UIColor(rgb: 0x007ee5), serviceBackgroundColor: serviceBackgroundColor ?? .black, day: false) -} - -public func makeDefaultDayPresentationTheme(accentColor: Int32?, serviceBackgroundColor: UIColor) -> PresentationTheme { - let color: UIColor - if let accentColor = accentColor { - color = UIColor(rgb: UInt32(bitPattern: accentColor)) - } else { - color = UIColor(rgb: UInt32(bitPattern: defaultDayAccentColor)) - } - return makeDefaultPresentationTheme(accentColor: color, serviceBackgroundColor: serviceBackgroundColor, day: true) +public func makeDefaultDayPresentationTheme(accentColor: UIColor? = nil, serviceBackgroundColor: UIColor) -> PresentationTheme { + let accentColor = accentColor ?? defaultDayAccentColor + return makeDefaultDayPresentationTheme(accentColor: accentColor, serviceBackgroundColor: serviceBackgroundColor, day: true) } diff --git a/submodules/TelegramPresentationData/Sources/MakePresentationTheme.swift b/submodules/TelegramPresentationData/Sources/MakePresentationTheme.swift new file mode 100644 index 0000000000..716b461713 --- /dev/null +++ b/submodules/TelegramPresentationData/Sources/MakePresentationTheme.swift @@ -0,0 +1,21 @@ +import Foundation +import UIKit +import TelegramUIPreferences + +public func makePresentationTheme(themeReference: PresentationThemeReference, accentColor: UIColor, serviceBackgroundColor: UIColor) -> PresentationTheme { + let theme: PresentationTheme + switch themeReference { + case let .builtin(reference): + switch reference { + case .dayClassic: + theme = makeDefaultDayPresentationTheme(serviceBackgroundColor: serviceBackgroundColor) + case .night: + theme = makeDarkPresentationTheme(accentColor: accentColor) + case .nightAccent: + theme = makeDarkAccentPresentationTheme(accentColor: accentColor) + case .day: + theme = makeDefaultDayPresentationTheme(accentColor: accentColor, serviceBackgroundColor: serviceBackgroundColor) + } + } + return theme +} diff --git a/submodules/TelegramPresentationData/Sources/PresentationData.swift b/submodules/TelegramPresentationData/Sources/PresentationData.swift index b11974299d..efca79ad2e 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationData.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationData.swift @@ -254,38 +254,34 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager) - let parameters = AutomaticThemeSwitchParameters(settings: themeSettings.automaticThemeSwitchSetting) if automaticThemeShouldSwitchNow(parameters, currentTheme: themeSettings.theme) { effectiveTheme = .builtin(themeSettings.automaticThemeSwitchSetting.theme) - switch effectiveChatWallpaper { - case .builtin, .color: - switch themeSettings.automaticThemeSwitchSetting.theme { - case .nightAccent: - effectiveChatWallpaper = .color(0x18222d) - case .nightGrayscale: - effectiveChatWallpaper = .color(0x000000) - default: - break - } - default: - break - } } else { effectiveTheme = themeSettings.theme } let effectiveAccentColor = themeSettings.themeSpecificAccentColors[effectiveTheme.index]?.color ?? defaultDayAccentColor - switch effectiveTheme { case let .builtin(reference): switch reference { case .dayClassic: themeValue = defaultPresentationTheme - case .nightGrayscale: + case .day: + themeValue = makeDefaultDayPresentationTheme(accentColor: effectiveAccentColor, serviceBackgroundColor: defaultServiceBackgroundColor) + case .night: themeValue = makeDarkPresentationTheme(accentColor: effectiveAccentColor) case .nightAccent: themeValue = makeDarkAccentPresentationTheme(accentColor: effectiveAccentColor) - case .day: - themeValue = makeDefaultDayPresentationTheme(accentColor: effectiveAccentColor, serviceBackgroundColor: defaultServiceBackgroundColor) } } + + if effectiveTheme != themeSettings.theme { + switch effectiveChatWallpaper { + case .builtin, .color: + effectiveChatWallpaper = themeValue.chat.defaultWallpaper + default: + break + } + } + let dateTimeFormat = currentDateTimeFormat() let stringsValue: PresentationStrings if let localizationSettings = localizationSettings { @@ -348,7 +344,7 @@ private func automaticThemeShouldSwitchNow(_ parameters: AutomaticThemeSwitchPar switch currentTheme { case let .builtin(builtin): switch builtin { - case .nightAccent, .nightGrayscale: + case .nightAccent, .night: return false default: break @@ -532,20 +528,6 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI let automaticTheme = PresentationThemeReference.builtin(themeSettings.automaticThemeSwitchSetting.theme) if let themeSpecificWallpaper = themeSettings.themeSpecificChatWallpapers[automaticTheme.index] { effectiveChatWallpaper = themeSpecificWallpaper - } else { - switch effectiveChatWallpaper { - case .builtin, .color: - switch themeSettings.automaticThemeSwitchSetting.theme { - case .nightAccent: - effectiveChatWallpaper = .color(0x18222d) - case .nightGrayscale: - effectiveChatWallpaper = .color(0x000000) - default: - break - } - default: - break - } } effectiveTheme = automaticTheme } else { @@ -559,8 +541,8 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI case let .builtin(reference): switch reference { case .dayClassic: - themeValue = makeDefaultPresentationTheme(serviceBackgroundColor: serviceBackgroundColor) - case .nightGrayscale: + themeValue = makeDefaultDayPresentationTheme(serviceBackgroundColor: serviceBackgroundColor) + case .night: themeValue = makeDarkPresentationTheme(accentColor: effectiveAccentColor) case .nightAccent: themeValue = makeDarkAccentPresentationTheme(accentColor: effectiveAccentColor) @@ -569,6 +551,15 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI } } + if effectiveTheme != themeSettings.theme && themeSettings.themeSpecificChatWallpapers[effectiveTheme.index] == nil { + switch effectiveChatWallpaper { + case .builtin, .color: + effectiveChatWallpaper = themeValue.chat.defaultWallpaper + default: + break + } + } + let localizationSettings: LocalizationSettings? if let current = sharedData.entries[SharedDataKeys.localizationSettings] as? LocalizationSettings { localizationSettings = current diff --git a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift index 07c62cdc40..0daa235d02 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift @@ -3930,192 +3930,194 @@ public final class PresentationStrings { public var Channel_Setup_TypePublicHelp: String { return self._s[3475]! } public var Passport_Identity_EditInternalPassport: String { return self._s[3476]! } public var PhotoEditor_Skip: String { return self._s[3477]! } - public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { + public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue) } - public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { + public func UserCount(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue) } - public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[2 * 6 + Int(form.rawValue)]!, stringValue) + public func PUSH_CHAT_MESSAGE_FWDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[2 * 6 + Int(form.rawValue)]!, _2, _1, _3) } - public func Watch_UserInfo_Mute(_ value: Int32) -> String { + public func ForwardedFiles(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[3 * 6 + Int(form.rawValue)]!, stringValue) } - public func StickerPack_StickerCount(_ value: Int32) -> String { + public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[4 * 6 + Int(form.rawValue)]!, stringValue) } - public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { + public func Passport_Scans(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[5 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_ShortHours(_ value: Int32) -> String { + public func MuteExpires_Minutes(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[6 * 6 + Int(form.rawValue)]!, stringValue) } - public func Call_Minutes(_ value: Int32) -> String { + public func AttachmentMenu_SendVideo(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, stringValue) } - public func Map_ETAHours(_ value: Int32) -> String { + public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, stringValue) } - public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, stringValue) + public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, _2, _1, _3) } - public func Notification_GameScoreExtended(_ value: Int32) -> String { + public func SharedMedia_Video(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[10 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_ShortDays(_ value: Int32) -> String { + public func Map_ETAMinutes(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, stringValue) } - public func SharedMedia_Generic(_ value: Int32) -> String { + public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_ShortMinutes(_ value: Int32) -> String { + public func StickerPack_AddStickerCount(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, stringValue) } - public func QuickSend_Photos(_ value: Int32) -> String { + public func ForwardedMessages(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_StatusOnline(_ value: Int32) -> String { + public func Call_Minutes(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { + public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, _1, _2) + public func ChatList_SelectedChats(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, stringValue) } - public func Map_ETAMinutes(_ value: Int32) -> String { + public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, stringValue) } - public func MuteExpires_Minutes(_ value: Int32) -> String { + public func MessageTimer_ShortSeconds(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, stringValue) } - public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { + public func Contacts_ImportersCount(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedPhotos(_ value: Int32) -> String { + public func Conversation_StatusOnline(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, stringValue) } - public func StickerPack_AddStickerCount(_ value: Int32) -> String { + public func AttachmentMenu_SendGif(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, stringValue) } - public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { + public func MessageTimer_Days(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) } - public func MuteExpires_Hours(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Weeks(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, stringValue) - } - public func GroupInfo_ParticipantCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) + public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, _1, _2) } public func LastSeen_HoursAgo(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_StickerCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, stringValue) } - public func MuteExpires_Days(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_FWDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func MessageTimer_ShortWeeks(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, _1, _2) - } public func MessageTimer_Years(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ChatList_DeleteConfirmation(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Map_ETAHours(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedVideos(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Days(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedAudios(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedPolls(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, _1, _2) + public func Call_ShortSeconds(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessagePoll_VotedCount(_ value: Int32) -> String { + public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, _1, _2) + public func ForwardedGifs(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, stringValue) } - public func AttachmentMenu_SendVideo(_ value: Int32) -> String { + public func ForwardedStickers(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, stringValue) @@ -4124,116 +4126,112 @@ public final class PresentationStrings { let form = presentationStringsPluralizationForm(self.lc, selector) return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, _0, _1) } - public func SharedMedia_File(_ value: Int32) -> String { + public func MessageTimer_Hours(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, stringValue) } - public func AttachmentMenu_SendItem(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Video(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_AddMaskCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Months(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, stringValue) - } - public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, stringValue) - } - public func UserCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_Seconds(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_SharePhoto(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Seconds(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedAudios(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Hours(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedLocations(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_ShareItem(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedStickers(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendGif(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, stringValue) + public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, _2, _1, _3) } public func Notifications_Exceptions(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Seconds(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, stringValue) + } + public func QuickSend_Photos(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_ShareItem(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedLocations(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func MuteFor_Days(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, stringValue) + } + public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, stringValue) + } + public func InviteText_ContactsCountText(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) } public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, _1, _2) + return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, _1, _2) } - public func ForwardedPolls(_ value: Int32) -> String { + public func MuteExpires_Hours(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func MessageTimer_ShortHours(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSimple(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortMinutes(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Weeks(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, stringValue) @@ -4243,177 +4241,177 @@ public final class PresentationStrings { let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, stringValue) } - public func Passport_Scans(_ value: Int32) -> String { + public func MessageTimer_ShortWeeks(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, _1, _2) + public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, selector) return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, _2, _1, _3) } - public func SharedMedia_Link(_ value: Int32) -> String { + public func SharedMedia_Photo(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, stringValue) } - public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { + public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, _2, _1, _3) + return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, _1, _2) } - public func Call_ShortMinutes(_ value: Int32) -> String { + public func Watch_UserInfo_Mute(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedVideoMessages(_ value: Int32) -> String { + public func Conversation_StatusMembers(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, _1, _2) + public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_StatusSubscribers(_ value: Int32) -> String { + public func SharedMedia_File(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_ShortSeconds(_ value: Int32) -> String { + public func ForwardedVideoMessages(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, stringValue) } - public func Call_ShortSeconds(_ value: Int32) -> String { + public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) } - public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { + public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) } - public func MuteFor_Hours(_ value: Int32) -> String { + public func MessagePoll_VotedCount(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, selector) return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, _1, _2) } - public func ChatList_DeleteConfirmation(_ value: Int32) -> String { + public func Media_SharePhoto(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) } - public func Invitation_Members(_ value: Int32) -> String { + public func Call_ShortMinutes(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, stringValue) } - public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { + public func MessageTimer_Minutes(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) } - public func ChatList_SelectedChats(_ value: Int32) -> String { + public func SharedMedia_Generic(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, stringValue) } - public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { + public func Call_Seconds(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedVideos(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedGifs(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_ShareVideo(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, stringValue) - } - public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteFor_Days(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSimple(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LastSeen_MinutesAgo(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedFiles(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Days(_ value: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, stringValue) + public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, _1, _2) } public func ForwardedContacts(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, selector) + return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Months(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_Link(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LastSeen_MinutesAgo(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteFor_Hours(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_ShareVideo(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreExtended(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) } - public func Contacts_ImportersCount(_ value: Int32) -> String { + public func Invitation_Members(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedMessages(_ value: Int32) -> String { + public func Conversation_StatusSubscribers(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) } - public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { + public func StickerPack_AddMaskCount(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_StatusMembers(_ value: Int32) -> String { + public func ForwardedPhotos(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, stringValue) @@ -4422,37 +4420,39 @@ public final class PresentationStrings { let form = presentationStringsPluralizationForm(self.lc, selector) return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, _1, _2) } - public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { + public func AttachmentMenu_SendItem(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, _2, _1, _3) + public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_Minutes(_ value: Int32) -> String { + public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) } - public func InviteText_ContactsCountText(_ value: Int32) -> String { + public func MessageTimer_ShortDays(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func SharedMedia_Photo(_ value: Int32) -> String { + public func GroupInfo_ParticipantCount(_ value: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { let form = presentationStringsPluralizationForm(self.lc, selector) - return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, _1, _2) + return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { + let form = presentationStringsPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, stringValue) } public init(primaryComponent: PresentationStringsComponent, secondaryComponent: PresentationStringsComponent?, groupingSeparator: String) { diff --git a/submodules/TelegramPresentationData/Sources/PresentationTheme.swift b/submodules/TelegramPresentationData/Sources/PresentationTheme.swift index 28767e4fa3..d4418a6310 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationTheme.swift @@ -781,6 +781,7 @@ public final class PresentationThemeChatHistoryNavigation { } public final class PresentationThemeChat { + public let defaultWallpaper: TelegramWallpaper public let message: PresentationThemeChatMessage public let serviceMessage: PresentationThemeServiceMessage public let inputPanel: PresentationThemeChatInputPanel @@ -788,7 +789,8 @@ public final class PresentationThemeChat { public let inputButtonPanel: PresentationThemeInputButtonPanel public let historyNavigation: PresentationThemeChatHistoryNavigation - public init(message: PresentationThemeChatMessage, serviceMessage: PresentationThemeServiceMessage, inputPanel: PresentationThemeChatInputPanel, inputMediaPanel: PresentationThemeInputMediaPanel, inputButtonPanel: PresentationThemeInputButtonPanel, historyNavigation: PresentationThemeChatHistoryNavigation) { + public init(defaultWallpaper: TelegramWallpaper, message: PresentationThemeChatMessage, serviceMessage: PresentationThemeServiceMessage, inputPanel: PresentationThemeChatInputPanel, inputMediaPanel: PresentationThemeInputMediaPanel, inputButtonPanel: PresentationThemeInputButtonPanel, historyNavigation: PresentationThemeChatHistoryNavigation) { + self.defaultWallpaper = defaultWallpaper self.message = message self.serviceMessage = serviceMessage self.inputPanel = inputPanel @@ -843,7 +845,7 @@ public final class PresentationThemeInAppNotification { public enum PresentationThemeBuiltinName { case dayClassic case day - case nightGrayscale + case night case nightAccent public var reference: PresentationBuiltinThemeReference { @@ -852,8 +854,8 @@ public enum PresentationThemeBuiltinName { return .dayClassic case .day: return .day - case .nightGrayscale: - return .nightGrayscale + case .night: + return .night case .nightAccent: return .nightAccent } @@ -889,7 +891,7 @@ public enum PresentationThemeName: Equatable { return "Day" case .dayClassic: return "Classic" - case .nightGrayscale: + case .night: return "Night" case .nightAccent: return "Night" diff --git a/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift b/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift index 0acbfdeda0..90e07d2ccc 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift @@ -1,5 +1,6 @@ import Foundation import UIKit +import TelegramCore public enum PresentationThemeColorDecodingError: Error { case generic @@ -26,6 +27,37 @@ private func encodeColor(_ values: inout KeyedEncodingContainer, _ val } } +extension TelegramWallpaper: Codable { + public init(from decoder: Decoder) throws { + let values = try decoder.singleValueContainer() + if let value = try? values.decode(String.self) { + switch value.lowercased() { + case "builtin": + self = .builtin(WallpaperSettings()) + default: + if let color = UIColor(hexString: value) { + self = .color(Int32(bitPattern: color.rgb)) + } else { + throw PresentationThemeColorDecodingError.generic + } + } + } + throw PresentationThemeColorDecodingError.generic + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .builtin: + try container.encode("builtin") + case let .color(value): + try container.encode(String(format: "%06x", value)) + default: + break + } + } +} + extension PresentationThemeStatusBarStyle: Codable { public init(from decoder: Decoder) throws { let values = try decoder.singleValueContainer() @@ -102,10 +134,10 @@ extension PresentationThemeKeyboardColor: Codable { public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { - case .light: - try container.encode("light") - case .dark: - try container.encode("dark") + case .light: + try container.encode("light") + case .dark: + try container.encode("dark") } } } @@ -1255,6 +1287,7 @@ extension PresentationThemeChatHistoryNavigation: Codable { extension PresentationThemeChat: Codable { enum CodingKeys: String, CodingKey { + case defaultWallpaper case message case serviceMessage case inputPanel @@ -1265,7 +1298,8 @@ extension PresentationThemeChat: Codable { public convenience init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) - self.init(message: try values.decode(PresentationThemeChatMessage.self, forKey: .message), + self.init(defaultWallpaper: try values.decode(TelegramWallpaper.self, forKey: .defaultWallpaper), + message: try values.decode(PresentationThemeChatMessage.self, forKey: .message), serviceMessage: try values.decode(PresentationThemeServiceMessage.self, forKey: .serviceMessage), inputPanel: try values.decode(PresentationThemeChatInputPanel.self, forKey: .inputPanel), inputMediaPanel: try values.decode(PresentationThemeInputMediaPanel.self, forKey: .inputMediaPanel), @@ -1275,6 +1309,7 @@ extension PresentationThemeChat: Codable { public func encode(to encoder: Encoder) throws { var values = encoder.container(keyedBy: CodingKeys.self) + try values.encode(self.defaultWallpaper, forKey: .defaultWallpaper) try values.encode(self.message, forKey: .message) try values.encode(self.serviceMessage, forKey: .serviceMessage) try values.encode(self.inputPanel, forKey: .inputPanel) @@ -1367,7 +1402,7 @@ extension PresentationThemeName: Codable { try container.encode("Classic") case .nightAccent: try container.encode("Night Tinted") - case .nightGrayscale: + case .night: try container.encode("Night") } case let .custom(name): diff --git a/submodules/TelegramPresentationData/TelegramPresentationData_Xcode.xcodeproj/project.pbxproj b/submodules/TelegramPresentationData/TelegramPresentationData_Xcode.xcodeproj/project.pbxproj index a3bd8a10ca..5955d030f5 100644 --- a/submodules/TelegramPresentationData/TelegramPresentationData_Xcode.xcodeproj/project.pbxproj +++ b/submodules/TelegramPresentationData/TelegramPresentationData_Xcode.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0938677D22E0B9CB000EF19E /* MakePresentationTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0938677C22E0B9CB000EF19E /* MakePresentationTheme.swift */; }; 0957DE1522D88B82001B4D57 /* PresentationThemeEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0957DE1422D88B82001B4D57 /* PresentationThemeEncoder.swift */; }; 0957DE1922D95E0F001B4D57 /* PresentationThemeDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0957DE1822D95E0F001B4D57 /* PresentationThemeDecoder.swift */; }; 097A581B22D528680078B73C /* PresentationThemeCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 097A581A22D528680078B73C /* PresentationThemeCodable.swift */; }; @@ -25,15 +26,16 @@ D0AE31CB22B279D00058D3BC /* NumericFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE31CA22B279D00058D3BC /* NumericFormat.swift */; }; D0AE31CD22B279FD0058D3BC /* PresentationsResourceCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE31CC22B279FD0058D3BC /* PresentationsResourceCache.swift */; }; D0AE31D222B27A780058D3BC /* DefaultDarkPresentationTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE31CE22B27A780058D3BC /* DefaultDarkPresentationTheme.swift */; }; - D0AE31D322B27A780058D3BC /* DefaultDarkAccentPresentationTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE31CF22B27A780058D3BC /* DefaultDarkAccentPresentationTheme.swift */; }; + D0AE31D322B27A780058D3BC /* DefaultDarkTintedPresentationTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE31CF22B27A780058D3BC /* DefaultDarkTintedPresentationTheme.swift */; }; D0AE31D422B27A780058D3BC /* DefaultPresentationStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE31D022B27A780058D3BC /* DefaultPresentationStrings.swift */; }; - D0AE31D522B27A780058D3BC /* DefaultPresentationTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE31D122B27A780058D3BC /* DefaultPresentationTheme.swift */; }; + D0AE31D522B27A780058D3BC /* DefaultDayPresentationTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE31D122B27A780058D3BC /* DefaultDayPresentationTheme.swift */; }; D0AE31D822B27AAF0058D3BC /* EDSunriseSet.h in Headers */ = {isa = PBXBuildFile; fileRef = D0AE31D622B27AAE0058D3BC /* EDSunriseSet.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0AE31D922B27AAF0058D3BC /* EDSunriseSet.m in Sources */ = {isa = PBXBuildFile; fileRef = D0AE31D722B27AAE0058D3BC /* EDSunriseSet.m */; }; D0AE321422B2826A0058D3BC /* ComponentsThemes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE321322B282690058D3BC /* ComponentsThemes.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 0938677C22E0B9CB000EF19E /* MakePresentationTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakePresentationTheme.swift; sourceTree = ""; }; 0957DE1422D88B82001B4D57 /* PresentationThemeEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentationThemeEncoder.swift; sourceTree = ""; }; 0957DE1822D95E0F001B4D57 /* PresentationThemeDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentationThemeDecoder.swift; sourceTree = ""; }; 097A581A22D528680078B73C /* PresentationThemeCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentationThemeCodable.swift; sourceTree = ""; }; @@ -54,9 +56,9 @@ D0AE31CA22B279D00058D3BC /* NumericFormat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumericFormat.swift; sourceTree = ""; }; D0AE31CC22B279FD0058D3BC /* PresentationsResourceCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentationsResourceCache.swift; sourceTree = ""; }; D0AE31CE22B27A780058D3BC /* DefaultDarkPresentationTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultDarkPresentationTheme.swift; sourceTree = ""; }; - D0AE31CF22B27A780058D3BC /* DefaultDarkAccentPresentationTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultDarkAccentPresentationTheme.swift; sourceTree = ""; }; + D0AE31CF22B27A780058D3BC /* DefaultDarkTintedPresentationTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultDarkTintedPresentationTheme.swift; sourceTree = ""; }; D0AE31D022B27A780058D3BC /* DefaultPresentationStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultPresentationStrings.swift; sourceTree = ""; }; - D0AE31D122B27A780058D3BC /* DefaultPresentationTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultPresentationTheme.swift; sourceTree = ""; }; + D0AE31D122B27A780058D3BC /* DefaultDayPresentationTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultDayPresentationTheme.swift; sourceTree = ""; }; D0AE31D622B27AAE0058D3BC /* EDSunriseSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EDSunriseSet.h; sourceTree = ""; }; D0AE31D722B27AAE0058D3BC /* EDSunriseSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EDSunriseSet.m; sourceTree = ""; }; D0AE321322B282690058D3BC /* ComponentsThemes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComponentsThemes.swift; sourceTree = ""; }; @@ -99,18 +101,19 @@ D0AE31A822B273F20058D3BC /* Sources */ = { isa = PBXGroup; children = ( + D0AE31D122B27A780058D3BC /* DefaultDayPresentationTheme.swift */, + D0AE31CE22B27A780058D3BC /* DefaultDarkPresentationTheme.swift */, + D0AE31CF22B27A780058D3BC /* DefaultDarkTintedPresentationTheme.swift */, + 0938677C22E0B9CB000EF19E /* MakePresentationTheme.swift */, + D0AE31D022B27A780058D3BC /* DefaultPresentationStrings.swift */, + D0AE31C622B2799B0058D3BC /* NumberPluralizationForm.h */, + D0AE31C722B2799B0058D3BC /* NumberPluralizationForm.m */, + D0AE31CA22B279D00058D3BC /* NumericFormat.swift */, + D0AE31C422B279720058D3BC /* StringPluralization.swift */, D0AE321322B282690058D3BC /* ComponentsThemes.swift */, D0AE31D622B27AAE0058D3BC /* EDSunriseSet.h */, D0AE31D722B27AAE0058D3BC /* EDSunriseSet.m */, - D0AE31CF22B27A780058D3BC /* DefaultDarkAccentPresentationTheme.swift */, - D0AE31CE22B27A780058D3BC /* DefaultDarkPresentationTheme.swift */, - D0AE31D022B27A780058D3BC /* DefaultPresentationStrings.swift */, - D0AE31D122B27A780058D3BC /* DefaultPresentationTheme.swift */, D0AE31CC22B279FD0058D3BC /* PresentationsResourceCache.swift */, - D0AE31CA22B279D00058D3BC /* NumericFormat.swift */, - D0AE31C622B2799B0058D3BC /* NumberPluralizationForm.h */, - D0AE31C722B2799B0058D3BC /* NumberPluralizationForm.m */, - D0AE31C422B279720058D3BC /* StringPluralization.swift */, D0AE31B222B2746B0058D3BC /* PresentationData.swift */, D0AE31B122B2746B0058D3BC /* PresentationStrings.swift */, D0AE31B322B2746B0058D3BC /* PresentationTheme.swift */, @@ -216,9 +219,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D0AE31D522B27A780058D3BC /* DefaultPresentationTheme.swift in Sources */, + D0AE31D522B27A780058D3BC /* DefaultDayPresentationTheme.swift in Sources */, D0AE31D422B27A780058D3BC /* DefaultPresentationStrings.swift in Sources */, 097A581B22D528680078B73C /* PresentationThemeCodable.swift in Sources */, + 0938677D22E0B9CB000EF19E /* MakePresentationTheme.swift in Sources */, D0AE31CB22B279D00058D3BC /* NumericFormat.swift in Sources */, 0957DE1922D95E0F001B4D57 /* PresentationThemeDecoder.swift in Sources */, D0AE31B422B2746B0058D3BC /* PresentationStrings.swift in Sources */, @@ -228,7 +232,7 @@ D0AE31C922B2799B0058D3BC /* NumberPluralizationForm.m in Sources */, D0AE31D922B27AAF0058D3BC /* EDSunriseSet.m in Sources */, D0AE31B522B2746B0058D3BC /* PresentationData.swift in Sources */, - D0AE31D322B27A780058D3BC /* DefaultDarkAccentPresentationTheme.swift in Sources */, + D0AE31D322B27A780058D3BC /* DefaultDarkTintedPresentationTheme.swift in Sources */, D0AE31B622B2746B0058D3BC /* PresentationTheme.swift in Sources */, 0957DE1522D88B82001B4D57 /* PresentationThemeEncoder.swift in Sources */, D0AE31D222B27A780058D3BC /* DefaultDarkPresentationTheme.swift in Sources */, diff --git a/submodules/TelegramUI/TelegramUI/AuthorizationSequenceController.swift b/submodules/TelegramUI/TelegramUI/AuthorizationSequenceController.swift index 6856cc558c..d6e9fcf4b8 100644 --- a/submodules/TelegramUI/TelegramUI/AuthorizationSequenceController.swift +++ b/submodules/TelegramUI/TelegramUI/AuthorizationSequenceController.swift @@ -277,7 +277,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail } var dismissImpl: (() -> Void)? let alertTheme = AlertControllerTheme(presentationTheme: strongSelf.theme) - let attributedText = stringWithAppliedEntities(termsOfService.text, entities: termsOfService.entities, baseColor: alertTheme.primaryColor, linkColor: alertTheme.accentColor, baseFont: Font.regular(13.0), linkFont: Font.regular(13.0), boldFont: Font.semibold(13.0), italicFont: Font.italic(13.0), boldItalicFont: Font.semiboldItalic(13.0), fixedFont: Font.regular(13.0)) + let attributedText = stringWithAppliedEntities(termsOfService.text, entities: termsOfService.entities, baseColor: alertTheme.primaryColor, linkColor: alertTheme.accentColor, baseFont: Font.regular(13.0), linkFont: Font.regular(13.0), boldFont: Font.semibold(13.0), italicFont: Font.italic(13.0), boldItalicFont: Font.semiboldItalic(13.0), fixedFont: Font.regular(13.0), blockQuoteFont: Font.regular(13.0)) let contentNode = TextAlertContentNode(theme: alertTheme, title: NSAttributedString(string: strongSelf.strings.Login_TermsOfServiceHeader, font: Font.medium(17.0), textColor: alertTheme.primaryColor, paragraphAlignment: .center), text: attributedText, actions: [ TextAlertAction(type: .defaultAction, title: strongSelf.strings.Login_TermsOfServiceAgree, action: { dismissImpl?() diff --git a/submodules/TelegramUI/TelegramUI/ChannelDiscussionGroupSetupHeaderItem.swift b/submodules/TelegramUI/TelegramUI/ChannelDiscussionGroupSetupHeaderItem.swift index b41f4825d7..6fad4b7ba0 100644 --- a/submodules/TelegramUI/TelegramUI/ChannelDiscussionGroupSetupHeaderItem.swift +++ b/submodules/TelegramUI/TelegramUI/ChannelDiscussionGroupSetupHeaderItem.swift @@ -113,7 +113,7 @@ class ChannelDiscussionGroupSetupHeaderItemNode: ListViewItemNode { iconImage = UIImage(bundleImageName: "Chat/Info/DiscussDayIcon")?.precomposed() case .nightAccent: iconImage = UIImage(bundleImageName: "Chat/Info/DiscussNightAccentIcon")?.precomposed() - case .nightGrayscale: + case .night: iconImage = UIImage(bundleImageName: "Chat/Info/DiscussNightIcon")?.precomposed() } case .custom: diff --git a/submodules/TelegramUI/TelegramUI/ChatAnimationGalleryItem.swift b/submodules/TelegramUI/TelegramUI/ChatAnimationGalleryItem.swift index 578c2e6477..25432b9be3 100644 --- a/submodules/TelegramUI/TelegramUI/ChatAnimationGalleryItem.swift +++ b/submodules/TelegramUI/TelegramUI/ChatAnimationGalleryItem.swift @@ -336,7 +336,7 @@ final class ChatAnimationGalleryItemNode: ZoomableContentGalleryItemNode { case .Fetching: self.context.account.postbox.mediaBox.cancelInteractiveResourceFetch(resource.resource) case .Remote: - self.fetchDisposable.set(fetchedMediaResource(postbox: self.context.account.postbox, reference: resource, statsCategory: statsCategory ?? .generic).start()) + self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, reference: resource, statsCategory: statsCategory ?? .generic).start()) default: break } diff --git a/submodules/TelegramUI/TelegramUI/ChatBotInfoItem.swift b/submodules/TelegramUI/TelegramUI/ChatBotInfoItem.swift index 2c42f66e9b..993f51b18a 100644 --- a/submodules/TelegramUI/TelegramUI/ChatBotInfoItem.swift +++ b/submodules/TelegramUI/TelegramUI/ChatBotInfoItem.swift @@ -152,7 +152,7 @@ final class ChatBotInfoItemNode: ListViewItemNode { updatedTextAndEntities = (item.text, generateTextEntities(item.text, enabledTypes: .all)) } - let attributedText = stringWithAppliedEntities(updatedTextAndEntities.0, entities: updatedTextAndEntities.1, baseColor: item.presentationData.theme.theme.chat.message.infoPrimaryTextColor, linkColor: item.presentationData.theme.theme.chat.message.infoLinkTextColor, baseFont: messageFont, linkFont: messageFont, boldFont: messageBoldFont, italicFont: messageItalicFont, boldItalicFont: messageBoldItalicFont, fixedFont: messageFixedFont) + let attributedText = stringWithAppliedEntities(updatedTextAndEntities.0, entities: updatedTextAndEntities.1, baseColor: item.presentationData.theme.theme.chat.message.infoPrimaryTextColor, linkColor: item.presentationData.theme.theme.chat.message.infoLinkTextColor, baseFont: messageFont, linkFont: messageFont, boldFont: messageBoldFont, italicFont: messageItalicFont, boldItalicFont: messageBoldItalicFont, fixedFont: messageFixedFont, blockQuoteFont: messageFont) let horizontalEdgeInset: CGFloat = 10.0 + params.leftInset let horizontalContentInset: CGFloat = 12.0 diff --git a/submodules/TelegramUI/TelegramUI/ChatDocumentGalleryItem.swift b/submodules/TelegramUI/TelegramUI/ChatDocumentGalleryItem.swift index 396970d588..9e994f6f7b 100644 --- a/submodules/TelegramUI/TelegramUI/ChatDocumentGalleryItem.swift +++ b/submodules/TelegramUI/TelegramUI/ChatDocumentGalleryItem.swift @@ -382,7 +382,7 @@ class ChatDocumentGalleryItemNode: ZoomableContentGalleryItemNode, WKNavigationD case .Fetching: context.account.postbox.mediaBox.cancelInteractiveResourceFetch(fileReference.media.resource) case .Remote: - self.fetchDisposable.set(fetchedMediaResource(postbox: context.account.postbox, reference: fileReference.resourceReference(fileReference.media.resource)).start()) + self.fetchDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: fileReference.resourceReference(fileReference.media.resource)).start()) default: break } diff --git a/submodules/TelegramUI/TelegramUI/ChatExternalFileGalleryItem.swift b/submodules/TelegramUI/TelegramUI/ChatExternalFileGalleryItem.swift index 31087e25ba..9e925fb975 100644 --- a/submodules/TelegramUI/TelegramUI/ChatExternalFileGalleryItem.swift +++ b/submodules/TelegramUI/TelegramUI/ChatExternalFileGalleryItem.swift @@ -316,7 +316,7 @@ class ChatExternalFileGalleryItemNode: GalleryItemNode { case .Fetching: context.account.postbox.mediaBox.cancelInteractiveResourceFetch(fileReference.media.resource) case .Remote: - self.fetchDisposable.set(fetchedMediaResource(postbox: context.account.postbox, reference: fileReference.resourceReference(fileReference.media.resource)).start()) + self.fetchDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: fileReference.resourceReference(fileReference.media.resource)).start()) default: break } diff --git a/submodules/TelegramUI/TelegramUI/ChatImageGalleryItem.swift b/submodules/TelegramUI/TelegramUI/ChatImageGalleryItem.swift index 49e12bb097..8b638b3172 100644 --- a/submodules/TelegramUI/TelegramUI/ChatImageGalleryItem.swift +++ b/submodules/TelegramUI/TelegramUI/ChatImageGalleryItem.swift @@ -221,7 +221,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode { self.imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, photoReference: imageReference), dispatchOnDisplayLink: false) self.zoomableContent = (largestSize.dimensions, self.imageNode) - self.fetchDisposable.set(fetchedMediaResource(postbox: self.context.account.postbox, reference: imageReference.resourceReference(largestSize.resource)).start()) + self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, reference: imageReference.resourceReference(largestSize.resource)).start()) self.setupStatus(resource: largestSize.resource) } else { self._ready.set(.single(Void())) @@ -463,7 +463,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode { case .Fetching: self.context.account.postbox.mediaBox.cancelInteractiveResourceFetch(resource.resource) case .Remote: - self.fetchDisposable.set(fetchedMediaResource(postbox: self.context.account.postbox, reference: resource, statsCategory: statsCategory ?? .generic).start()) + self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, reference: resource, statsCategory: statsCategory ?? .generic).start()) default: break } diff --git a/submodules/TelegramUI/TelegramUI/ChatItemGalleryFooterContentNode.swift b/submodules/TelegramUI/TelegramUI/ChatItemGalleryFooterContentNode.swift index 7629d635e4..c09b73d672 100644 --- a/submodules/TelegramUI/TelegramUI/ChatItemGalleryFooterContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatItemGalleryFooterContentNode.swift @@ -167,6 +167,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll private let messageContextDisposable = MetaDisposable() + private var videoFramePreviewNode: ASImageNode? + + private var validLayout: (CGSize, LayoutMetrics, CGFloat, CGFloat, CGFloat, CGFloat)? + var playbackControl: (() -> Void)? var seekBackward: (() -> Void)? var seekForward: (() -> Void)? @@ -225,6 +229,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } } + private var scrubbingHandleRelativePosition: CGFloat = 0.0 + var scrubberView: ChatVideoGalleryItemScrubberView? = nil { willSet { if let scrubberView = self.scrubberView, scrubberView.superview == self.view { @@ -234,6 +240,15 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll didSet { if let scrubberView = self.scrubberView { self.view.addSubview(scrubberView) + scrubberView.updateScrubbingHandlePosition = { [weak self] value in + guard let strongSelf = self else { + return + } + strongSelf.scrubbingHandleRelativePosition = value + if let validLayout = strongSelf.validLayout { + let _ = strongSelf.updateLayout(size: validLayout.0, metrics: validLayout.1, leftInset: validLayout.2, rightInset: validLayout.3, bottomInset: validLayout.4, contentInset: validLayout.5, transition: .immediate) + } + } } } } @@ -500,6 +515,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { + self.validLayout = (size, metrics, leftInset, rightInset, bottomInset, contentInset) + let width = size.width var bottomInset = bottomInset if !bottomInset.isZero && bottomInset < 30.0 { @@ -621,6 +638,17 @@ 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 { + 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) + 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) + } + return panelHeight } @@ -993,4 +1021,44 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll @objc private func statusPressed() { self.fetchControl?() } + + func setFramePreviewImageIsLoading() { + if self.videoFramePreviewNode?.image != nil { + //self.videoFramePreviewNode?.subnodes?.first?.alpha = 1.0 + } + } + + func setFramePreviewImage(image: UIImage?) { + if let image = image { + let videoFramePreviewNode: ASImageNode + var animateIn = false + if let current = self.videoFramePreviewNode { + videoFramePreviewNode = current + } else { + videoFramePreviewNode = ASImageNode() + videoFramePreviewNode.displaysAsynchronously = false + videoFramePreviewNode.displayWithoutProcessing = true + let dimNode = ASDisplayNode() + dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5) + videoFramePreviewNode.addSubnode(dimNode) + self.videoFramePreviewNode = videoFramePreviewNode + self.addSubnode(videoFramePreviewNode) + animateIn = true + } + videoFramePreviewNode.subnodes?.first?.alpha = 0.0 + let updateLayout = videoFramePreviewNode.image?.size != image.size + videoFramePreviewNode.image = image + if updateLayout, let validLayout = self.validLayout { + let _ = self.updateLayout(size: validLayout.0, metrics: validLayout.1, leftInset: validLayout.2, rightInset: validLayout.3, bottomInset: validLayout.4, contentInset: validLayout.5, transition: .immediate) + } + if animateIn { + videoFramePreviewNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) + } + } 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() + }) + } + } } diff --git a/submodules/TelegramUI/TelegramUI/ChatMediaInputStickerPackItem.swift b/submodules/TelegramUI/TelegramUI/ChatMediaInputStickerPackItem.swift index 1d852e5574..30b5d5f32b 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMediaInputStickerPackItem.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMediaInputStickerPackItem.swift @@ -197,7 +197,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode { } } if let resourceReference = resourceReference { - self.stickerFetchedDisposable.set(fetchedMediaResource(postbox: account.postbox, reference: resourceReference).start()) + self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: resourceReference).start()) } } diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageActionItemNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageActionItemNode.swift index 3b7617e208..e07c4c5351 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageActionItemNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageActionItemNode.swift @@ -385,7 +385,7 @@ private func universalServiceMessageString(theme: ChatPresentationThemeData?, st } attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor) case let .customText(text, entities): - attributedString = stringWithAppliedEntities(text, entities: entities, baseColor: primaryTextColor, linkColor: primaryTextColor, baseFont: titleFont, linkFont: titleBoldFont, boldFont: titleBoldFont, italicFont: titleFont, boldItalicFont: titleBoldFont, fixedFont: titleFont, underlineLinks: false) + attributedString = stringWithAppliedEntities(text, entities: entities, baseColor: primaryTextColor, linkColor: primaryTextColor, baseFont: titleFont, linkFont: titleBoldFont, boldFont: titleBoldFont, italicFont: titleFont, boldItalicFont: titleBoldFont, fixedFont: titleFont, blockQuoteFont: titleFont, underlineLinks: false) case let .botDomainAccessGranted(domain): attributedString = NSAttributedString(string: strings.AuthSessions_Message(domain).0, font: titleFont, textColor: primaryTextColor) case let .botSentSecureValues(types): diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageAttachedContentNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageAttachedContentNode.swift index f70cc6e086..b68200b160 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageAttachedContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageAttachedContentNode.swift @@ -15,6 +15,7 @@ private let textBoldFont = Font.semibold(15.0) private let textItalicFont = Font.italic(15.0) private let textBoldItalicFont = Font.semiboldItalic(15.0) private let textFixedFont = Font.regular(15.0) +private let textBlockQuoteFont = Font.regular(15.0) private let buttonFont = Font.semibold(13.0) enum ChatMessageAttachedContentActionIcon { @@ -371,7 +372,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { string.append(NSAttributedString(string: "\n", font: textFont, textColor: messageTheme.primaryTextColor)) } if let entities = entities { - string.append(stringWithAppliedEntities(text, entities: entities, baseColor: messageTheme.primaryTextColor, linkColor: messageTheme.linkTextColor, baseFont: textFont, linkFont: textFont, boldFont: textBoldFont, italicFont: textItalicFont, boldItalicFont: textBoldItalicFont, fixedFont: textFixedFont)) + string.append(stringWithAppliedEntities(text, entities: entities, baseColor: messageTheme.primaryTextColor, linkColor: messageTheme.linkTextColor, baseFont: textFont, linkFont: textFont, boldFont: textBoldFont, italicFont: textItalicFont, boldItalicFont: textBoldItalicFont, fixedFont: textFixedFont, blockQuoteFont: textBlockQuoteFont)) } else { string.append(NSAttributedString(string: text + "\n", font: textFont, textColor: messageTheme.primaryTextColor)) } diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageBubbleItemNode.swift index 5459e75993..8bcbf723a0 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageBubbleItemNode.swift @@ -745,7 +745,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView { if let rawAuthorNameColor = authorNameColor { var dimColors = false switch item.presentationData.theme.theme.name { - case .builtin(.nightAccent), .builtin(.nightGrayscale): + case .builtin(.nightAccent), .builtin(.night): dimColors = true default: break diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveInstantVideoNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveInstantVideoNode.swift index e67014873b..a14ea83239 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveInstantVideoNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveInstantVideoNode.swift @@ -309,7 +309,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { if let updatedFile = updatedFile, updatedMedia { if let resource = updatedFile.previewRepresentations.first?.resource { - strongSelf.fetchedThumbnailDisposable.set(fetchedMediaResource(postbox: item.context.account.postbox, reference: FileMediaReference.message(message: MessageReference(item.message), media: updatedFile).resourceReference(resource)).start()) + strongSelf.fetchedThumbnailDisposable.set(fetchedMediaResource(mediaBox: item.context.account.postbox.mediaBox, reference: FileMediaReference.message(message: MessageReference(item.message), media: updatedFile).resourceReference(resource)).start()) } else { strongSelf.fetchedThumbnailDisposable.set(nil) } diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveMediaNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveMediaNode.swift index 4dfde50fa7..074ffc7141 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveMediaNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveMediaNode.swift @@ -511,7 +511,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { updatedFetchControls = FetchControls(fetch: { manual in if let strongSelf = self { if file.isAnimated { - strongSelf.fetchDisposable.set(fetchedMediaResource(postbox: context.account.postbox, reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), statsCategory: statsCategoryForFileWithAttributes(file.attributes)).start()) + strongSelf.fetchDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), statsCategory: statsCategoryForFileWithAttributes(file.attributes)).start()) } else { strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(context: context, message: message, file: file, userInitiated: manual).start()) } diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageTextBubbleContentNode.swift index 6e98e91484..e33571fb75 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageTextBubbleContentNode.swift @@ -230,7 +230,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { let forceStatusNewline = false if let entities = entities { - attributedText = stringWithAppliedEntities(rawText, entities: entities, baseColor: messageTheme.primaryTextColor, linkColor: messageTheme.linkTextColor, baseFont: textFont, linkFont: textFont, boldFont: item.presentationData.messageBoldFont, italicFont: item.presentationData.messageItalicFont, boldItalicFont: item.presentationData.messageBoldItalicFont, fixedFont: item.presentationData.messageFixedFont) + attributedText = stringWithAppliedEntities(rawText, entities: entities, baseColor: messageTheme.primaryTextColor, linkColor: messageTheme.linkTextColor, baseFont: textFont, linkFont: textFont, boldFont: item.presentationData.messageBoldFont, italicFont: item.presentationData.messageItalicFont, boldItalicFont: item.presentationData.messageBoldItalicFont, fixedFont: item.presentationData.messageFixedFont, blockQuoteFont: item.presentationData.messageBlockQuoteFont) } else { attributedText = NSAttributedString(string: rawText, font: textFont, textColor: messageTheme.primaryTextColor) } @@ -242,7 +242,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { let textInsets = UIEdgeInsets(top: 2.0, left: 0.0, bottom: 5.0, right: 0.0) - let (textLayout, textApply) = textLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: cutout, insets: textInsets)) + let (textLayout, textApply) = textLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: cutout, insets: textInsets, lineColor: messageTheme.accentControlColor)) var textFrame = CGRect(origin: CGPoint(x: -textInsets.left, y: -textInsets.top), size: textLayout.size) var textFrameWithoutInsets = CGRect(origin: CGPoint(x: textFrame.origin.x + textInsets.left, y: textFrame.origin.y + textInsets.top), size: CGSize(width: textFrame.width - textInsets.left - textInsets.right, height: textFrame.height - textInsets.top - textInsets.bottom)) diff --git a/submodules/TelegramUI/TelegramUI/ChatPresentationData.swift b/submodules/TelegramUI/TelegramUI/ChatPresentationData.swift index 9971681d4e..22b3e1a386 100644 --- a/submodules/TelegramUI/TelegramUI/ChatPresentationData.swift +++ b/submodules/TelegramUI/TelegramUI/ChatPresentationData.swift @@ -84,6 +84,7 @@ public final class ChatPresentationData { let messageItalicFont: UIFont let messageBoldItalicFont: UIFont let messageFixedFont: UIFont + let messageBlockQuoteFont: UIFont init(theme: ChatPresentationThemeData, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool, largeEmoji: Bool) { self.theme = theme @@ -103,5 +104,6 @@ public final class ChatPresentationData { self.messageItalicFont = UIFont.italicSystemFont(ofSize: baseFontSize) self.messageBoldItalicFont = Font.semiboldItalic(baseFontSize) self.messageFixedFont = UIFont(name: "Menlo-Regular", size: baseFontSize - 1.0) ?? UIFont.systemFont(ofSize: baseFontSize) + self.messageBlockQuoteFont = UIFont.systemFont(ofSize: baseFontSize - 1.0) } } diff --git a/submodules/TelegramUI/TelegramUI/ChatTextInputAttributes.swift b/submodules/TelegramUI/TelegramUI/ChatTextInputAttributes.swift index 032306111a..939a7918d6 100644 --- a/submodules/TelegramUI/TelegramUI/ChatTextInputAttributes.swift +++ b/submodules/TelegramUI/TelegramUI/ChatTextInputAttributes.swift @@ -39,6 +39,7 @@ struct ChatTextFontAttributes: OptionSet { static let bold = ChatTextFontAttributes(rawValue: 1 << 0) static let italic = ChatTextFontAttributes(rawValue: 1 << 1) static let monospace = ChatTextFontAttributes(rawValue: 1 << 2) + static let blockQuote = ChatTextFontAttributes(rawValue: 1 << 3) } func textAttributedStringForStateText(_ stateText: NSAttributedString, fontSize: CGFloat, textColor: UIColor, accentTextColor: UIColor) -> NSAttributedString { diff --git a/submodules/TelegramUI/TelegramUI/ChatVideoGalleryItemScrubberView.swift b/submodules/TelegramUI/TelegramUI/ChatVideoGalleryItemScrubberView.swift index fc13847130..ab588236ca 100644 --- a/submodules/TelegramUI/TelegramUI/ChatVideoGalleryItemScrubberView.swift +++ b/submodules/TelegramUI/TelegramUI/ChatVideoGalleryItemScrubberView.swift @@ -42,6 +42,8 @@ final class ChatVideoGalleryItemScrubberView: UIView { } } + var updateScrubbing: (Double?) -> Void = { _ in } + var updateScrubbingHandlePosition: (CGFloat) -> Void = { _ in } var seek: (Double) -> Void = { _ in } override init(frame: CGRect) { @@ -63,6 +65,11 @@ final class ChatVideoGalleryItemScrubberView: UIView { self?.seek(timestamp) } + self.scrubberNode.update = { [weak self] timestamp, position in + self?.updateScrubbing(timestamp) + self?.updateScrubbingHandlePosition(position) + } + self.scrubberNode.playerStatusUpdated = { [weak self] status in if let strongSelf = self { strongSelf.playbackStatus = status diff --git a/submodules/TelegramUI/TelegramUI/FetchManager.swift b/submodules/TelegramUI/TelegramUI/FetchManager.swift index 8ad30c60c5..e02ae126c1 100644 --- a/submodules/TelegramUI/TelegramUI/FetchManager.swift +++ b/submodules/TelegramUI/TelegramUI/FetchManager.swift @@ -272,7 +272,7 @@ private final class FetchManagerCategoryContext { parsedRanges = resultRanges } activeContext.disposable?.dispose() - activeContext.disposable = (fetchedMediaResource(postbox: self.postbox, reference: entry.resourceReference, ranges: parsedRanges, statsCategory: entry.statsCategory, reportResultStatus: true, continueInBackground: entry.userInitiated) + activeContext.disposable = (fetchedMediaResource(mediaBox: self.postbox.mediaBox, reference: entry.resourceReference, ranges: parsedRanges, statsCategory: entry.statsCategory, reportResultStatus: true, continueInBackground: entry.userInitiated) |> mapToSignal { type -> Signal in if let storeManager = storeManager, let mediaReference = entry.mediaReference, case .remote = type, let peerType = entry.storeToDownloadsPeerType { return storeDownloadedMedia(storeManager: storeManager, media: mediaReference, peerType: peerType) @@ -413,7 +413,7 @@ private final class FetchManagerCategoryContext { }) } else if ranges.isEmpty { } else { - activeContext.disposable = (fetchedMediaResource(postbox: self.postbox, reference: entry.resourceReference, ranges: parsedRanges, statsCategory: entry.statsCategory, reportResultStatus: true, continueInBackground: entry.userInitiated) + activeContext.disposable = (fetchedMediaResource(mediaBox: self.postbox.mediaBox, reference: entry.resourceReference, ranges: parsedRanges, statsCategory: entry.statsCategory, reportResultStatus: true, continueInBackground: entry.userInitiated) |> mapToSignal { type -> Signal in if let storeManager = storeManager, let mediaReference = entry.mediaReference, case .remote = type, let peerType = entry.storeToDownloadsPeerType { return storeDownloadedMedia(storeManager: storeManager, media: mediaReference, peerType: peerType) diff --git a/submodules/TelegramUI/TelegramUI/FetchMediaUtils.swift b/submodules/TelegramUI/TelegramUI/FetchMediaUtils.swift index 6062d9860f..25c0df6115 100644 --- a/submodules/TelegramUI/TelegramUI/FetchMediaUtils.swift +++ b/submodules/TelegramUI/TelegramUI/FetchMediaUtils.swift @@ -6,11 +6,11 @@ import SwiftSignalKit import TelegramUIPreferences public func freeMediaFileInteractiveFetched(account: Account, fileReference: FileMediaReference) -> Signal { - return fetchedMediaResource(postbox: account.postbox, reference: fileReference.resourceReference(fileReference.media.resource)) + return fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(fileReference.media.resource)) } func freeMediaFileResourceInteractiveFetched(account: Account, fileReference: FileMediaReference, resource: MediaResource) -> Signal { - return fetchedMediaResource(postbox: account.postbox, reference: fileReference.resourceReference(resource)) + return fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(resource)) } func cancelFreeMediaFileInteractiveFetch(account: Account, file: TelegramMediaFile) { diff --git a/submodules/TelegramUI/TelegramUI/FetchVideoThumbnail.swift b/submodules/TelegramUI/TelegramUI/FetchVideoThumbnail.swift index 7b15a72e72..f485016bee 100644 --- a/submodules/TelegramUI/TelegramUI/FetchVideoThumbnail.swift +++ b/submodules/TelegramUI/TelegramUI/FetchVideoThumbnail.swift @@ -344,8 +344,8 @@ func fetchedPartialVideoThumbnailData(postbox: Postbox, fileReference: FileMedia subscriber.putCompletion() return EmptyDisposable } - let fetchedHead = fetchedMediaResource(postbox: postbox, reference: fileReference.resourceReference(fileReference.media.resource), range: (0 ..< min(size, headerSize), .elevated), statsCategory: .video, reportResultStatus: false, preferBackgroundReferenceRevalidation: false).start() - let fetchedTail = fetchedMediaResource(postbox: postbox, reference: fileReference.resourceReference(fileReference.media.resource), range: (max(0, size - tailSize) ..< size, .elevated), statsCategory: .video, reportResultStatus: false, preferBackgroundReferenceRevalidation: false).start() + let fetchedHead = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: fileReference.resourceReference(fileReference.media.resource), range: (0 ..< min(size, headerSize), .elevated), statsCategory: .video, reportResultStatus: false, preferBackgroundReferenceRevalidation: false).start() + let fetchedTail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: fileReference.resourceReference(fileReference.media.resource), range: (max(0, size - tailSize) ..< size, .elevated), statsCategory: .video, reportResultStatus: false, preferBackgroundReferenceRevalidation: false).start() return ActionDisposable { fetchedHead.dispose() diff --git a/submodules/TelegramUI/TelegramUI/GalleryController.swift b/submodules/TelegramUI/TelegramUI/GalleryController.swift index e2c884eb88..6856c12d7a 100644 --- a/submodules/TelegramUI/TelegramUI/GalleryController.swift +++ b/submodules/TelegramUI/TelegramUI/GalleryController.swift @@ -122,7 +122,7 @@ private let boldItalicFont = Font.semiboldItalic(16.0) private let fixedFont = UIFont(name: "Menlo-Regular", size: 15.0) ?? textFont func galleryCaptionStringWithAppliedEntities(_ text: String, entities: [MessageTextEntity]) -> NSAttributedString { - return stringWithAppliedEntities(text, entities: entities, baseColor: .white, linkColor: UIColor(rgb: 0x5ac8fa), baseFont: textFont, linkFont: textFont, boldFont: boldFont, italicFont: italicFont, boldItalicFont: boldItalicFont, fixedFont: fixedFont, underlineLinks: false) + return stringWithAppliedEntities(text, entities: entities, baseColor: .white, linkColor: UIColor(rgb: 0x5ac8fa), baseFont: textFont, linkFont: textFont, boldFont: boldFont, italicFont: italicFont, boldItalicFont: boldItalicFont, fixedFont: fixedFont, blockQuoteFont: textFont, underlineLinks: false) } private func galleryMessageCaptionText(_ message: Message) -> String { diff --git a/submodules/TelegramUI/TelegramUI/GroupStickerPackCurrentItem.swift b/submodules/TelegramUI/TelegramUI/GroupStickerPackCurrentItem.swift index c82c8346f8..6840993a82 100644 --- a/submodules/TelegramUI/TelegramUI/GroupStickerPackCurrentItem.swift +++ b/submodules/TelegramUI/TelegramUI/GroupStickerPackCurrentItem.swift @@ -228,7 +228,7 @@ class GroupStickerPackCurrentItemNode: ItemListRevealOptionsItemNode { if fileUpdated { if let file = file { updatedImageSignal = chatMessageSticker(account: item.account, file: file, small: false) - updatedFetchSignal = fetchedMediaResource(postbox: item.account.postbox, reference: stickerPackFileReference(file).resourceReference(file.resource)) + updatedFetchSignal = fetchedMediaResource(mediaBox: item.account.postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(file.resource)) } else { updatedImageSignal = .single({ _ in return nil }) updatedFetchSignal = .complete() diff --git a/submodules/TelegramUI/TelegramUI/InstantImageGalleryItem.swift b/submodules/TelegramUI/TelegramUI/InstantImageGalleryItem.swift index b44d45f0ff..bcfd2415ce 100644 --- a/submodules/TelegramUI/TelegramUI/InstantImageGalleryItem.swift +++ b/submodules/TelegramUI/TelegramUI/InstantImageGalleryItem.swift @@ -133,7 +133,7 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode { self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets(), emptyColor: .black))() self.imageNode.setSignal(chatMessagePhoto(postbox: self.context.account.postbox, photoReference: imageReference), dispatchOnDisplayLink: false) self.zoomableContent = (largestSize.dimensions, self.imageNode) - self.fetchDisposable.set(fetchedMediaResource(postbox: self.context.account.postbox, reference: imageReference.resourceReference(largestSize.resource)).start()) + self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, reference: imageReference.resourceReference(largestSize.resource)).start()) } else { self._ready.set(.single(Void())) } @@ -286,7 +286,7 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode { if let (context, media) = self.contextAndMedia, let fileReference = media.concrete(TelegramMediaFile.self) { if isVisible { - self.fetchDisposable.set(fetchedMediaResource(postbox: context.account.postbox, reference: fileReference.resourceReference(fileReference.media.resource)).start()) + self.fetchDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: fileReference.resourceReference(fileReference.media.resource)).start()) } else { self.fetchDisposable.set(nil) } diff --git a/submodules/TelegramUI/TelegramUI/InstantPagePlayableVideoNode.swift b/submodules/TelegramUI/TelegramUI/InstantPagePlayableVideoNode.swift index 4a1f95d6b8..2bcee6071d 100644 --- a/submodules/TelegramUI/TelegramUI/InstantPagePlayableVideoNode.swift +++ b/submodules/TelegramUI/TelegramUI/InstantPagePlayableVideoNode.swift @@ -57,7 +57,7 @@ final class InstantPagePlayableVideoNode: ASDisplayNode, InstantPageNode { self.addSubnode(self.videoNode) if let file = media.media as? TelegramMediaFile { - self.fetchedDisposable.set(fetchedMediaResource(postbox: context.account.postbox, reference: AnyMediaReference.webPage(webPage: WebpageReference(webPage), media: file).resourceReference(file.resource)).start()) + self.fetchedDisposable.set(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: AnyMediaReference.webPage(webPage: WebpageReference(webPage), media: file).resourceReference(file.resource)).start()) self.statusDisposable.set((context.account.postbox.mediaBox.resourceStatus(file.resource) |> deliverOnMainQueue).start(next: { [weak self] status in displayLinkDispatcher.dispatch { diff --git a/submodules/TelegramUI/TelegramUI/ItemListAddressItem.swift b/submodules/TelegramUI/TelegramUI/ItemListAddressItem.swift index c05ce7c48f..c5eaa57a47 100644 --- a/submodules/TelegramUI/TelegramUI/ItemListAddressItem.swift +++ b/submodules/TelegramUI/TelegramUI/ItemListAddressItem.swift @@ -182,7 +182,7 @@ class ItemListAddressItemNode: ListViewItemNode { let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.label, font: labelFont, textColor: labelColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftOffset - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let baseColor = item.theme.list.itemPrimaryTextColor - let string = stringWithAppliedEntities(item.text, entities: [], baseColor: baseColor, linkColor: item.theme.list.itemAccentColor, baseFont: textFont, linkFont: textFont, boldFont: textBoldFont, italicFont: textItalicFont, boldItalicFont: textBoldItalicFont, fixedFont: textFixedFont) + let string = stringWithAppliedEntities(item.text, entities: [], baseColor: baseColor, linkColor: item.theme.list.itemAccentColor, baseFont: textFont, linkFont: textFont, boldFont: textBoldFont, italicFont: textItalicFont, boldItalicFont: textBoldItalicFont, fixedFont: textFixedFont, blockQuoteFont: textFont) let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: string, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - leftOffset - leftInset - rightInset - 98.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let padding: CGFloat = !item.label.isEmpty ? 39.0 : 20.0 diff --git a/submodules/TelegramUI/TelegramUI/ItemListDisclosureItem.swift b/submodules/TelegramUI/TelegramUI/ItemListDisclosureItem.swift index b5ef0e3c4d..8f480b8912 100644 --- a/submodules/TelegramUI/TelegramUI/ItemListDisclosureItem.swift +++ b/submodules/TelegramUI/TelegramUI/ItemListDisclosureItem.swift @@ -258,7 +258,7 @@ class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode { var labelConstrain: CGFloat = params.width - params.rightInset - leftInset - 40.0 - titleLayout.size.width - 10.0 switch item.labelStyle { case .badge: - labelBadgeColor = item.theme.rootController.tabBar.badgeTextColor + labelBadgeColor = item.theme.list.itemCheckColors.foregroundColor labelFont = badgeFont case .detailText, .multilineDetailText: labelBadgeColor = item.theme.list.itemSecondaryTextColor diff --git a/submodules/TelegramUI/TelegramUI/ItemListMultilineTextItem.swift b/submodules/TelegramUI/TelegramUI/ItemListMultilineTextItem.swift index 8a0dd83357..2b85440197 100644 --- a/submodules/TelegramUI/TelegramUI/ItemListMultilineTextItem.swift +++ b/submodules/TelegramUI/TelegramUI/ItemListMultilineTextItem.swift @@ -185,7 +185,7 @@ class ItemListMultilineTextItemNode: ListViewItemNode { } let entities = generateTextEntities(item.text, enabledTypes: item.enabledEntityTypes) - let string = stringWithAppliedEntities(item.text, entities: entities, baseColor: textColor, linkColor: item.theme.list.itemAccentColor, baseFont: titleFont, linkFont: titleFont, boldFont: titleBoldFont, italicFont: titleItalicFont, boldItalicFont: titleBoldItalicFont, fixedFont: titleFixedFont) + let string = stringWithAppliedEntities(item.text, entities: entities, baseColor: textColor, linkColor: item.theme.list.itemAccentColor, baseFont: titleFont, linkFont: titleFont, boldFont: titleBoldFont, italicFont: titleItalicFont, boldItalicFont: titleBoldItalicFont, fixedFont: titleFixedFont, blockQuoteFont: titleFont) let (titleLayout, titleApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: string, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 20.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) diff --git a/submodules/TelegramUI/TelegramUI/ItemListStickerPackItem.swift b/submodules/TelegramUI/TelegramUI/ItemListStickerPackItem.swift index 879f756a5e..a7ed3223d8 100644 --- a/submodules/TelegramUI/TelegramUI/ItemListStickerPackItem.swift +++ b/submodules/TelegramUI/TelegramUI/ItemListStickerPackItem.swift @@ -377,7 +377,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { imageSize = imageBoundingSize } if fileUpdated, let resourceReference = resourceReference { - updatedFetchSignal = fetchedMediaResource(postbox: item.account.postbox, reference: resourceReference) + updatedFetchSignal = fetchedMediaResource(mediaBox: item.account.postbox.mediaBox, reference: resourceReference) } } else { updatedImageSignal = .single({ _ in return nil }) diff --git a/submodules/TelegramUI/TelegramUI/ItemListTextWithLabelItem.swift b/submodules/TelegramUI/TelegramUI/ItemListTextWithLabelItem.swift index 774113f7eb..c21de0574d 100644 --- a/submodules/TelegramUI/TelegramUI/ItemListTextWithLabelItem.swift +++ b/submodules/TelegramUI/TelegramUI/ItemListTextWithLabelItem.swift @@ -209,7 +209,7 @@ class ItemListTextWithLabelItemNode: ListViewItemNode { case .highlighted: baseColor = item.theme.list.itemHighlightedColor } - let string = stringWithAppliedEntities(item.text, entities: entities, baseColor: baseColor, linkColor: item.theme.list.itemAccentColor, baseFont: textFont, linkFont: textFont, boldFont: textBoldFont, italicFont: textItalicFont, boldItalicFont: textBoldItalicFont, fixedFont: textFixedFont) + let string = stringWithAppliedEntities(item.text, entities: entities, baseColor: baseColor, linkColor: item.theme.list.itemAccentColor, baseFont: textFont, linkFont: textFont, boldFont: textBoldFont, italicFont: textItalicFont, boldItalicFont: textBoldItalicFont, fixedFont: textFixedFont, blockQuoteFont: textFont) let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: string, backgroundColor: nil, maximumNumberOfLines: item.multiline ? 0 : 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftOffset - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let contentSize = CGSize(width: params.width, height: textLayout.size.height + 39.0) diff --git a/submodules/TelegramUI/TelegramUI/LegacyPreferencesImport.swift b/submodules/TelegramUI/TelegramUI/LegacyPreferencesImport.swift index 046361b72c..47b1af5fc1 100644 --- a/submodules/TelegramUI/TelegramUI/LegacyPreferencesImport.swift +++ b/submodules/TelegramUI/TelegramUI/LegacyPreferencesImport.swift @@ -183,7 +183,7 @@ func importLegacyPreferences(accountManager: AccountManager, account: TemporaryA } settings.chatWallpaper = .color(0xffffff) case 2: - settings.theme = .builtin(.nightGrayscale) + settings.theme = .builtin(.night) settings.chatWallpaper = .color(0x00000) case 3: settings.theme = .builtin(.nightAccent) @@ -213,7 +213,7 @@ func importLegacyPreferences(accountManager: AccountManager, account: TemporaryA let nightTheme: PresentationBuiltinThemeReference switch autoNightPreferences.preferredPalette { case 1: - nightTheme = .nightGrayscale + nightTheme = .night default: nightTheme = .nightAccent } diff --git a/submodules/TelegramUI/TelegramUI/MultiplexedSoftwareVideoSourceManager.swift b/submodules/TelegramUI/TelegramUI/MultiplexedSoftwareVideoSourceManager.swift index 61f789fb89..deff80076a 100644 --- a/submodules/TelegramUI/TelegramUI/MultiplexedSoftwareVideoSourceManager.swift +++ b/submodules/TelegramUI/TelegramUI/MultiplexedSoftwareVideoSourceManager.swift @@ -66,7 +66,7 @@ final class MultiplexedSoftwareVideoSourceManager { context.source = SoftwareVideoSource(path: data.path) } } - }), fetchStatusDisposable: fetchedMediaResource(postbox: self.account.postbox, reference: AnyMediaReference.standalone(media: file).resourceReference(file.resource)).start()) + }), fetchStatusDisposable: fetchedMediaResource(mediaBox: self.account.postbox.mediaBox, reference: AnyMediaReference.standalone(media: file).resourceReference(file.resource)).start()) } } } diff --git a/submodules/TelegramUI/TelegramUI/NativeVideoContent.swift b/submodules/TelegramUI/TelegramUI/NativeVideoContent.swift index 962bb21008..7458ad6094 100644 --- a/submodules/TelegramUI/TelegramUI/NativeVideoContent.swift +++ b/submodules/TelegramUI/TelegramUI/NativeVideoContent.swift @@ -312,7 +312,7 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent func fetchControl(_ control: UniversalVideoNodeFetchControl) { switch control { case .fetch: - self.fetchDisposable.set(fetchedMediaResource(postbox: self.postbox, reference: self.fileReference.resourceReference(self.fileReference.media.resource), statsCategory: statsCategoryForFileWithAttributes(self.fileReference.media.attributes)).start()) + self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.postbox.mediaBox, reference: self.fileReference.resourceReference(self.fileReference.media.resource), statsCategory: statsCategoryForFileWithAttributes(self.fileReference.media.attributes)).start()) case .cancel: self.postbox.mediaBox.cancelInteractiveResourceFetch(self.fileReference.media.resource) } diff --git a/submodules/TelegramUI/TelegramUI/OpenChatMessage.swift b/submodules/TelegramUI/TelegramUI/OpenChatMessage.swift index e9a787018f..1a7b70ad11 100644 --- a/submodules/TelegramUI/TelegramUI/OpenChatMessage.swift +++ b/submodules/TelegramUI/TelegramUI/OpenChatMessage.swift @@ -355,8 +355,8 @@ func openChatMessage(context: AccountContext, message: Message, standalone: Bool } return nil })) - case let .theme(file): - let controller = ThemePreviewController(context: context, previewTheme: makeDefaultDayPresentationTheme(accentColor: nil, serviceBackgroundColor: .black)) + case let .theme(media): + let controller = ThemePreviewController(context: context, previewTheme: makeDefaultDayPresentationTheme(accentColor: nil, serviceBackgroundColor: .black), media: .message(message: MessageReference(message), media: media)) present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) } } diff --git a/submodules/TelegramUI/TelegramUI/Pasteboard.swift b/submodules/TelegramUI/TelegramUI/Pasteboard.swift index 3f654f700d..7b10d9ea40 100644 --- a/submodules/TelegramUI/TelegramUI/Pasteboard.swift +++ b/submodules/TelegramUI/TelegramUI/Pasteboard.swift @@ -5,7 +5,7 @@ import TelegramCore import MobileCoreServices private func rtfStringWithAppliedEntities(_ text: String, entities: [MessageTextEntity]) -> String { - let test = stringWithAppliedEntities(text, entities: entities, baseColor: .black, linkColor: .black, baseFont: Font.regular(14.0), linkFont: Font.regular(14.0), boldFont: Font.semibold(14.0), italicFont: Font.italic(14.0), boldItalicFont: Font.semiboldItalic(14.0), fixedFont: Font.monospace(14.0), underlineLinks: false, external: true) + let test = stringWithAppliedEntities(text, entities: entities, baseColor: .black, linkColor: .black, baseFont: Font.regular(14.0), linkFont: Font.regular(14.0), boldFont: Font.semibold(14.0), italicFont: Font.italic(14.0), boldItalicFont: Font.semiboldItalic(14.0), fixedFont: Font.monospace(14.0), blockQuoteFont: Font.regular(14.0), underlineLinks: false, external: true) if let data = try? test.data(from: NSRange(location: 0, length: test.length), documentAttributes: [NSAttributedString.DocumentAttributeKey.documentType: NSAttributedString.DocumentType.rtf]) { if var rtf = String(data: data, encoding: .windowsCP1252) { diff --git a/submodules/TelegramUI/TelegramUI/PeerAvatar.swift b/submodules/TelegramUI/TelegramUI/PeerAvatar.swift index 27dee710bf..53f5581b2b 100644 --- a/submodules/TelegramUI/TelegramUI/PeerAvatar.swift +++ b/submodules/TelegramUI/TelegramUI/PeerAvatar.swift @@ -44,11 +44,11 @@ public func peerAvatarImageData(account: Account, peer: Peer, authorOfMessage: M }) var fetchedDataDisposable: Disposable? if let peerReference = PeerReference(peer) { - fetchedDataDisposable = fetchedMediaResource(postbox: account.postbox, reference: .avatar(peer: peerReference, resource: smallProfileImage.resource), statsCategory: .generic).start() + fetchedDataDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .avatar(peer: peerReference, resource: smallProfileImage.resource), statsCategory: .generic).start() } else if let authorOfMessage = authorOfMessage { - fetchedDataDisposable = fetchedMediaResource(postbox: account.postbox, reference: .messageAuthorAvatar(message: authorOfMessage, resource: smallProfileImage.resource), statsCategory: .generic).start() + fetchedDataDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .messageAuthorAvatar(message: authorOfMessage, resource: smallProfileImage.resource), statsCategory: .generic).start() } else { - fetchedDataDisposable = fetchedMediaResource(postbox: account.postbox, reference: .standalone(resource: smallProfileImage.resource), statsCategory: .generic).start() + fetchedDataDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .standalone(resource: smallProfileImage.resource), statsCategory: .generic).start() } return ActionDisposable { resourceDataDisposable.dispose() diff --git a/submodules/TelegramUI/TelegramUI/PeerAvatarImageGalleryItem.swift b/submodules/TelegramUI/TelegramUI/PeerAvatarImageGalleryItem.swift index 4678d64f96..2b289a341d 100644 --- a/submodules/TelegramUI/TelegramUI/PeerAvatarImageGalleryItem.swift +++ b/submodules/TelegramUI/TelegramUI/PeerAvatarImageGalleryItem.swift @@ -174,7 +174,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode { self.imageNode.setSignal(chatAvatarGalleryPhoto(account: self.context.account, representations: representations), dispatchOnDisplayLink: false) self.zoomableContent = (largestSize.dimensions, self.imageNode) if let largestIndex = representations.index(where: { $0.representation == largestSize }) { - self.fetchDisposable.set(fetchedMediaResource(postbox: self.context.account.postbox, reference: representations[largestIndex].reference).start()) + self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, reference: representations[largestIndex].reference).start()) } self.statusDisposable.set((self.context.account.postbox.mediaBox.resourceStatus(largestSize.resource) @@ -341,7 +341,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode { } if let largestIndex = representations.index(where: { $0.representation == largestSize }) { - self.fetchDisposable.set(fetchedMediaResource(postbox: self.context.account.postbox, reference: representations[largestIndex].reference).start()) + self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, reference: representations[largestIndex].reference).start()) } default: break diff --git a/submodules/TelegramUI/TelegramUI/PhotoResources.swift b/submodules/TelegramUI/TelegramUI/PhotoResources.swift index d297052a78..bccee7a2e8 100644 --- a/submodules/TelegramUI/TelegramUI/PhotoResources.swift +++ b/submodules/TelegramUI/TelegramUI/PhotoResources.swift @@ -39,9 +39,9 @@ func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaReference if let _ = decodedThumbnailData { fetchedThumbnail = .complete() } else { - fetchedThumbnail = fetchedMediaResource(postbox: postbox, reference: photoReference.resourceReference(smallestRepresentation.resource), statsCategory: .image) + fetchedThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: photoReference.resourceReference(smallestRepresentation.resource), statsCategory: .image) } - let fetchedFullSize = fetchedMediaResource(postbox: postbox, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image) + let fetchedFullSize = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image) let anyThumbnail: [Signal] if tryAdditionalRepresentations { @@ -148,7 +148,7 @@ private func chatMessageFileDatas(account: Account, fileReference: FileMediaRefe if !fetched, let _ = decodedThumbnailData { fetchedThumbnail = .single(.local) } else if let thumbnailResource = thumbnailResource { - fetchedThumbnail = fetchedMediaResource(postbox: account.postbox, reference: fileReference.resourceReference(thumbnailResource), statsCategory: statsCategoryForFileWithAttributes(fileReference.media.attributes)) + fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource), statsCategory: statsCategoryForFileWithAttributes(fileReference.media.attributes)) } else { fetchedThumbnail = .complete() } @@ -211,7 +211,7 @@ private func chatMessageImageFileThumbnailDatas(account: Account, fileReference: if let decodedThumbnailData = decodedThumbnailData { if autoFetchFullSizeThumbnail, let thumbnailRepresentation = thumbnailRepresentation, (thumbnailRepresentation.dimensions.width > 200.0 || thumbnailRepresentation.dimensions.height > 200.0) { return Signal { subscriber in - let fetchedDisposable = fetchedMediaResource(postbox: account.postbox, reference: fileReference.resourceReference(thumbnailRepresentation.resource), statsCategory: .video).start() + let fetchedDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(thumbnailRepresentation.resource), statsCategory: .video).start() let thumbnailDisposable = account.postbox.mediaBox.resourceData(thumbnailRepresentation.resource, attemptSynchronously: false).start(next: { next in let data: Data? = next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []) subscriber.putNext(Tuple(data ?? decodedThumbnailData, nil, false)) @@ -226,7 +226,7 @@ private func chatMessageImageFileThumbnailDatas(account: Account, fileReference: return .single(Tuple(decodedThumbnailData, nil, false)) } } else if let thumbnailResource = thumbnailResource { - let fetchedThumbnail: Signal = fetchedMediaResource(postbox: account.postbox, reference: fileReference.resourceReference(thumbnailResource)) + let fetchedThumbnail: Signal = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource)) return Signal { subscriber in let fetchedDisposable = fetchedThumbnail.start() let thumbnailDisposable = account.postbox.mediaBox.resourceData(thumbnailResource, pathExtension: pathExtension).start(next: { next in @@ -262,7 +262,7 @@ private func chatMessageImageFileThumbnailDatas(account: Account, fileReference: if let _ = fileReference.media.immediateThumbnailData { fetchedThumbnail = .complete() } else if let thumbnailResource = thumbnailResource { - fetchedThumbnail = fetchedMediaResource(postbox: account.postbox, reference: fileReference.resourceReference(thumbnailResource)) + fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource)) } else { fetchedThumbnail = .complete() } @@ -330,7 +330,7 @@ private func chatMessageVideoDatas(postbox: Postbox, fileReference: FileMediaRef } else if let decodedThumbnailData = fileReference.media.immediateThumbnailData.flatMap(decodeTinyThumbnail) { if autoFetchFullSizeThumbnail, let thumbnailRepresentation = thumbnailRepresentation, (thumbnailRepresentation.dimensions.width > 200.0 || thumbnailRepresentation.dimensions.height > 200.0) { thumbnail = Signal { subscriber in - let fetchedDisposable = fetchedMediaResource(postbox: postbox, reference: fileReference.resourceReference(thumbnailRepresentation.resource), statsCategory: .video).start() + let fetchedDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: fileReference.resourceReference(thumbnailRepresentation.resource), statsCategory: .video).start() let thumbnailDisposable = postbox.mediaBox.resourceData(thumbnailRepresentation.resource, attemptSynchronously: synchronousLoad).start(next: { next in let data: Data? = next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []) subscriber.putNext(data ?? decodedThumbnailData) @@ -346,7 +346,7 @@ private func chatMessageVideoDatas(postbox: Postbox, fileReference: FileMediaRef } } else if let thumbnailResource = thumbnailResource { thumbnail = Signal { subscriber in - let fetchedDisposable = fetchedMediaResource(postbox: postbox, reference: fileReference.resourceReference(thumbnailResource), statsCategory: .video).start() + let fetchedDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource), statsCategory: .video).start() let thumbnailDisposable = postbox.mediaBox.resourceData(thumbnailResource, attemptSynchronously: synchronousLoad).start(next: { next in subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: [])) }, error: subscriber.putError, completed: subscriber.putCompletion) @@ -893,7 +893,7 @@ private func chatMessagePhotoThumbnailDatas(account: Account, photoReference: Im let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: []) return .single(Tuple(nil, loadedData, true)) } else { - let fetchedThumbnail = fetchedMediaResource(postbox: account.postbox, reference: photoReference.resourceReference(smallestRepresentation.resource), statsCategory: .image) + let fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: photoReference.resourceReference(smallestRepresentation.resource), statsCategory: .image) let thumbnail = Signal { subscriber in let fetchedDisposable = fetchedThumbnail.start() @@ -1235,8 +1235,8 @@ private func avatarGalleryThumbnailDatas(postbox: Postbox, representations: [Ima let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: []) return .single(Tuple(nil, loadedData, true)) } else { - let fetchedThumbnail = fetchedMediaResource(postbox: postbox, reference: representations[smallestIndex].reference, statsCategory: .image) - let fetchedFullSize = fetchedMediaResource(postbox: postbox, reference: representations[largestIndex].reference, statsCategory: .image) + let fetchedThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: representations[smallestIndex].reference, statsCategory: .image) + let fetchedFullSize = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: representations[largestIndex].reference, statsCategory: .image) let thumbnail = Signal { subscriber in let fetchedDisposable = fetchedThumbnail.start() @@ -1474,7 +1474,7 @@ func gifPaneVideoThumbnail(account: Account, videoReference: FileMediaReference) }, completed: { subscriber.putCompletion() }) - let fetched = fetchedMediaResource(postbox: account.postbox, reference: videoReference.resourceReference(thumbnailResource)).start() + let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: videoReference.resourceReference(thumbnailResource)).start() return ActionDisposable { data.dispose() fetched.dispose() @@ -1763,7 +1763,7 @@ func chatMessagePhotoStatus(context: AccountContext, messageId: MessageId, photo public func standaloneChatMessagePhotoInteractiveFetched(account: Account, photoReference: ImageMediaReference) -> Signal { if let largestRepresentation = largestRepresentationForPhoto(photoReference.media) { - return fetchedMediaResource(postbox: account.postbox, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image, reportResultStatus: true) + return fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image, reportResultStatus: true) |> mapToSignal { type -> Signal in return .single(type) } @@ -1774,7 +1774,7 @@ public func standaloneChatMessagePhotoInteractiveFetched(account: Account, photo public func chatMessagePhotoInteractiveFetched(context: AccountContext, photoReference: ImageMediaReference, storeToDownloadsPeerType: MediaAutoDownloadPeerType?) -> Signal { if let largestRepresentation = largestRepresentationForPhoto(photoReference.media) { - return fetchedMediaResource(postbox: context.account.postbox, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image, reportResultStatus: true) + return fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image, reportResultStatus: true) |> mapToSignal { type -> Signal in if case .remote = type, let peerType = storeToDownloadsPeerType { return storeDownloadedMedia(storeManager: context.downloadedMediaStoreManager, media: photoReference.abstract, peerType: peerType) @@ -1798,7 +1798,7 @@ func chatMessagePhotoCancelInteractiveFetch(account: Account, photoReference: Im } func chatMessageWebFileInteractiveFetched(account: Account, image: TelegramMediaWebFile) -> Signal { - return fetchedMediaResource(postbox: account.postbox, reference: .standalone(resource: image.resource), statsCategory: .image) + return fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .standalone(resource: image.resource), statsCategory: .image) } func chatMessageWebFileCancelInteractiveFetch(account: Account, image: TelegramMediaWebFile) { @@ -1820,7 +1820,7 @@ func chatWebpageSnippetFileData(account: Account, fileReference: FileMediaRefere }, completed: { subscriber.putCompletion() })) - disposable.add(fetchedMediaResource(postbox: account.postbox, reference: fileReference.resourceReference(resource)).start()) + disposable.add(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(resource)).start()) return disposable } } @@ -1841,7 +1841,7 @@ func chatWebpageSnippetPhotoData(account: Account, photoReference: ImageMediaRef }, completed: { subscriber.putCompletion() })) - disposable.add(fetchedMediaResource(postbox: account.postbox, reference: photoReference.resourceReference(closestRepresentation.resource)).start()) + disposable.add(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: photoReference.resourceReference(closestRepresentation.resource)).start()) return disposable } } else { @@ -1943,7 +1943,7 @@ private func chatSecretMessageVideoData(account: Account, fileReference: FileMed if let smallestRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) { let thumbnailResource = smallestRepresentation.resource - let fetchedThumbnail = fetchedMediaResource(postbox: account.postbox, reference: fileReference.resourceReference(thumbnailResource)) + let fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource)) let decodedThumbnailData = fileReference.media.immediateThumbnailData.flatMap(decodeTinyThumbnail) @@ -2313,8 +2313,8 @@ private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaR let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: []) return .single(Tuple(nil, loadedData, true)) } else { - let fetchedThumbnail = fetchedMediaResource(postbox: account.postbox, reference: representations[smallestIndex].reference) - let fetchedFullSize = fetchedMediaResource(postbox: account.postbox, reference: representations[largestIndex].reference) + let fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: representations[smallestIndex].reference) + let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: representations[largestIndex].reference) let thumbnail = Signal { subscriber in let fetchedDisposable = fetchedThumbnail.start() @@ -2792,7 +2792,7 @@ func playerAlbumArt(postbox: Postbox, fileReference: FileMediaReference?, albumA if let fileReference = fileReference, let smallestRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) { let thumbnailResource = smallestRepresentation.resource - let fetchedThumbnail = fetchedMediaResource(postbox: postbox, reference: fileReference.resourceReference(thumbnailResource)) + let fetchedThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: fileReference.resourceReference(thumbnailResource)) let thumbnail = Signal { subscriber in let fetchedDisposable = fetchedThumbnail.start() diff --git a/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping b/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping index 0282856f52..6ff2cc2f42 100644 Binary files a/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping and b/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping differ diff --git a/submodules/TelegramUI/TelegramUI/SaveToCameraRoll.swift b/submodules/TelegramUI/TelegramUI/SaveToCameraRoll.swift index 280c0df029..f22e48de05 100644 --- a/submodules/TelegramUI/TelegramUI/SaveToCameraRoll.swift +++ b/submodules/TelegramUI/TelegramUI/SaveToCameraRoll.swift @@ -45,7 +45,7 @@ private func fetchMediaData(context: AccountContext, postbox: Postbox, mediaRefe if let resource = resource { let fetchedData: Signal = Signal { subscriber in - let fetched = fetchedMediaResource(postbox: postbox, reference: mediaReference.resourceReference(resource)).start() + let fetched = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: mediaReference.resourceReference(resource)).start() let status = postbox.mediaBox.resourceStatus(resource).start(next: { status in switch status { case .Local: diff --git a/submodules/TelegramUI/TelegramUI/ShareController.swift b/submodules/TelegramUI/TelegramUI/ShareController.swift index 32756d36ea..3588f9d5cb 100644 --- a/submodules/TelegramUI/TelegramUI/ShareController.swift +++ b/submodules/TelegramUI/TelegramUI/ShareController.swift @@ -54,7 +54,7 @@ private enum ExternalShareResourceStatus { private func collectExternalShareResource(postbox: Postbox, resourceReference: MediaResourceReference, statsCategory: MediaResourceStatsCategory) -> Signal { return Signal { subscriber in - let fetched = fetchedMediaResource(postbox: postbox, reference: resourceReference, statsCategory: statsCategory).start() + let fetched = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: resourceReference, statsCategory: statsCategory).start() let data = postbox.mediaBox.resourceData(resourceReference.resource, option: .complete(waitUntilFetchStatus: false)).start(next: { value in if value.complete { subscriber.putNext(.done(value)) diff --git a/submodules/TelegramUI/TelegramUI/SharedMediaPlayer.swift b/submodules/TelegramUI/TelegramUI/SharedMediaPlayer.swift index 3455ebf698..348dce7358 100644 --- a/submodules/TelegramUI/TelegramUI/SharedMediaPlayer.swift +++ b/submodules/TelegramUI/TelegramUI/SharedMediaPlayer.swift @@ -751,7 +751,7 @@ final class SharedMediaPlayer { } switch next { case let .telegramFile(file): - fetchedNextSignal = fetchedMediaResource(postbox: self.account.postbox, reference: file.resourceReference(file.media.resource)) + fetchedNextSignal = fetchedMediaResource(mediaBox: self.account.postbox.mediaBox, reference: file.resourceReference(file.media.resource)) |> ignoreValues |> `catch` { _ -> Signal in return .complete() diff --git a/submodules/TelegramUI/TelegramUI/SoftwareVideoLayerFrameManager.swift b/submodules/TelegramUI/TelegramUI/SoftwareVideoLayerFrameManager.swift index 1867870198..7385a10619 100644 --- a/submodules/TelegramUI/TelegramUI/SoftwareVideoLayerFrameManager.swift +++ b/submodules/TelegramUI/TelegramUI/SoftwareVideoLayerFrameManager.swift @@ -38,7 +38,7 @@ final class SoftwareVideoLayerFrameManager { self.layerHolder = layerHolder layerHolder.layer.videoGravity = .resizeAspectFill layerHolder.layer.masksToBounds = true - self.fetchDisposable = fetchedMediaResource(postbox: account.postbox, reference: fileReference.resourceReference(resource)).start() + self.fetchDisposable = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(resource)).start() } deinit { diff --git a/submodules/TelegramUI/TelegramUI/StickerPackPreviewController.swift b/submodules/TelegramUI/TelegramUI/StickerPackPreviewController.swift index cce3af5d24..76dd7c71b9 100644 --- a/submodules/TelegramUI/TelegramUI/StickerPackPreviewController.swift +++ b/submodules/TelegramUI/TelegramUI/StickerPackPreviewController.swift @@ -155,7 +155,7 @@ final class StickerPackPreviewController: ViewController { for item in topItems { if let item = item as? StickerPackItem, item.file.isAnimatedSticker { let signal = Signal { subscriber in - let fetched = fetchedMediaResource(postbox: account.postbox, reference: FileMediaReference.standalone(media: item.file).resourceReference(item.file.resource)).start() + let fetched = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: FileMediaReference.standalone(media: item.file).resourceReference(item.file.resource)).start() let data = account.postbox.mediaBox.resourceData(item.file.resource).start() let fetchedRepresentation = chatMessageAnimatedStickerDatas(postbox: account.postbox, file: item.file, small: false, size: CGSize(width: 160.0, height: 160.0), fetched: true, onlyFullSize: false, synchronousLoad: false).start(next: { next in let hasContent = next._0 != nil || next._1 != nil diff --git a/submodules/TelegramUI/TelegramUI/StickerPackPreviewControllerNode.swift b/submodules/TelegramUI/TelegramUI/StickerPackPreviewControllerNode.swift index 03c62c1ed6..db7082b12e 100644 --- a/submodules/TelegramUI/TelegramUI/StickerPackPreviewControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/StickerPackPreviewControllerNode.swift @@ -371,7 +371,8 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol if self.currentItems.isEmpty && !updatedItems.isEmpty { let entities = generateTextEntities(info.title, enabledTypes: [.mention]) - self.contentTitleNode.attributedText = stringWithAppliedEntities(info.title, entities: entities, baseColor: self.presentationData.theme.actionSheet.primaryTextColor, linkColor: self.presentationData.theme.actionSheet.controlAccentColor, baseFont: Font.medium(20.0), linkFont: Font.medium(20.0), boldFont: Font.medium(20.0), italicFont: Font.medium(20.0), boldItalicFont: Font.medium(20.0), fixedFont: Font.medium(20.0)) + let font = Font.medium(20.0) + self.contentTitleNode.attributedText = stringWithAppliedEntities(info.title, entities: entities, baseColor: self.presentationData.theme.actionSheet.primaryTextColor, linkColor: self.presentationData.theme.actionSheet.controlAccentColor, baseFont: font, linkFont: font, boldFont: font, italicFont: font, boldItalicFont: font, fixedFont: font, blockQuoteFont: font) animateIn = true } transaction = StickerPackPreviewGridTransaction(previousList: self.currentItems, list: updatedItems, account: self.context.account, interaction: self.interaction) diff --git a/submodules/TelegramUI/TelegramUI/StickerResources.swift b/submodules/TelegramUI/TelegramUI/StickerResources.swift index d8a893c765..a498108ecd 100644 --- a/submodules/TelegramUI/TelegramUI/StickerResources.swift +++ b/submodules/TelegramUI/TelegramUI/StickerResources.swift @@ -68,12 +68,12 @@ private func chatMessageStickerDatas(postbox: Postbox, file: TelegramMediaFile, return Signal { subscriber in var fetch: Disposable? if fetched { - fetch = fetchedMediaResource(postbox: postbox, reference: stickerPackFileReference(file).resourceReference(resource)).start() + fetch = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(resource)).start() } var fetchThumbnail: Disposable? if !thumbnailResource.id.isEqual(to: resource.id) { - fetchThumbnail = fetchedMediaResource(postbox: postbox, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start() + fetchThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start() } let disposable = (combineLatest(thumbnailData, fullSizeData) |> map { thumbnailData, fullSizeData -> Tuple3 in @@ -119,12 +119,12 @@ func chatMessageAnimatedStickerDatas(postbox: Postbox, file: TelegramMediaFile, return Signal { subscriber in var fetch: Disposable? if fetched { - fetch = fetchedMediaResource(postbox: postbox, reference: stickerPackFileReference(file).resourceReference(resource)).start() + fetch = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(resource)).start() } var fetchThumbnail: Disposable? if !thumbnailResource.id.isEqual(to: resource.id) { - fetchThumbnail = fetchedMediaResource(postbox: postbox, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start() + fetchThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start() } let disposable = (combineLatest(thumbnailData, fullSizeData) |> map { thumbnailData, fullSizeData -> Tuple3 in @@ -162,7 +162,7 @@ private func chatMessageStickerThumbnailData(postbox: Postbox, file: TelegramMed let thumbnailData = postbox.mediaBox.cachedResourceRepresentation(thumbnailResource, representation: CachedStickerAJpegRepresentation(size: nil), complete: false) return Signal { subscriber in - var fetchThumbnail = fetchedMediaResource(postbox: postbox, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start() + var fetchThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: stickerPackFileReference(file).resourceReference(thumbnailResource)).start() let disposable = (thumbnailData |> map { thumbnailData -> Data? in diff --git a/submodules/TelegramUI/TelegramUI/StringWithAppliedEntities.swift b/submodules/TelegramUI/TelegramUI/StringWithAppliedEntities.swift index fef36803ae..511b6534de 100644 --- a/submodules/TelegramUI/TelegramUI/StringWithAppliedEntities.swift +++ b/submodules/TelegramUI/TelegramUI/StringWithAppliedEntities.swift @@ -45,24 +45,25 @@ func chatInputStateStringWithAppliedEntities(_ text: String, entities: [MessageT return string } -func stringWithAppliedEntities(_ text: String, entities: [MessageTextEntity], baseColor: UIColor, linkColor: UIColor, baseFont: UIFont, linkFont: UIFont, boldFont: UIFont, italicFont: UIFont, boldItalicFont: UIFont, fixedFont: UIFont, underlineLinks: Bool = true, external: Bool = false) -> NSAttributedString { +func stringWithAppliedEntities(_ text: String, entities: [MessageTextEntity], baseColor: UIColor, linkColor: UIColor, baseFont: UIFont, linkFont: UIFont, boldFont: UIFont, italicFont: UIFont, boldItalicFont: UIFont, fixedFont: UIFont, blockQuoteFont: UIFont, underlineLinks: Bool = true, external: Bool = false) -> NSAttributedString { var nsString: NSString? let string = NSMutableAttributedString(string: text, attributes: [NSAttributedStringKey.font: baseFont, NSAttributedStringKey.foregroundColor: baseColor]) var skipEntity = false - let stringLength = string.length var underlineAllLinks = false if linkColor.isEqual(baseColor) { underlineAllLinks = true } var fontAttributes: [NSRange: ChatTextFontAttributes] = [:] + var rangeOffset: Int = 0 for i in 0 ..< entities.count { if skipEntity { skipEntity = false continue } + let stringLength = string.length let entity = entities[i] - var range = NSRange(location: entity.range.lowerBound, length: entity.range.upperBound - entity.range.lowerBound) + var range = NSRange(location: entity.range.lowerBound + rangeOffset, length: entity.range.upperBound - entity.range.lowerBound) if nsString == nil { nsString = text as NSString } @@ -188,6 +189,25 @@ func stringWithAppliedEntities(_ text: String, entities: [MessageTextEntity], ba string.addAttribute(NSAttributedStringKey(rawValue: TelegramTextAttributes.BotCommand), value: nsString!.substring(with: range), range: range) case .Code, .Pre: string.addAttribute(NSAttributedStringKey.font, value: fixedFont, range: range) + case .BlockQuote: + if let fontAttribute = fontAttributes[range] { + fontAttributes[range] = fontAttribute.union(.blockQuote) + } else { + fontAttributes[range] = .blockQuote + } + + let paragraphBreak = "\n" + string.insert(NSAttributedString(string: paragraphBreak), at: range.lowerBound) + + let paragraphRange = NSRange(location: range.lowerBound + paragraphBreak.count, length: range.upperBound - range.lowerBound) + + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.headIndent = 10.0 + paragraphStyle.tabStops = [NSTextTab(textAlignment: .left, location: paragraphStyle.headIndent, options: [:])] + string.addAttribute(NSAttributedStringKey.paragraphStyle, value: paragraphStyle, range: paragraphRange) + + string.insert(NSAttributedString(string: paragraphBreak), at: paragraphRange.upperBound) + rangeOffset += paragraphBreak.count case let .Custom(type): if type == ApplicationSpecificEntityType.Timecode { string.addAttribute(NSAttributedStringKey.foregroundColor, value: linkColor, range: range) @@ -208,7 +228,9 @@ func stringWithAppliedEntities(_ text: String, entities: [MessageTextEntity], ba for (range, fontAttributes) in fontAttributes { var font: UIFont? - if fontAttributes == [.bold, .italic] { + if fontAttributes.contains(.blockQuote) { + font = blockQuoteFont + } else if fontAttributes == [.bold, .italic] { font = boldItalicFont } else if fontAttributes == [.bold] { font = boldFont diff --git a/submodules/TelegramUI/TelegramUI/TermsOfServiceControllerNode.swift b/submodules/TelegramUI/TelegramUI/TermsOfServiceControllerNode.swift index 0d3c59e5fd..674458c03c 100644 --- a/submodules/TelegramUI/TelegramUI/TermsOfServiceControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/TermsOfServiceControllerNode.swift @@ -57,7 +57,7 @@ final class TermsOfServiceControllerNode: ViewControllerTracingNode { self.contentTextNode = ImmediateTextNode() self.contentTextNode.displaysAsynchronously = false self.contentTextNode.maximumNumberOfLines = 0 - self.contentTextNode.attributedText = stringWithAppliedEntities(text, entities: entities, baseColor: theme.primary, linkColor: theme.accent, baseFont: Font.regular(15.0), linkFont: Font.regular(15.0), boldFont: Font.semibold(15.0), italicFont: Font.italic(15.0), boldItalicFont: Font.semiboldItalic(15.0), fixedFont: Font.monospace(15.0)) + self.contentTextNode.attributedText = stringWithAppliedEntities(text, entities: entities, baseColor: theme.primary, linkColor: theme.accent, baseFont: Font.regular(15.0), linkFont: Font.regular(15.0), boldFont: Font.semibold(15.0), italicFont: Font.italic(15.0), boldItalicFont: Font.semiboldItalic(15.0), fixedFont: Font.monospace(15.0), blockQuoteFont: Font.regular(15.0)) self.toolbarNode = ASDisplayNode() self.toolbarSeparatorNode = ASDisplayNode() diff --git a/submodules/TelegramUI/TelegramUI/TextNode.swift b/submodules/TelegramUI/TelegramUI/TextNode.swift index 3a947ac672..de69f8ef66 100644 --- a/submodules/TelegramUI/TelegramUI/TextNode.swift +++ b/submodules/TelegramUI/TelegramUI/TextNode.swift @@ -41,4 +41,5 @@ struct TelegramTextAttributes { static let BotCommand = "TelegramBotCommand" static let Hashtag = "TelegramHashtag" static let Timecode = "TelegramTimecode" + static let BlockQuote = "TelegramBlockQuote" } diff --git a/submodules/TelegramUI/TelegramUI/ThemeAutoNightSettingsController.swift b/submodules/TelegramUI/TelegramUI/ThemeAutoNightSettingsController.swift index 6f15d652f0..b6b753817f 100644 --- a/submodules/TelegramUI/TelegramUI/ThemeAutoNightSettingsController.swift +++ b/submodules/TelegramUI/TelegramUI/ThemeAutoNightSettingsController.swift @@ -235,7 +235,7 @@ private enum ThemeAutoNightSettingsControllerEntry: ItemListNodeEntry { }) case let .themeNight(theme, title, value): return ItemListCheckboxItem(theme: theme, title: title, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: { - arguments.updateTheme(.nightGrayscale) + arguments.updateTheme(.night) }) } } @@ -294,7 +294,7 @@ private func themeAutoNightSettingsControllerEntries(theme: PresentationTheme, s case .timeBased, .brightness: entries.append(.themeHeader(theme, strings.AutoNightTheme_PreferredTheme)) entries.append(.themeNightBlue(theme, strings.Appearance_ThemeNightBlue, switchSetting.theme == .nightAccent)) - entries.append(.themeNight(theme, strings.Appearance_ThemeNight, switchSetting.theme == .nightGrayscale)) + entries.append(.themeNight(theme, strings.Appearance_ThemeNight, switchSetting.theme == .night)) } return entries diff --git a/submodules/TelegramUI/TelegramUI/ThemeGridController.swift b/submodules/TelegramUI/TelegramUI/ThemeGridController.swift index 086a2d988d..ce084deb64 100644 --- a/submodules/TelegramUI/TelegramUI/ThemeGridController.swift +++ b/submodules/TelegramUI/TelegramUI/ThemeGridController.swift @@ -178,7 +178,7 @@ final class ThemeGridController: ViewController { switch theme { case .day: fallbackWallpaper = .color(0xffffff) - case .nightGrayscale: + case .night: fallbackWallpaper = .color(0x000000) case .nightAccent: fallbackWallpaper = .color(0x18222d) @@ -251,7 +251,7 @@ final class ThemeGridController: ViewController { switch theme { case .day: wallpaper = .color(0xffffff) - case .nightGrayscale: + case .night: wallpaper = .color(0x000000) case .nightAccent: wallpaper = .color(0x18222d) diff --git a/submodules/TelegramUI/TelegramUI/ThemePreviewController.swift b/submodules/TelegramUI/TelegramUI/ThemePreviewController.swift index 826e23a125..6ee5c2dad1 100644 --- a/submodules/TelegramUI/TelegramUI/ThemePreviewController.swift +++ b/submodules/TelegramUI/TelegramUI/ThemePreviewController.swift @@ -9,32 +9,45 @@ import TelegramPresentationData import TelegramUIPreferences final class ThemePreviewController: ViewController { + private let context: AccountContext + private let previewTheme: PresentationTheme + private let media: AnyMediaReference + private var controllerNode: ThemePreviewControllerNode { return self.displayNode as! ThemePreviewControllerNode } - private let context: AccountContext - private let previewTheme: PresentationTheme + private var didPlayPresentationAnimation = false private var presentationData: PresentationData private var presentationDataDisposable: Disposable? - init(context: AccountContext, previewTheme: PresentationTheme) { + init(context: AccountContext, previewTheme: PresentationTheme, media: AnyMediaReference) { self.context = context self.previewTheme = previewTheme + self.media = media + self.presentationData = context.sharedContext.currentPresentationData.with { $0 } - super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData)) + super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationTheme: self.previewTheme, presentationStrings: self.presentationData.strings)) - self.title = self.presentationData.strings.WallpaperPreview_Title - self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style + if let author = previewTheme.author { + let titleView = CounterContollerTitleView(theme: self.previewTheme) + titleView.title = CounterContollerTitle(title: previewTheme.name.string, counter: author) + self.navigationItem.titleView = titleView + } else { + self.title = previewTheme.name.string + } + self.statusBar.statusBarStyle = self.previewTheme.rootController.statusBarStyle.style self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) + self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: self.previewTheme.rootController.navigationBar.accentTextColor), style: .plain, target: self, action: #selector(self.actionPressed)) + self.presentationDataDisposable = (context.sharedContext.presentationData |> deliverOnMainQueue).start(next: { [weak self] presentationData in if let strongSelf = self { strongSelf.presentationData = presentationData - strongSelf.updateThemeAndStrings() + strongSelf.updateStrings() } }) } @@ -47,12 +60,23 @@ final class ThemePreviewController: ViewController { self.presentationDataDisposable?.dispose() } + public override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + if let presentationArguments = self.presentationArguments as? ViewControllerPresentationArguments, !self.didPlayPresentationAnimation { + self.didPlayPresentationAnimation = true + if case .modalSheet = presentationArguments.presentationAnimation { + self.controllerNode.animateIn() + } + } + } + override func loadDisplayNode() { super.loadDisplayNode() self.displayNode = ThemePreviewControllerNode(context: self.context, previewTheme: self.previewTheme, dismiss: { [weak self] in if let strongSelf = self { - strongSelf.dismiss(animated: true, completion: {}) + strongSelf.dismiss() } }, apply: { [weak self] in if let strongSelf = self { @@ -67,17 +91,25 @@ final class ThemePreviewController: ViewController { return PresentationThemeSettings(chatWallpaper: .color(0xffffff), theme: .builtin(.day), themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, themeTintColors: current.themeTintColors, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations) }) - }).start() + }).start(completed: { [weak self] in + if let strongSelf = self { + strongSelf.dismiss() + } + }) } }) self.displayNodeDidLoad() - - } - private func updateThemeAndStrings() { - self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style - self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData)) + private func updateStrings() { + + } + + override public func dismiss(completion: (() -> Void)? = nil) { + self.controllerNode.animateOut(completion: { [weak self] in + self?.presentingViewController?.dismiss(animated: false, completion: nil) + completion?() + }) } override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { @@ -86,4 +118,8 @@ final class ThemePreviewController: ViewController { self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition) } + @objc private func actionPressed() { + let controller = ShareController(context: self.context, subject: .media(self.media)) + self.present(controller, in: .window(.root), blockInteraction: true) + } } diff --git a/submodules/TelegramUI/TelegramUI/ThemePreviewControllerNode.swift b/submodules/TelegramUI/TelegramUI/ThemePreviewControllerNode.swift index c0c075499e..7d14aa6eb3 100644 --- a/submodules/TelegramUI/TelegramUI/ThemePreviewControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/ThemePreviewControllerNode.swift @@ -11,6 +11,7 @@ import TelegramUIPreferences class ThemePreviewControllerNode: ASDisplayNode { private let context: AccountContext private let previewTheme: PresentationTheme + private var presentationData: PresentationData private var messageNodes: [ListViewItemNode]? private let toolbarNode: WallpaperGalleryToolbarNode @@ -21,30 +22,43 @@ class ThemePreviewControllerNode: ASDisplayNode { self.context = context self.previewTheme = previewTheme - let presentationData = context.sharedContext.currentPresentationData.with { $0 } + self.presentationData = context.sharedContext.currentPresentationData.with { $0 } - - self.toolbarNode = WallpaperGalleryToolbarNode(theme: presentationData.theme, strings: presentationData.strings) + self.toolbarNode = WallpaperGalleryToolbarNode(theme: self.previewTheme, strings: self.presentationData.strings) super.init() + self.setViewBlock({ + return UITracingLayerView() + }) + + if case let .color(value) = self.previewTheme.chat.defaultWallpaper { + self.backgroundColor = UIColor(rgb: UInt32(bitPattern: value)) + } else { + self.backgroundColor = self.previewTheme.list.plainBackgroundColor + } + self.addSubnode(self.toolbarNode) - self.toolbarNode.cancel = { [weak self] in + self.toolbarNode.cancel = { dismiss() } - self.toolbarNode.done = { [weak self] in + self.toolbarNode.done = { apply() } } - func updatePresentationData(_ presentationData: PresentationData) { - + func animateIn(completion: (() -> Void)? = nil) { + self.layer.animatePosition(from: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), to: self.layer.position, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring) + } + + func animateOut(completion: (() -> Void)? = nil) { + self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), duration: 0.2, timingFunction: kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: false, completion: { _ in + completion?() + }) } func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { - let hadLayout = self.validLayout != nil - transition.updateFrame(node: self.toolbarNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom), size: CGSize(width: layout.size.width, height: 49.0 + layout.intrinsicInsets.bottom))) self.toolbarNode.updateLayout(size: CGSize(width: layout.size.width, height: 49.0), layout: layout, transition: transition) } diff --git a/submodules/TelegramUI/TelegramUI/ThemeSettingsAccentColorItem.swift b/submodules/TelegramUI/TelegramUI/ThemeSettingsAccentColorItem.swift index 2961cb9d3f..8ee8b8fbb1 100644 --- a/submodules/TelegramUI/TelegramUI/ThemeSettingsAccentColorItem.swift +++ b/submodules/TelegramUI/TelegramUI/ThemeSettingsAccentColorItem.swift @@ -13,8 +13,8 @@ private func generateSwatchImage(color: PresentationThemeAccentColor, selected: context.clear(bounds) - let fillColor = UIColor(rgb: UInt32(bitPattern: color.color)) - let strokeColor = UIColor(rgb: UInt32(bitPattern: color.baseColor.colorValue)) + let fillColor = color.color + let strokeColor = color.baseColor.color context.setFillColor(fillColor.cgColor) context.setStrokeColor(strokeColor.cgColor) @@ -41,10 +41,10 @@ class ThemeSettingsAccentColorItem: ListViewItem, ItemListItem { let colors: [PresentationThemeBaseColor] let currentColor: PresentationThemeAccentColor let updated: (PresentationThemeAccentColor) -> Void - let toggleSlider: () -> Void + let toggleSlider: (PresentationThemeBaseColor) -> Void let tag: ItemListItemTag? - init(theme: PresentationTheme, sectionId: ItemListSectionId, colors: [PresentationThemeBaseColor], currentColor: PresentationThemeAccentColor, updated: @escaping (PresentationThemeAccentColor) -> Void, toggleSlider: @escaping () -> Void, tag: ItemListItemTag? = nil) { + init(theme: PresentationTheme, sectionId: ItemListSectionId, colors: [PresentationThemeBaseColor], currentColor: PresentationThemeAccentColor, updated: @escaping (PresentationThemeAccentColor) -> Void, toggleSlider: @escaping (PresentationThemeBaseColor) -> Void, tag: ItemListItemTag? = nil) { self.theme = theme self.colors = colors self.currentColor = currentColor @@ -274,7 +274,7 @@ class ThemeSettingsAccentColorItemNode: ListViewItemNode, ItemListItemNode { } if imageNode == selectedNode { - item.toggleSlider() + item.toggleSlider(accentColor.baseColor) } }) diff --git a/submodules/TelegramUI/TelegramUI/ThemeSettingsController.swift b/submodules/TelegramUI/TelegramUI/ThemeSettingsController.swift index fb3bd72068..3bb9970dfe 100644 --- a/submodules/TelegramUI/TelegramUI/ThemeSettingsController.swift +++ b/submodules/TelegramUI/TelegramUI/ThemeSettingsController.swift @@ -12,21 +12,19 @@ private final class ThemeSettingsControllerArguments { let selectTheme: (PresentationThemeReference) -> Void let selectFontSize: (PresentationFontSize) -> Void let openWallpaperSettings: () -> Void - let openAccentColor: (Int32) -> Void let selectAccentColor: (PresentationThemeAccentColor) -> Void - let toggleColorSlider: () -> Void - let toggleTintAllColors: () -> Void + let toggleColorSlider: (Bool) -> Void + let toggleTintAllColors: (Bool) -> Void let openAutoNightTheme: () -> Void let toggleLargeEmoji: (Bool) -> Void let disableAnimations: (Bool) -> Void let selectAppIcon: (String) -> Void - init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, selectFontSize: @escaping (PresentationFontSize) -> Void, openWallpaperSettings: @escaping () -> Void, openAccentColor: @escaping (Int32) -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor) -> Void, toggleColorSlider: @escaping () -> Void, toggleTintAllColors: @escaping () -> Void, openAutoNightTheme: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (String) -> Void) { + init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, selectFontSize: @escaping (PresentationFontSize) -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor) -> Void, toggleColorSlider: @escaping (Bool) -> Void, toggleTintAllColors: @escaping (Bool) -> Void, openAutoNightTheme: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (String) -> Void) { self.context = context self.selectTheme = selectTheme self.selectFontSize = selectFontSize self.openWallpaperSettings = openWallpaperSettings - self.openAccentColor = openAccentColor self.selectAccentColor = selectAccentColor self.toggleColorSlider = toggleColorSlider self.toggleTintAllColors = toggleTintAllColors @@ -252,15 +250,16 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { if theme.overallDarkAppearance { colors = colors.filter { $0 != .black } } - if case let .builtin(name) = theme.name, name == .nightGrayscale { + if case let .builtin(name) = theme.name, name == .night { + colors = colors.filter { $0 != .gray } } else { colors = colors.filter { $0 != .white } } return ThemeSettingsAccentColorItem(theme: theme, sectionId: self.section, colors: colors, currentColor: color ?? PresentationThemeAccentColor(baseColor: .blue, value: 0.5), updated: { color in arguments.selectAccentColor(color) - }, toggleSlider: { - arguments.toggleColorSlider() + }, toggleSlider: { baseColor in + arguments.toggleColorSlider(baseColor == .white) }, tag: ThemeSettingsEntryTag.accentColor) case let .autoNightTheme(theme, text, value): return ItemListDisclosureItem(theme: theme, icon: nil, title: text, label: value, labelStyle: .text, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { @@ -314,10 +313,10 @@ private func themeSettingsControllerEntries(presentationData: PresentationData, entries.append(.themeListHeader(presentationData.theme, strings.Appearance_ColorTheme.uppercased())) entries.append(.chatPreview(presentationData.theme, theme, wallpaper, fontSize, presentationData.strings, dateTimeFormat, presentationData.nameDisplayOrder)) if case .builtin = themeReference { - entries.append(.themeItem(presentationData.theme, presentationData.strings, [.builtin(.dayClassic), .builtin(.day), .builtin(.nightAccent), .builtin(.nightGrayscale)], themeReference, themeSpecificAccentColors, themeSpecificAccentColors[themeReference.index], displayColorSlider)) + entries.append(.themeItem(presentationData.theme, presentationData.strings, [.builtin(.dayClassic), .builtin(.day), .builtin(.nightAccent), .builtin(.night)], themeReference, themeSpecificAccentColors, themeSpecificAccentColors[themeReference.index], displayColorSlider)) } - if theme.name == .builtin(.nightAccent) || theme.name == .builtin(.nightGrayscale) { - //entries.append(.themeTint(presentationData.theme, strings.Appearance_TintAllColors, false)) + if theme.name == .builtin(.nightAccent) || theme.name == .builtin(.night) { + entries.append(.themeTint(presentationData.theme, strings.Appearance_TintAllColors, false)) } if theme.name != .builtin(.dayClassic) { entries.append(.accentColor(presentationData.theme, strings.Appearance_AccentColor, themeSpecificAccentColors[themeReference.index])) @@ -363,7 +362,6 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The } var pushControllerImpl: ((ViewController) -> Void)? - var presentControllerImpl: ((ViewController) -> Void)? let _ = telegramWallpapers(postbox: context.account.postbox, network: context.account.network).start() @@ -390,45 +388,12 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The } let chatWallpaper: TelegramWallpaper - if let themeSpecificWallpaper = current.themeSpecificChatWallpapers[theme.index] { - if case let .builtin(themeReference) = theme { - switch themeReference { - case .nightAccent: - if let themeSpecificAccentColor = current.themeSpecificAccentColors[theme.index] { - let accentColor = UIColor(rgb: UInt32(bitPattern: themeSpecificAccentColor.color)) - let backgroundColor = accentColor.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18) - chatWallpaper = .color(Int32(bitPattern: backgroundColor.rgb)) - } else { - chatWallpaper = .color(0x18222d) - } - default: - chatWallpaper = themeSpecificWallpaper - } - } else { - chatWallpaper = themeSpecificWallpaper - } + chatWallpaper = themeSpecificWallpaper } else { - if case let .builtin(themeReference) = theme { - switch themeReference { - case .day: - chatWallpaper = .color(0xffffff) - case .dayClassic: - chatWallpaper = .builtin(WallpaperSettings()) - case .nightAccent: - if let themeSpecificAccentColor = current.themeSpecificAccentColors[theme.index] { - let accentColor = UIColor(rgb: UInt32(bitPattern: themeSpecificAccentColor.color)) - let backgroundColor = accentColor.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18) - chatWallpaper = .color(Int32(bitPattern: backgroundColor.rgb)) - } else { - chatWallpaper = .color(0x18222d) - } - case .nightGrayscale: - chatWallpaper = .color(0x000000) - } - } else { - chatWallpaper = .builtin(WallpaperSettings()) - } + let accentColor = current.themeSpecificAccentColors[theme.index]?.color ?? defaultDayAccentColor + let theme = makePresentationTheme(themeReference: current.theme, accentColor: accentColor, serviceBackgroundColor: defaultServiceBackgroundColor) + chatWallpaper = theme.chat.defaultWallpaper } return PresentationThemeSettings(chatWallpaper: chatWallpaper, theme: theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, themeTintColors: current.themeTintColors, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations) @@ -440,63 +405,30 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The }).start() }, openWallpaperSettings: { pushControllerImpl?(ThemeGridController(context: context)) - }, openAccentColor: { color in - presentControllerImpl?(ThemeAccentColorActionSheet(context: context, currentValue: color, applyValue: { color in - let themeAccentColor: PresentationThemeBaseColor - switch color { - case 0xf83b4c: - themeAccentColor = .red - case 0xff7519: - themeAccentColor = .orange - case 0xeba239: - themeAccentColor = .yellow - case 0x29b327: - themeAccentColor = .green - case 0x00c2ed: - themeAccentColor = .cyan - case 0x007ee5: - themeAccentColor = .blue - case 0x7748ff: - themeAccentColor = .purple - case 0xff5da2: - themeAccentColor = .pink - default: - themeAccentColor = .blue - } - - let _ = updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in - var themeSpecificAccentColors = current.themeSpecificAccentColors - themeSpecificAccentColors[current.theme.index] = PresentationThemeAccentColor(baseColor: themeAccentColor, value: 0.5) - - return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, theme: current.theme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, themeTintColors: current.themeTintColors, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations) - }).start() - })) }, selectAccentColor: { color in let _ = updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in var themeSpecificAccentColors = current.themeSpecificAccentColors themeSpecificAccentColors[current.theme.index] = color + var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers + + let theme = makePresentationTheme(themeReference: current.theme, accentColor: color.color, serviceBackgroundColor: defaultServiceBackgroundColor) var chatWallpaper = current.chatWallpaper - if case let .builtin(themeReference) = current.theme { - switch themeReference { - case .nightAccent: - if let themeSpecificAccentColor = themeSpecificAccentColors[current.theme.index] { - let accentColor = UIColor(rgb: UInt32(bitPattern: themeSpecificAccentColor.color)) - let backgroundColor = accentColor.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18) - chatWallpaper = .color(Int32(bitPattern: backgroundColor.rgb)) - } else { - chatWallpaper = .color(0x18222d) - } - default: - break - } + if let wallpaper = current.themeSpecificChatWallpapers[current.theme.index], wallpaper.hasWallpaper { + } else { + chatWallpaper = theme.chat.defaultWallpaper + themeSpecificChatWallpapers[current.theme.index] = chatWallpaper } - return PresentationThemeSettings(chatWallpaper: chatWallpaper, theme: current.theme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, themeTintColors: current.themeTintColors, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations) + if color.baseColor == .white { + updateState { $0.withDisplayColorSlider(false) } + } + + return PresentationThemeSettings(chatWallpaper: chatWallpaper, theme: current.theme, themeSpecificAccentColors: themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, themeTintColors: current.themeTintColors, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations) }).start() - }, toggleColorSlider: { - updateState { $0.withDisplayColorSlider(!$0.displayColorSlider) } - }, toggleTintAllColors: { + }, toggleColorSlider: { forceHidden in + updateState { $0.withDisplayColorSlider(forceHidden ? false : !$0.displayColorSlider) } + }, toggleTintAllColors: { value in }, openAutoNightTheme: { pushControllerImpl?(themeAutoNightSettingsController(context: context)) @@ -504,9 +436,9 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The let _ = updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, theme: current.theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, themeTintColors: current.themeTintColors, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: largeEmoji, disableAnimations: current.disableAnimations) }).start() - }, disableAnimations: { disabled in + }, disableAnimations: { value in let _ = updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in - return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, theme: current.theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, themeTintColors: current.themeTintColors, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: disabled) + return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, theme: current.theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, themeTintColors: current.themeTintColors, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: value) }).start() }, selectAppIcon: { name in currentAppIconName.set(name) @@ -516,40 +448,23 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The let signal = combineLatest(context.sharedContext.presentationData |> deliverOnMainQueue, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings]) |> deliverOnMainQueue, availableAppIcons, currentAppIconName.get() |> deliverOnMainQueue, statePromise.get() |> deliverOnMainQueue) |> map { presentationData, sharedData, availableAppIcons, currentAppIconName, state -> (ItemListControllerState, (ItemListNodeState, ThemeSettingsControllerEntry.ItemGenerationArguments)) in - let theme: PresentationTheme - let fontSize: PresentationFontSize - let wallpaper: TelegramWallpaper - let dateTimeFormat: PresentationDateTimeFormat - let largeEmoji: Bool - let disableAnimations: Bool - let settings = (sharedData.entries[ApplicationSpecificSharedDataKeys.presentationThemeSettings] as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings - switch settings.theme { - case let .builtin(reference): - switch reference { - case .dayClassic: - theme = defaultPresentationTheme - case .nightGrayscale: - theme = makeDarkPresentationTheme(accentColor: settings.themeSpecificAccentColors[settings.theme.index]?.color ?? defaultDayAccentColor) - case .nightAccent: - theme = makeDarkAccentPresentationTheme(accentColor: settings.themeSpecificAccentColors[settings.theme.index]?.color ?? defaultDayAccentColor) - case .day: - theme = makeDefaultDayPresentationTheme(accentColor: settings.themeSpecificAccentColors[settings.theme.index]?.color ?? defaultDayAccentColor, serviceBackgroundColor: defaultServiceBackgroundColor) - } - } + + let fontSize = settings.fontSize + let dateTimeFormat = presentationData.dateTimeFormat + let largeEmoji = settings.largeEmoji + let disableAnimations = settings.disableAnimations + + let accentColor = settings.themeSpecificAccentColors[settings.theme.index]?.color ?? defaultDayAccentColor + let theme = makePresentationTheme(themeReference: settings.theme, accentColor: accentColor, serviceBackgroundColor: defaultServiceBackgroundColor) + let wallpaper: TelegramWallpaper if let themeSpecificWallpaper = settings.themeSpecificChatWallpapers[settings.theme.index] { wallpaper = themeSpecificWallpaper } else { wallpaper = settings.chatWallpaper } - fontSize = settings.fontSize - - dateTimeFormat = presentationData.dateTimeFormat - largeEmoji = settings.largeEmoji - disableAnimations = settings.disableAnimations - let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Appearance_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) let listState = ItemListNodeState(entries: themeSettingsControllerEntries(presentationData: presentationData, theme: theme, themeReference: settings.theme, themeSpecificAccentColors: settings.themeSpecificAccentColors, autoNightSettings: settings.automaticThemeSwitchSetting, strings: presentationData.strings, wallpaper: wallpaper, fontSize: fontSize, dateTimeFormat: dateTimeFormat, largeEmoji: largeEmoji, disableAnimations: disableAnimations, availableAppIcons: availableAppIcons, currentAppIconName: currentAppIconName, displayColorSlider: state.displayColorSlider), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false) @@ -560,9 +475,6 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The pushControllerImpl = { [weak controller] c in (controller?.navigationController as? NavigationController)?.pushViewController(c) } - presentControllerImpl = { [weak controller] c in - controller?.present(c, in: .window(.root)) - } return controller } diff --git a/submodules/TelegramUI/TelegramUI/ThemeSettingsThemeItem.swift b/submodules/TelegramUI/TelegramUI/ThemeSettingsThemeItem.swift index 5f5ef8a77d..8e692ee042 100644 --- a/submodules/TelegramUI/TelegramUI/ThemeSettingsThemeItem.swift +++ b/submodules/TelegramUI/TelegramUI/ThemeSettingsThemeItem.swift @@ -37,7 +37,7 @@ private func generateBorderImage(theme: PresentationTheme, bordered: Bool, selec })?.stretchableImage(withLeftCapWidth: 15, topCapHeight: 15) } -private func generateThemeIconImage(theme: PresentationThemeReference, accentColor: Int32?) -> UIImage { +private func generateThemeIconImage(theme: PresentationThemeReference, accentColor: UIColor?) -> UIImage { return generateImage(CGSize(width: 98.0, height: 62.0), rotatedContext: { size, context in guard case let .builtin(theme) = theme else { return @@ -45,48 +45,35 @@ private func generateThemeIconImage(theme: PresentationThemeReference, accentCol let bounds = CGRect(origin: CGPoint(), size: size) let background: UIColor - let incomingBubble: UIColor - let outgoingBubble: UIColor + let incomingFill: UIColor + var incomingStrokeColor: UIColor? + let outgoingFill: UIColor switch theme { case .dayClassic: background = UIColor(rgb: 0xd6e2ee) - incomingBubble = UIColor(rgb: 0xffffff) - outgoingBubble = UIColor(rgb: 0xe1ffc7) + incomingFill = UIColor(rgb: 0xffffff) + incomingStrokeColor = UIColor(rgb: 0xc9d6e2) + outgoingFill = UIColor(rgb: 0xe1ffc7) case .day: background = .white - incomingBubble = UIColor(rgb: 0xd5dde6) - if let accentColor = accentColor { - outgoingBubble = UIColor(rgb: UInt32(bitPattern: accentColor)) - } else { - outgoingBubble = UIColor(rgb: 0x007aff) - } - case .nightGrayscale: + incomingFill = UIColor(rgb: 0xd5dde6) + outgoingFill = accentColor ?? UIColor(rgb: 0x007aff) + case .night: background = UIColor(rgb: 0x000000) - incomingBubble = UIColor(rgb: 0x1f1f1f) - if let accentColorValue = accentColor { - let accentColor = UIColor(rgb: UInt32(bitPattern: accentColorValue)) - outgoingBubble = accentColor - } else { - outgoingBubble = UIColor(rgb: 0x313131) - } + incomingFill = UIColor(rgb: 0x1f1f1f) + outgoingFill = accentColor ?? UIColor(rgb: 0x007aff) case .nightAccent: - if let accentColorValue = accentColor { - let accentColor = UIColor(rgb: UInt32(bitPattern: accentColorValue)) - background = accentColor.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18) - incomingBubble = accentColor.withMultiplied(hue: 1.024, saturation: 0.585, brightness: 0.25) - outgoingBubble = accentColor.withMultiplied(hue: 1.019, saturation: 0.731, brightness: 0.59) - } else { - background = UIColor(rgb: 0x18222d) - incomingBubble = UIColor(rgb: 0x32475e) - outgoingBubble = UIColor(rgb: 0x3d6a97) - } + let accentColor = accentColor ?? UIColor(rgb: 0x007aff) + background = accentColor.withMultiplied(hue: 1.024, saturation: 0.573, brightness: 0.18) + incomingFill = accentColor.withMultiplied(hue: 1.024, saturation: 0.585, brightness: 0.25) + outgoingFill = accentColor.withMultiplied(hue: 1.019, saturation: 0.731, brightness: 0.59) } context.setFillColor(background.cgColor) context.fill(bounds) - let incoming = generateTintedImage(image: UIImage(bundleImageName: "Settings/ThemeBubble"), color: incomingBubble) - let outgoing = generateTintedImage(image: UIImage(bundleImageName: "Settings/ThemeBubble"), color: outgoingBubble) + let incoming = generateTintedImage(image: UIImage(bundleImageName: "Settings/ThemeBubble"), color: incomingFill) + let outgoing = generateTintedImage(image: UIImage(bundleImageName: "Settings/ThemeBubble"), color: outgoingFill) context.translateBy(x: bounds.width / 2.0, y: bounds.height / 2.0) context.scaleBy(x: 1.0, y: -1.0) @@ -373,7 +360,7 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode { name = item.strings.Appearance_ThemeCarouselClassic case .day: name = item.strings.Appearance_ThemeCarouselDay - case .nightGrayscale: + case .night: name = "Night" //item.strings.Appearance_ThemeCarouselNight case .nightAccent: name = "Tinted Night" //item.strings.Appearance_ThemeCarouselNightBlue @@ -416,8 +403,8 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode { } let previousBaseColor = strongSelf.colorSlider.baseColor - let newBaseColor = UIColor(rgb: UInt32(bitPattern: item.currentColor?.baseColor.colorValue ?? 0)) - strongSelf.colorSlider.baseColor = newBaseColor + let newBaseColor = item.currentColor?.baseColor.color + strongSelf.colorSlider.baseColor = newBaseColor ?? .black if previousBaseColor != newBaseColor { strongSelf.colorSlider.value = item.currentColor?.value ?? 0.5 } diff --git a/submodules/TelegramUI/TelegramUI/TransformOutgoingMessageMedia.swift b/submodules/TelegramUI/TelegramUI/TransformOutgoingMessageMedia.swift index f132e68494..9322cca278 100644 --- a/submodules/TelegramUI/TelegramUI/TransformOutgoingMessageMedia.swift +++ b/submodules/TelegramUI/TelegramUI/TransformOutgoingMessageMedia.swift @@ -9,7 +9,7 @@ public func transformOutgoingMessageMedia(postbox: Postbox, network: Network, me switch media.media { case let file as TelegramMediaFile: let signal = Signal { subscriber in - let fetch = fetchedMediaResource(postbox: postbox, reference: media.resourceReference(file.resource)).start() + let fetch = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: media.resourceReference(file.resource)).start() let data = postbox.mediaBox.resourceData(file.resource, option: .complete(waitUntilFetchStatus: true)).start(next: { next in subscriber.putNext(next) if next.complete { @@ -125,7 +125,7 @@ public func transformOutgoingMessageMedia(postbox: Postbox, network: Network, me case let image as TelegramMediaImage: if let representation = largestImageRepresentation(image.representations) { let signal = Signal { subscriber in - let fetch = fetchedMediaResource(postbox: postbox, reference: media.resourceReference(representation.resource)).start() + let fetch = fetchedMediaResource(mediaBox: postbox.mediaBox, reference: media.resourceReference(representation.resource)).start() let data = postbox.mediaBox.resourceData(representation.resource, option: .complete(waitUntilFetchStatus: true)).start(next: { next in subscriber.putNext(next) if next.complete { diff --git a/submodules/TelegramUI/TelegramUI/UniversalVideoGalleryItem.swift b/submodules/TelegramUI/TelegramUI/UniversalVideoGalleryItem.swift index 62820724c3..c2b1b21df1 100644 --- a/submodules/TelegramUI/TelegramUI/UniversalVideoGalleryItem.swift +++ b/submodules/TelegramUI/TelegramUI/UniversalVideoGalleryItem.swift @@ -154,6 +154,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { private let footerContentNode: ChatItemGalleryFooterContentNode private var videoNode: UniversalVideoNode? + private var videoFramePreview: MediaPlayerFramePreview? private var pictureInPictureNode: UniversalVideoGalleryItemPictureInPictureNode? private let statusButtonNode: HighlightableButtonNode private let statusNode: RadialStatusNode @@ -178,6 +179,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { private var fetchStatus: MediaResourceStatus? private var fetchControls: FetchControls? + private var scrubbingFrame = Promise(nil) + private var scrubbingFrames = false + private var scrubbingFrameDisposable: Disposable? + var playbackCompleted: (() -> Void)? init(context: AccountContext, presentationData: PresentationData, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void) { @@ -203,6 +208,24 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { self?.videoNode?.seek(timecode) } + self.scrubberView.updateScrubbing = { [weak self] timecode in + guard let strongSelf = self, let videoFramePreview = strongSelf.videoFramePreview else { + return + } + if let timecode = timecode { + if !strongSelf.scrubbingFrames { + strongSelf.scrubbingFrames = true + strongSelf.scrubbingFrame.set(videoFramePreview.generatedFrames + |> map(Optional.init)) + } + videoFramePreview.generateFrame(at: timecode) + } else { + strongSelf.scrubbingFrame.set(.single(nil)) + videoFramePreview.cancelPendingFrames() + strongSelf.scrubbingFrames = false + } + } + self.statusButtonNode.addSubnode(self.statusNode) self.statusButtonNode.addTarget(self, action: #selector(statusButtonPressed), forControlEvents: .touchUpInside) @@ -255,10 +278,28 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { break } } + + self.scrubbingFrameDisposable = (self.scrubbingFrame.get() + |> deliverOnMainQueue).start(next: { [weak self] result in + guard let strongSelf = self else { + return + } + if let result = result { + switch result { + case .waitingForData: + strongSelf.footerContentNode.setFramePreviewImageIsLoading() + case let .image(image): + strongSelf.footerContentNode.setFramePreviewImage(image: image) + } + } else { + strongSelf.footerContentNode.setFramePreviewImage(image: nil) + } + }) } deinit { self.statusDisposable.dispose() + self.scrubbingFrameDisposable?.dispose() } override func ready() -> Signal { @@ -304,6 +345,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { var isAnimated = false if let content = item.content as? NativeVideoContent { isAnimated = content.fileReference.media.isAnimated + self.videoFramePreview = MediaPlayerFramePreview(postbox: item.context.account.postbox, fileReference: content.fileReference) } else if let _ = item.content as? SystemVideoContent { self._title.set(.single(item.presentationData.strings.Message_Video)) } else if let content = item.content as? WebEmbedVideoContent, case .iframe = webEmbedType(content: content.webpageContent) { diff --git a/submodules/TelegramUI/TelegramUI/UpdateInfoItem.swift b/submodules/TelegramUI/TelegramUI/UpdateInfoItem.swift index e5cf15cb24..aaab7a0921 100644 --- a/submodules/TelegramUI/TelegramUI/UpdateInfoItem.swift +++ b/submodules/TelegramUI/TelegramUI/UpdateInfoItem.swift @@ -208,7 +208,7 @@ class UpdateInfoItemNode: ListViewItemNode { let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: textColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 88.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) - let string = stringWithAppliedEntities(item.text, entities: item.entities, baseColor: textColor, linkColor: item.theme.list.itemAccentColor, baseFont: textFont, linkFont: textFont, boldFont: textBoldFont, italicFont: textItalicFont, boldItalicFont: textBoldItalicFont, fixedFont: textFixedFont) + let string = stringWithAppliedEntities(item.text, entities: item.entities, baseColor: textColor, linkColor: item.theme.list.itemAccentColor, baseFont: textFont, linkFont: textFont, boldFont: textBoldFont, italicFont: textItalicFont, boldItalicFont: textBoldItalicFont, fixedFont: textFixedFont, blockQuoteFont: textFont) let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: string, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 28.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let contentSize: CGSize diff --git a/submodules/TelegramUI/TelegramUI/WallpaperGalleryItem.swift b/submodules/TelegramUI/TelegramUI/WallpaperGalleryItem.swift index 2500879f77..487551af6b 100644 --- a/submodules/TelegramUI/TelegramUI/WallpaperGalleryItem.swift +++ b/submodules/TelegramUI/TelegramUI/WallpaperGalleryItem.swift @@ -281,7 +281,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { } signal = wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: fileReference, representations: convertedRepresentations, alwaysShowThumbnailFirst: true, autoFetchFullSize: false) } - fetchSignal = fetchedMediaResource(postbox: context.account.postbox, reference: convertedRepresentations[convertedRepresentations.count - 1].reference) + fetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: convertedRepresentations[convertedRepresentations.count - 1].reference) let account = context.account statusSignal = context.sharedContext.accountManager.mediaBox.resourceStatus(file.file.resource) |> take(1) @@ -307,7 +307,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { signal = wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: convertedRepresentations, alwaysShowThumbnailFirst: true, autoFetchFullSize: false) if let largestIndex = convertedRepresentations.index(where: { $0.representation == largestSize }) { - fetchSignal = fetchedMediaResource(postbox: context.account.postbox, reference: convertedRepresentations[largestIndex].reference) + fetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: convertedRepresentations[largestIndex].reference) } else { fetchSignal = .complete() } @@ -402,7 +402,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode { let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil) signal = chatMessagePhoto(postbox: context.account.postbox, photoReference: .standalone(media: tmpImage)) - fetchSignal = fetchedMediaResource(postbox: context.account.postbox, reference: .media(media: .standalone(media: tmpImage), resource: imageResource)) + fetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .media(media: .standalone(media: tmpImage), resource: imageResource)) statusSignal = context.account.postbox.mediaBox.resourceStatus(imageResource) } else { displaySize = CGSize(width: 1.0, height: 1.0) diff --git a/submodules/TelegramUI/TelegramUI/WallpaperResources.swift b/submodules/TelegramUI/TelegramUI/WallpaperResources.swift index 055e8fce06..678d6e03b6 100644 --- a/submodules/TelegramUI/TelegramUI/WallpaperResources.swift +++ b/submodules/TelegramUI/TelegramUI/WallpaperResources.swift @@ -73,10 +73,10 @@ private func wallpaperDatas(account: Account, accountManager: AccountManager, fi if let _ = decodedThumbnailData { fetchedThumbnail = .complete() } else { - fetchedThumbnail = fetchedMediaResource(postbox: account.postbox, reference: representations[smallestIndex].reference) + fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: representations[smallestIndex].reference) } - let fetchedFullSize = fetchedMediaResource(postbox: account.postbox, reference: representations[largestIndex].reference) + let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: representations[largestIndex].reference) let thumbnailData: Signal if let decodedThumbnailData = decodedThumbnailData { @@ -303,8 +303,8 @@ private func patternWallpaperDatas(account: Account, accountManager: AccountMana let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: []) return .single((nil, loadedData, true)) } else { - let fetchedThumbnail = fetchedMediaResource(postbox: account.postbox, reference: representations[smallestIndex].reference) - let fetchedFullSize = fetchedMediaResource(postbox: account.postbox, reference: representations[largestIndex].reference) + let fetchedThumbnail = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: representations[smallestIndex].reference) + let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: representations[largestIndex].reference) let thumbnailData = Signal { subscriber in let fetchedDisposable = fetchedThumbnail.start() diff --git a/submodules/TelegramUI/TelegramUI_Xcode.xcodeproj/project.pbxproj b/submodules/TelegramUI/TelegramUI_Xcode.xcodeproj/project.pbxproj index c656a187ad..c67e427bbd 100644 --- a/submodules/TelegramUI/TelegramUI_Xcode.xcodeproj/project.pbxproj +++ b/submodules/TelegramUI/TelegramUI_Xcode.xcodeproj/project.pbxproj @@ -1012,7 +1012,6 @@ D0EC6DC11EB9F58900EBF1C3 /* ChatMediaInputTrendingItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0575AEE1E9FF881006F2541 /* ChatMediaInputTrendingItem.swift */; }; D0EC6DC21EB9F58900EBF1C3 /* ChatMediaInputStickerPackItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0E41DB55D0A00C6B04F /* ChatMediaInputStickerPackItem.swift */; }; D0EC6DC31EB9F58900EBF1C3 /* ChatMediaInputStickerGridItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C36821DB66AD40064C744 /* ChatMediaInputStickerGridItem.swift */; }; - D0EC6DC51EB9F58900EBF1C3 /* SoftwareVideoSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D002A0D01E9B99F500A81812 /* SoftwareVideoSource.swift */; }; D0EC6DC61EB9F58900EBF1C3 /* MultiplexedSoftwareVideoSourceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D002A0D21E9BBE6700A81812 /* MultiplexedSoftwareVideoSourceManager.swift */; }; D0EC6DC71EB9F58900EBF1C3 /* SampleBufferPool.swift in Sources */ = {isa = PBXBuildFile; fileRef = D002A0D41E9BD48400A81812 /* SampleBufferPool.swift */; }; D0EC6DC81EB9F58900EBF1C3 /* MultiplexedVideoNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D002A0D61E9BD92100A81812 /* MultiplexedVideoNode.swift */; }; @@ -1429,7 +1428,6 @@ 9F06830A21A404C4001D8EDB /* NotificationExceptionSettingsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationExceptionSettingsController.swift; sourceTree = ""; }; D000CAB921EE130D0011B15D /* MapResourceToAvatarSizes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapResourceToAvatarSizes.swift; sourceTree = ""; }; D000CABB21F158AD0011B15D /* PrepareSecretThumbnailData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrepareSecretThumbnailData.swift; sourceTree = ""; }; - D002A0D01E9B99F500A81812 /* SoftwareVideoSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SoftwareVideoSource.swift; sourceTree = ""; }; D002A0D21E9BBE6700A81812 /* MultiplexedSoftwareVideoSourceManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiplexedSoftwareVideoSourceManager.swift; sourceTree = ""; }; D002A0D41E9BD48400A81812 /* SampleBufferPool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SampleBufferPool.swift; sourceTree = ""; }; D002A0D61E9BD92100A81812 /* MultiplexedVideoNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiplexedVideoNode.swift; sourceTree = ""; }; @@ -3079,7 +3077,6 @@ D01C06B41FBB7720001561AB /* ChatMediaInputSettingsItem.swift */, D021E0E41DB55D0A00C6B04F /* ChatMediaInputStickerPackItem.swift */, D08C36821DB66AD40064C744 /* ChatMediaInputStickerGridItem.swift */, - D002A0D01E9B99F500A81812 /* SoftwareVideoSource.swift */, D002A0D21E9BBE6700A81812 /* MultiplexedSoftwareVideoSourceManager.swift */, D002A0D41E9BD48400A81812 /* SampleBufferPool.swift */, D002A0D61E9BD92100A81812 /* MultiplexedVideoNode.swift */, @@ -5949,7 +5946,6 @@ D0E9BAE81F0574FF00F079A4 /* STPCustomer.m in Sources */, D0C0B59F1EE082F5000F4D2C /* ChatSearchInputPanelNode.swift in Sources */, D079FCD91F05A5550038FADE /* BotCheckoutPasswordEntryController.swift in Sources */, - D0EC6DC51EB9F58900EBF1C3 /* SoftwareVideoSource.swift in Sources */, 0962E66121B3512500245FD9 /* WebSearchController.swift in Sources */, D0EC6DC61EB9F58900EBF1C3 /* MultiplexedSoftwareVideoSourceManager.swift in Sources */, D0EC6DC71EB9F58900EBF1C3 /* SampleBufferPool.swift in Sources */, diff --git a/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift b/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift index 67e583bf2a..7b90851be5 100644 --- a/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift @@ -6,7 +6,7 @@ import Display public enum PresentationBuiltinThemeReference: Int32 { case dayClassic = 0 - case nightGrayscale = 1 + case night = 1 case day = 2 case nightAccent = 3 } @@ -178,54 +178,33 @@ public enum PresentationThemeBaseColor: Int32, CaseIterable { case black case white - public var colorValue: Int32 { + public var color: UIColor { + let value: UInt32 switch self { case .blue: - return 0x007ee5 + value = 0x007aff case .cyan: - return 0x00c2ed + value = 0x00c2ed case .green: - return 0x29b327 + value = 0x29b327 case .pink: - return 0xff5da2 + value = 0xeb6ca4 case .orange: - return 0xff7519 + value = 0xf08200 case .purple: - return 0x7748ff + value = 0x9472ee case .red: - return 0xf83b4c + value = 0xd33213 case .yellow: - return 0xeba239 + value = 0xedb400 case .gray: - return 0x6d839e + value = 0x6d839e case .black: - return 0x000000 + value = 0x000000 case .white: - return 0xffffff + value = 0xffffff } - -// switch self { -// case .blue: -// return 0x007aff -// case .cyan: -// return 0x00c2ed -// case .green: -// return 0x70bb23 -// case .pink: -// return 0xeb6ca4 -// case .orange: -// return 0xf08200 -// case .purple: -// return 0x9472ee -// case .red: -// return 0xd33213 -// case .yellow: -// return 0xedb400 -// case .gray: -// return 0x6d839e -// case .black: -// return 0x000000 -// } + return UIColor(rgb: value) } } @@ -248,18 +227,17 @@ public struct PresentationThemeAccentColor: PostboxCoding, Equatable { encoder.encodeDouble(Double(self.value), forKey: "v") } - public var color: Int32 { + public var color: UIColor { var hue: CGFloat = 0.0 var saturation: CGFloat = 0.0 var value: CGFloat = 0.0 - let color = UIColor(rgb: UInt32(bitPattern: self.baseColor.colorValue)) + let color = self.baseColor.color let delta = (-0.5 + self.value) * 0.8 if color.getHue(&hue, saturation: &saturation, brightness: &value, alpha: nil) { - let newColor = UIColor(hue: hue, saturation: saturation, brightness: min(1.0, max(0.0, value + delta)), alpha: 1.0) - return Int32(bitPattern: newColor.rgb) + return UIColor(hue: hue, saturation: saturation, brightness: min(1.0, max(0.0, value + delta)), alpha: 1.0) } else { - return self.baseColor.colorValue + return color } } } diff --git a/submodules/ffmpeg/FFMpeg/FFMpegAVFrame.h b/submodules/ffmpeg/FFMpeg/FFMpegAVFrame.h index b5960710b5..e1145e3cba 100644 --- a/submodules/ffmpeg/FFMpeg/FFMpegAVFrame.h +++ b/submodules/ffmpeg/FFMpeg/FFMpegAVFrame.h @@ -2,6 +2,11 @@ NS_ASSUME_NONNULL_BEGIN +typedef NS_ENUM(NSUInteger, FFMpegAVFrameColorRange) { + FFMpegAVFrameColorRangeRestricted, + FFMpegAVFrameColorRangeFull +}; + @interface FFMpegAVFrame : NSObject @property (nonatomic, readonly) int32_t width; @@ -9,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) uint8_t **data; @property (nonatomic, readonly) int *lineSize; @property (nonatomic, readonly) int64_t pts; +@property (nonatomic, readonly) FFMpegAVFrameColorRange colorRange; - (instancetype)init; diff --git a/submodules/ffmpeg/FFMpeg/FFMpegAVFrame.m b/submodules/ffmpeg/FFMpeg/FFMpegAVFrame.m index 9bd1ec8a10..fd1fcb203a 100644 --- a/submodules/ffmpeg/FFMpeg/FFMpegAVFrame.m +++ b/submodules/ffmpeg/FFMpeg/FFMpegAVFrame.m @@ -44,6 +44,16 @@ return _impl->pts; } +- (FFMpegAVFrameColorRange)colorRange { + switch (_impl->color_range) { + case AVCOL_RANGE_MPEG: + case AVCOL_RANGE_UNSPECIFIED: + return FFMpegAVFrameColorRangeRestricted; + default: + return FFMpegAVFrameColorRangeFull; + } +} + - (void *)impl { return _impl; } diff --git a/submodules/ffmpeg/FFMpeg/FFMpegAVIOContext.m b/submodules/ffmpeg/FFMpeg/FFMpegAVIOContext.m index 5704c84051..2bce9764d1 100644 --- a/submodules/ffmpeg/FFMpeg/FFMpegAVIOContext.m +++ b/submodules/ffmpeg/FFMpeg/FFMpegAVIOContext.m @@ -15,6 +15,7 @@ if (self != nil) { void *avIoBuffer = av_malloc(bufferSize); _impl = avio_alloc_context(avIoBuffer, bufferSize, 0, opaqueContext, readPacket, nil, seek); + _impl->direct = 1; if (_impl == nil) { av_free(avIoBuffer); return nil; diff --git a/submodules/ffmpeg/FFMpeg/build-ffmpeg.sh b/submodules/ffmpeg/FFMpeg/build-ffmpeg.sh index 5f962d8080..e7c155dc02 100755 --- a/submodules/ffmpeg/FFMpeg/build-ffmpeg.sh +++ b/submodules/ffmpeg/FFMpeg/build-ffmpeg.sh @@ -48,7 +48,6 @@ set -e CONFIGURE_FLAGS="--enable-cross-compile --disable-programs \ --disable-armv5te --disable-armv6 --disable-armv6t2 \ --disable-doc --enable-pic --disable-all --disable-everything \ - --disable-videotoolbox \ --enable-avcodec \ --enable-swresample \ --enable-avformat \ @@ -56,13 +55,16 @@ CONFIGURE_FLAGS="--enable-cross-compile --disable-programs \ --enable-libopus \ --enable-audiotoolbox \ --enable-bsf=aac_adtstoasc \ - --enable-decoder=h264,libopus,mp3_at,aac_at,flac,alac_at,pcm_s16le,pcm_s24le,gsm_ms_at \ + --enable-decoder=h264,hevc,libopus,mp3_at,aac_at,flac,alac_at,pcm_s16le,pcm_s24le,gsm_ms_at \ --enable-demuxer=aac,mov,m4v,mp3,ogg,libopus,flac,wav,aiff,matroska \ --enable-parser=aac,h264,mp3,libopus \ --enable-protocol=file \ --enable-muxer=mp4 \ " + +#--enable-hwaccel=h264_videotoolbox,hevc_videotoolbox \ + if [ "$1" = "debug" ]; then CONFIGURE_FLAGS="$CONFIGURE_FLAGS --disable-optimizations --disable-stripping" diff --git a/submodules/ffmpeg/FFMpeg_Xcode.xcodeproj/project.pbxproj b/submodules/ffmpeg/FFMpeg_Xcode.xcodeproj/project.pbxproj index 0a669cd68f..8962e29030 100644 --- a/submodules/ffmpeg/FFMpeg_Xcode.xcodeproj/project.pbxproj +++ b/submodules/ffmpeg/FFMpeg_Xcode.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ D04555D721BF8B2F007A6DD9 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D04555D621BF8B2F007A6DD9 /* AudioToolbox.framework */; }; D04555D921BF8B4E007A6DD9 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D04555D821BF8B4E007A6DD9 /* libiconv.tbd */; }; D04555DB21BF8B77007A6DD9 /* libopus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D04555DA21BF8B77007A6DD9 /* libopus.a */; }; + D0E8B10E22D8E97B00C82570 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0E8B10D22D8E97B00C82570 /* VideoToolbox.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -71,6 +72,7 @@ D04555D821BF8B4E007A6DD9 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; }; D04555DA21BF8B77007A6DD9 /* libopus.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libopus.a; path = opus/lib/libopus.a; sourceTree = ""; }; D0CAD6A621C049D9001E3055 /* ffmpeg-4.1 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "ffmpeg-4.1"; sourceTree = ""; }; + D0E8B10D22D8E97B00C82570 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -78,6 +80,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D0E8B10E22D8E97B00C82570 /* VideoToolbox.framework in Frameworks */, D000CABF21F76B1B0011B15D /* libbz2.tbd in Frameworks */, D04555DB21BF8B77007A6DD9 /* libopus.a in Frameworks */, D04555D921BF8B4E007A6DD9 /* libiconv.tbd in Frameworks */, @@ -142,6 +145,7 @@ D04554C921BF1119007A6DD9 /* Frameworks */ = { isa = PBXGroup; children = ( + D0E8B10D22D8E97B00C82570 /* VideoToolbox.framework */, D000CABE21F76B1B0011B15D /* libbz2.tbd */, D04555DA21BF8B77007A6DD9 /* libopus.a */, D04555D821BF8B4E007A6DD9 /* libiconv.tbd */,