Merge branch 'master' into experiments/string-generation

This commit is contained in:
Ali 2021-07-18 02:18:59 +02:00
commit bbd096d88b
1840 changed files with 233489 additions and 30677 deletions

View File

@ -48,9 +48,11 @@ jobs:
cd $SOURCE_DIR
BUILD_NUMBER_OFFSET="$(cat build_number_offset)"
export APP_VERSION=$(cat versions.json | python3 -c 'import json,sys;obj=json.load(sys.stdin);print(obj["app"]);')
export COMMIT_COUNT=$(git rev-list --count HEAD)
export COMMIT_COUNT="$(($COMMIT_COUNT+2000))"
export COMMIT_COUNT="$(($COMMIT_COUNT+$BUILD_NUMBER_OFFSET))"
export BUILD_NUMBER="$COMMIT_COUNT"
echo "BUILD_NUMBER=$(echo $BUILD_NUMBER)" >> $GITHUB_ENV
echo "APP_VERSION=$(echo $APP_VERSION)" >> $GITHUB_ENV

View File

@ -70,6 +70,7 @@ beta_testflight:
stage: build
only:
- beta
- hotfix
except:
- tags
script:
@ -87,6 +88,7 @@ deploy_beta_testflight:
stage: deploy
only:
- beta
- hotfix
except:
- tags
script:
@ -100,6 +102,7 @@ verifysanity_beta_testflight:
stage: verifysanity
only:
- beta
- hotfix
except:
- tags
script:
@ -118,6 +121,7 @@ verify_beta_testflight:
stage: verify
only:
- beta
- hotfix
except:
- tags
script:

View File

@ -1 +1 @@
E65Wt9QZyVD8tvGhCJD3My6x57eDORYaiYh6HR7T3fK=
4f0d2d13a70664d3029d9b97935089df0426fe53745965d175408752838b80dd

View File

@ -277,6 +277,9 @@ official_apple_pay_merchants = [
"merchant.sberbank.test.ph.telegra.Telegraph",
"merchant.privatbank.test.telergramios",
"merchant.privatbank.prod.telergram",
"merchant.paymaster.test.telegramios",
"merchant.smartglocal.prod.telegramios",
"merchant.smartglocal.test.telegramios",
]
official_bundle_ids = [
@ -1430,6 +1433,96 @@ ios_extension(
],
)
plist_fragment(
name = "BroadcastUploadInfoPlist",
extension = "plist",
template =
"""
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleIdentifier</key>
<string>{telegram_bundle_id}.BroadcastUpload</string>
<key>CFBundleName</key>
<string>Telegram</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.broadcast-services-upload</string>
<key>NSExtensionPrincipalClass</key>
<string>BroadcastUploadSampleHandler</string>
<key>RPBroadcastProcessMode</key>
<string>RPBroadcastProcessModeSampleBuffer</string>
</dict>
""".format(
telegram_bundle_id = telegram_bundle_id,
)
)
swift_library(
name = "BroadcastUploadExtensionLib",
module_name = "BroadcastUploadExtensionLib",
srcs = glob([
"BroadcastUpload/**/*.swift",
]),
deps = [
"//submodules/TelegramUI:TelegramUI",
"//submodules/TelegramVoip:TelegramVoip",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/BuildConfig:BuildConfig",
"//submodules/WidgetItems:WidgetItems",
"//submodules/BroadcastUploadHelpers:BroadcastUploadHelpers",
],
)
genrule(
name = "SetMinOsVersionBroadcastUploadExtension",
cmd_bash =
"""
name=BroadcastUploadExtension.appex
cat $(location PatchMinOSVersion.source.sh) | sed -e "s/<<<MIN_OS_VERSION>>>/11\\.0/g" | sed -e "s/<<<NAME>>>/$$name/g" > $(location SetMinOsVersionBroadcastUploadExtension.sh)
""",
srcs = [
"PatchMinOSVersion.source.sh",
],
outs = [
"SetMinOsVersionBroadcastUploadExtension.sh",
],
executable = True,
visibility = [
"//visibility:public",
]
)
ios_extension(
name = "BroadcastUploadExtension",
bundle_id = "{telegram_bundle_id}.BroadcastUpload".format(
telegram_bundle_id = telegram_bundle_id,
),
families = [
"iphone",
"ipad",
],
infoplists = [
":BroadcastUploadInfoPlist",
":VersionInfoPlist",
":BuildNumberInfoPlist",
":AppNameInfoPlist",
],
minimum_os_version = "9.0", # maintain the same minimum OS version across extensions
ipa_post_processor = ":SetMinOsVersionBroadcastUploadExtension",
provisioning_profile = select({
":disableProvisioningProfilesSetting": None,
"//conditions:default": "@build_configuration//provisioning:BroadcastUpload.mobileprovision",
}),
deps = [":BroadcastUploadExtensionLib"],
frameworks = [
":TelegramUIFramework",
":SwiftSignalKitFramework",
],
)
plist_fragment(
name = "NotificationServiceInfoPlist",
extension = "plist",
@ -1718,6 +1811,7 @@ ios_application(
":NotificationServiceExtension",
":IntentsExtension",
":WidgetExtension",
":BroadcastUploadExtension",
],
}),
watch_application = select({
@ -1729,3 +1823,51 @@ ios_application(
":Lib",
],
)
# Temporary targets used to simplify webrtc build tests
ios_application(
name = "webrtc_build_test",
bundle_id = "{telegram_bundle_id}".format(
telegram_bundle_id = telegram_bundle_id,
),
families = ["iphone", "ipad"],
minimum_os_version = "9.0",
provisioning_profile = select({
":disableProvisioningProfilesSetting": None,
"//conditions:default": "@build_configuration//provisioning:Telegram.mobileprovision",
}),
entitlements = ":TelegramEntitlements.entitlements",
infoplists = [
":TelegramInfoPlist",
":BuildNumberInfoPlist",
":VersionInfoPlist",
":UrlTypesInfoPlist",
],
deps = [
"//third-party/webrtc:webrtc_lib",
],
)
ios_application(
name = "libvpx_build_test",
bundle_id = "{telegram_bundle_id}".format(
telegram_bundle_id = telegram_bundle_id,
),
families = ["iphone", "ipad"],
minimum_os_version = "9.0",
provisioning_profile = select({
":disableProvisioningProfilesSetting": None,
"//conditions:default": "@build_configuration//provisioning:Telegram.mobileprovision",
}),
entitlements = ":TelegramEntitlements.entitlements",
infoplists = [
":TelegramInfoPlist",
":BuildNumberInfoPlist",
":VersionInfoPlist",
":UrlTypesInfoPlist",
],
deps = [
"//third-party/libvpx:vpx",
],
)

View File

@ -0,0 +1,282 @@
import Foundation
import ReplayKit
import CoreVideo
import TelegramVoip
import SwiftSignalKit
import BuildConfig
import BroadcastUploadHelpers
import AudioToolbox
private func rootPathForBasePath(_ appGroupPath: String) -> String {
return appGroupPath + "/telegram-data"
}
@available(iOS 10.0, *)
@objc(BroadcastUploadSampleHandler) class BroadcastUploadSampleHandler: RPBroadcastSampleHandler {
private var screencastBufferClientContext: IpcGroupCallBufferBroadcastContext?
private var statusDisposable: Disposable?
private var audioConverter: CustomAudioConverter?
deinit {
self.statusDisposable?.dispose()
}
public override func beginRequest(with context: NSExtensionContext) {
super.beginRequest(with: context)
}
private func finish(with reason: IpcGroupCallBufferBroadcastContext.Status.FinishReason) {
var errorString: String?
switch reason {
case .callEnded:
errorString = "You're not in a voice chat"
case .error:
errorString = "Finished"
case .screencastEnded:
break
}
if let errorString = errorString {
let error = NSError(domain: "BroadcastUploadExtension", code: 1, userInfo: [
NSLocalizedDescriptionKey: errorString
])
finishBroadcastWithError(error)
} else {
finishBroadcastGracefully(self)
}
}
override public func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) {
guard let appBundleIdentifier = Bundle.main.bundleIdentifier, let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
self.finish(with: .error)
return
}
let baseAppBundleId = String(appBundleIdentifier[..<lastDotRange.lowerBound])
let appGroupName = "group.\(baseAppBundleId)"
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
guard let appGroupUrl = maybeAppGroupUrl else {
self.finish(with: .error)
return
}
let rootPath = rootPathForBasePath(appGroupUrl.path)
let logsPath = rootPath + "/broadcast-logs"
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
let screencastBufferClientContext = IpcGroupCallBufferBroadcastContext(basePath: rootPath + "/broadcast-coordination")
self.screencastBufferClientContext = screencastBufferClientContext
self.statusDisposable = (screencastBufferClientContext.status
|> deliverOnMainQueue).start(next: { [weak self] status in
guard let strongSelf = self else {
return
}
switch status {
case let .finished(reason):
strongSelf.finish(with: reason)
}
})
}
override public func broadcastPaused() {
}
override public func broadcastResumed() {
}
override public func broadcastFinished() {
}
override public func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
switch sampleBufferType {
case RPSampleBufferType.video:
processVideoSampleBuffer(sampleBuffer: sampleBuffer)
case RPSampleBufferType.audioApp:
processAudioSampleBuffer(sampleBuffer: sampleBuffer)
case RPSampleBufferType.audioMic:
break
@unknown default:
break
}
}
private func processVideoSampleBuffer(sampleBuffer: CMSampleBuffer) {
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
return
}
var orientation = CGImagePropertyOrientation.up
if #available(iOS 11.0, *) {
if let orientationAttachment = CMGetAttachment(sampleBuffer, key: RPVideoSampleOrientationKey as CFString, attachmentModeOut: nil) as? NSNumber {
orientation = CGImagePropertyOrientation(rawValue: orientationAttachment.uint32Value) ?? .up
}
}
if let data = serializePixelBuffer(buffer: pixelBuffer) {
self.screencastBufferClientContext?.setCurrentFrame(data: data, orientation: orientation)
}
}
private func processAudioSampleBuffer(sampleBuffer: CMSampleBuffer) {
guard let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer) else {
return
}
guard let asbd = CMAudioFormatDescriptionGetStreamBasicDescription(formatDescription) else {
return
}
/*guard let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) else {
return
}*/
let format = CustomAudioConverter.Format(
numChannels: Int(asbd.pointee.mChannelsPerFrame),
sampleRate: Int(asbd.pointee.mSampleRate)
)
if self.audioConverter?.format != format {
self.audioConverter = CustomAudioConverter(asbd: asbd)
}
if let audioConverter = self.audioConverter {
if let data = audioConverter.convert(sampleBuffer: sampleBuffer), !data.isEmpty {
self.screencastBufferClientContext?.writeAudioData(data: data)
}
}
}
}
private final class CustomAudioConverter {
struct Format: Equatable {
let numChannels: Int
let sampleRate: Int
}
let format: Format
var currentInputDescription: UnsafePointer<AudioStreamBasicDescription>?
var currentBuffer: AudioBuffer?
var currentBufferOffset: UInt32 = 0
init(asbd: UnsafePointer<AudioStreamBasicDescription>) {
self.format = Format(
numChannels: Int(asbd.pointee.mChannelsPerFrame),
sampleRate: Int(asbd.pointee.mSampleRate)
)
}
func convert(sampleBuffer: CMSampleBuffer) -> Data? {
guard let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer) else {
return nil
}
guard let asbd = CMAudioFormatDescriptionGetStreamBasicDescription(formatDescription) else {
return nil
}
var bufferList = AudioBufferList()
var blockBuffer: CMBlockBuffer? = nil
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
sampleBuffer,
bufferListSizeNeededOut: nil,
bufferListOut: &bufferList,
bufferListSize: MemoryLayout<AudioBufferList>.size,
blockBufferAllocator: nil,
blockBufferMemoryAllocator: nil,
flags: kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment,
blockBufferOut: &blockBuffer
)
let size = bufferList.mBuffers.mDataByteSize
guard size != 0, let mData = bufferList.mBuffers.mData else {
return nil
}
var outputDescription = AudioStreamBasicDescription(
mSampleRate: 48000.0,
mFormatID: kAudioFormatLinearPCM,
mFormatFlags: kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked,
mBytesPerPacket: 2,
mFramesPerPacket: 1,
mBytesPerFrame: 2,
mChannelsPerFrame: 1,
mBitsPerChannel: 16,
mReserved: 0
)
var maybeAudioConverter: AudioConverterRef?
let _ = AudioConverterNew(asbd, &outputDescription, &maybeAudioConverter)
guard let audioConverter = maybeAudioConverter else {
return nil
}
self.currentBuffer = AudioBuffer(
mNumberChannels: asbd.pointee.mChannelsPerFrame,
mDataByteSize: UInt32(size),
mData: mData
)
self.currentBufferOffset = 0
self.currentInputDescription = asbd
var numPackets: UInt32?
let outputSize = 32768 * 2
var outputBuffer = Data(count: outputSize)
outputBuffer.withUnsafeMutableBytes { (outputBytes: UnsafeMutableRawBufferPointer) -> Void in
var outputBufferList = AudioBufferList()
outputBufferList.mNumberBuffers = 1
outputBufferList.mBuffers.mNumberChannels = outputDescription.mChannelsPerFrame
outputBufferList.mBuffers.mDataByteSize = UInt32(outputSize)
outputBufferList.mBuffers.mData = outputBytes.baseAddress!
var outputDataPacketSize = UInt32(outputSize) / outputDescription.mBytesPerPacket
let result = AudioConverterFillComplexBuffer(
audioConverter,
converterComplexInputDataProc,
Unmanaged.passUnretained(self).toOpaque(),
&outputDataPacketSize,
&outputBufferList,
nil
)
if result == noErr {
numPackets = outputDataPacketSize
}
}
AudioConverterDispose(audioConverter)
if let numPackets = numPackets {
outputBuffer.count = Int(numPackets * outputDescription.mBytesPerPacket)
return outputBuffer
} else {
return nil
}
}
}
private func converterComplexInputDataProc(inAudioConverter: AudioConverterRef, ioNumberDataPackets: UnsafeMutablePointer<UInt32>, ioData: UnsafeMutablePointer<AudioBufferList>, ioDataPacketDescription: UnsafeMutablePointer<UnsafeMutablePointer<AudioStreamPacketDescription>?>?, inUserData: UnsafeMutableRawPointer?) -> Int32 {
guard let inUserData = inUserData else {
ioNumberDataPackets.pointee = 0
return 0
}
let instance = Unmanaged<CustomAudioConverter>.fromOpaque(inUserData).takeUnretainedValue()
guard let currentBuffer = instance.currentBuffer else {
ioNumberDataPackets.pointee = 0
return 0
}
guard let currentInputDescription = instance.currentInputDescription else {
ioNumberDataPackets.pointee = 0
return 0
}
let numPacketsInBuffer = currentBuffer.mDataByteSize / currentInputDescription.pointee.mBytesPerPacket
let numPacketsAvailable = numPacketsInBuffer - instance.currentBufferOffset / currentInputDescription.pointee.mBytesPerPacket
let numPacketsToRead = min(ioNumberDataPackets.pointee, numPacketsAvailable)
ioNumberDataPackets.pointee = numPacketsToRead
ioData.pointee.mNumberBuffers = 1
ioData.pointee.mBuffers.mData = currentBuffer.mData?.advanced(by: Int(instance.currentBufferOffset))
ioData.pointee.mBuffers.mDataByteSize = currentBuffer.mDataByteSize - instance.currentBufferOffset
ioData.pointee.mBuffers.mNumberChannels = currentBuffer.mNumberChannels
instance.currentBufferOffset += numPacketsToRead * currentInputDescription.pointee.mBytesPerPacket
return 0
}

View File

@ -38,7 +38,7 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
self.impl = NotificationViewControllerImpl(initializationData: NotificationViewControllerInitializationData(appGroupPath: appGroupUrl.path, apiId: buildConfig.apiId, apiHash: buildConfig.apiHash, languagesCategory: languagesCategory, encryptionParameters: encryptionParameters, appVersion: appVersion, bundleData: buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), setPreferredContentSize: { [weak self] size in
self.impl = NotificationViewControllerImpl(initializationData: NotificationViewControllerInitializationData(appBundleId: baseAppBundleId, appGroupPath: appGroupUrl.path, apiId: buildConfig.apiId, apiHash: buildConfig.apiHash, languagesCategory: languagesCategory, encryptionParameters: encryptionParameters, appVersion: appVersion, bundleData: buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), setPreferredContentSize: { [weak self] size in
self?.preferredContentSize = size
})
}

View File

@ -3,7 +3,7 @@
@implementation Serialization
- (NSUInteger)currentLayer {
return 125;
return 131;
}
- (id _Nullable)parseMessage:(NSData * _Nullable)data {

View File

@ -45,7 +45,7 @@ class ShareRootController: UIViewController {
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
self.impl = ShareRootControllerImpl(initializationData: ShareRootControllerInitializationData(appGroupPath: appGroupUrl.path, apiId: buildConfig.apiId, apiHash: buildConfig.apiHash, languagesCategory: languagesCategory, encryptionParameters: encryptionParameters, appVersion: appVersion, bundleData: buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), getExtensionContext: { [weak self] in
self.impl = ShareRootControllerImpl(initializationData: ShareRootControllerInitializationData(appBundleId: baseAppBundleId, appGroupPath: appGroupUrl.path, apiId: buildConfig.apiId, apiHash: buildConfig.apiHash, languagesCategory: languagesCategory, encryptionParameters: encryptionParameters, appVersion: appVersion, bundleData: buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), getExtensionContext: { [weak self] in
return self?.extensionContext
})
}

View File

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${APP_NAME}</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>$(PRODUCT_BUNDLE_SHORT_VERSION)</string>
<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>IntentsRestrictedWhileLocked</key>
<array/>
<key>IntentsRestrictedWhileProtectedDataUnavailable</key>
<array/>
<key>IntentsSupported</key>
<array>
<string>INSendMessageIntent</string>
<string>INStartAudioCallIntent</string>
<string>INSearchForMessagesIntent</string>
<string>INSetMessageAttributeIntent</string>
<string>INSearchCallHistoryIntent</string>
</array>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.intents-service</string>
<key>NSExtensionPrincipalClass</key>
<string>IntentHandler</string>
</dict>
</dict>
</plist>

View File

@ -35,7 +35,7 @@ private func parseAppSpecificContactReference(_ value: String) -> PeerId? {
}
let idString = String(value[value.index(value.startIndex, offsetBy: phonebookUsernamePrefix.count)...])
if let id = Int32(idString) {
return PeerId(namespace: Namespaces.Peer.CloudUser, id: id)
return PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt32Value(id))
}
return nil
}

View File

@ -114,7 +114,7 @@ class DefaultIntentHandler: INExtension, INSendMessageIntentHandling, INSearchFo
self.rootPath = rootPath
TempBox.initializeShared(basePath: rootPath, processType: "siri", launchSpecificId: arc4random64())
TempBox.initializeShared(basePath: rootPath, processType: "siri", launchSpecificId: Int64.random(in: Int64.min ... Int64.max))
let logsPath = rootPath + "/siri-logs"
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
@ -619,7 +619,7 @@ class DefaultIntentHandler: INExtension, INSendMessageIntentHandling, INSearchFo
}
for (_, messageId) in maxMessageIdsToApply {
signals.append(applyMaxReadIndexInteractively(postbox: account.postbox, stateManager: account.stateManager, index: MessageIndex(id: messageId, timestamp: 0))
signals.append(TelegramEngine(account: account).messages.applyMaxReadIndexInteractively(index: MessageIndex(id: messageId, timestamp: 0))
|> castError(IntentHandlingError.self))
}
@ -793,7 +793,7 @@ class DefaultIntentHandler: INExtension, INSendMessageIntentHandling, INSearchFo
var accountResults: [Signal<INObjectSection<Friend>, Error>] = []
for (accountId, accountPeerId, _) in accounts {
accountResults.append(accountTransaction(rootPath: rootPath, id: accountId, encryptionParameters: encryptionParameters, isReadOnly: true, useCopy: true, transaction: { postbox, transaction -> INObjectSection<Friend> in
accountResults.append(accountTransaction(rootPath: rootPath, id: accountId, encryptionParameters: encryptionParameters, isReadOnly: true, useCopy: false, transaction: { postbox, transaction -> INObjectSection<Friend> in
var accountTitle: String = ""
if let peer = transaction.getPeer(accountPeerId) as? TelegramUser {
if let username = peer.username, !username.isEmpty {
@ -884,7 +884,7 @@ private final class WidgetIntentHandler {
self.rootPath = rootPath
TempBox.initializeShared(basePath: rootPath, processType: "siri", launchSpecificId: arc4random64())
TempBox.initializeShared(basePath: rootPath, processType: "siri", launchSpecificId: Int64.random(in: Int64.min ... Int64.max))
let logsPath = rootPath + "/siri-logs"
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
@ -962,7 +962,7 @@ private final class WidgetIntentHandler {
var accountResults: [Signal<INObjectSection<Friend>, Error>] = []
for (accountId, accountPeerId, _) in accounts {
accountResults.append(accountTransaction(rootPath: rootPath, id: accountId, encryptionParameters: encryptionParameters, isReadOnly: true, useCopy: true, transaction: { postbox, transaction -> INObjectSection<Friend> in
accountResults.append(accountTransaction(rootPath: rootPath, id: accountId, encryptionParameters: encryptionParameters, isReadOnly: true, useCopy: false, transaction: { postbox, transaction -> INObjectSection<Friend> in
var accountTitle: String = ""
if let peer = transaction.getPeer(accountPeerId) as? TelegramUser {
if let username = peer.username, !username.isEmpty {
@ -1045,10 +1045,10 @@ private final class WidgetIntentHandler {
if !isActive {
continue
}
accountResults.append(accountTransaction(rootPath: rootPath, id: accountId, encryptionParameters: encryptionParameters, isReadOnly: true, useCopy: true, transaction: { postbox, transaction -> [Friend] in
accountResults.append(accountTransaction(rootPath: rootPath, id: accountId, encryptionParameters: encryptionParameters, isReadOnly: true, useCopy: false, transaction: { postbox, transaction -> [Friend] in
var peers: [Peer] = []
for id in getRecentPeers(transaction: transaction) {
for id in _internal_getRecentPeers(transaction: transaction) {
if let peer = transaction.getPeer(id), !(peer is TelegramSecretChat), !peer.isDeleted {
peers.append(peer)
}

View File

@ -166,7 +166,7 @@ private func callWithTelegramMessage(_ telegramMessage: Message, account: Accoun
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
private func messageWithTelegramMessage(_ telegramMessage: Message) -> INMessage? {
guard let author = telegramMessage.author, let user = telegramMessage.peers[author.id] as? TelegramUser, user.id.id != 777000 else {
guard let author = telegramMessage.author, let user = telegramMessage.peers[author.id] as? TelegramUser, user.id.id._internalGetInt32Value() != 777000 else {
return nil
}

View File

@ -72,4 +72,44 @@
<key>UIPrerenderedIcon</key>
<true/>
</dict>
<key>New1</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>New1_20x20</string>
<string>New1_29x29</string>
<string>New1_40x40</string>
<string>New1_58x58</string>
<string>New1_60x60</string>
<string>New1_76x76</string>
<string>New1_80x80</string>
<string>New1_87x87</string>
<string>New1_120x120</string>
<string>New1_152x152</string>
<string>New1_167x167</string>
<string>New1_180x180</string>
</array>
<key>UIPrerenderedIcon</key>
<true/>
</dict>
<key>New2</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>New2_20x20</string>
<string>New2_29x29</string>
<string>New2_40x40</string>
<string>New2_58x58</string>
<string>New2_60x60</string>
<string>New2_76x76</string>
<string>New2_80x80</string>
<string>New2_87x87</string>
<string>New2_120x120</string>
<string>New2_152x152</string>
<string>New2_167x167</string>
<string>New2_180x180</string>
</array>
<key>UIPrerenderedIcon</key>
<true/>
</dict>
</dict>

View File

@ -66,4 +66,44 @@
<key>UIPrerenderedIcon</key>
<true/>
</dict>
<key>New1</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>New1_20x20</string>
<string>New1_29x29</string>
<string>New1_40x40</string>
<string>New1_58x58</string>
<string>New1_60x60</string>
<string>New1_76x76</string>
<string>New1_80x80</string>
<string>New1_87x87</string>
<string>New1_120x120</string>
<string>New1_152x152</string>
<string>New1_167x167</string>
<string>New1_180x180</string>
</array>
<key>UIPrerenderedIcon</key>
<true/>
</dict>
<key>New2</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>New2_20x20</string>
<string>New2_29x29</string>
<string>New2_40x40</string>
<string>New2_58x58</string>
<string>New2_60x60</string>
<string>New2_76x76</string>
<string>New2_80x80</string>
<string>New2_87x87</string>
<string>New2_120x120</string>
<string>New2_152x152</string>
<string>New2_167x167</string>
<string>New2_180x180</string>
</array>
<key>UIPrerenderedIcon</key>
<true/>
</dict>
</dict>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -104,9 +104,8 @@
"PUSH_MESSAGES_1" = "%1$@|sent you a message";
"PUSH_MESSAGES_any" = "%1$@|sent you %2$d messages";
"PUSH_ALBUM" = "%1$@|sent you an album";
"PUSH_MESSAGE_DOCS" = "%1$@|sent you %2$d files";
"PUSH_MESSAGE_DOCS_1" = "%1$@|sent you a file";
"PUSH_MESSAGE_DOCS_any" = "%1$@|sent you %2$d files";
"PUSH_MESSAGE_FILES_1" = "%1$@|sent you a file";
"PUSH_MESSAGE_FILES_any" = "%1$@|sent you %2$d files";
"PUSH_CHANNEL_MESSAGE_TEXT" = "%1$@|%2$@";
@ -2552,7 +2551,6 @@ Unused sets are archived when you add more.";
"Message.ForwardedMessageShort" = "Forwarded From\n%@";
"Checkout.LiabilityAlertTitle" = "Warning";
"Checkout.LiabilityAlert" = "Neither Telegram, nor %1$@ will have access to your credit card information. Credit card details will be handled only by the payment system, %2$@.\n\nPayments will go directly to the developer of %1$@. Telegram cannot provide any guarantees, so proceed at your own risk. In case of problems, please contact the developer of %1$@ or your bank.";
"Settings.AppLanguage" = "Language";
"Settings.AppLanguage.Unofficial" = "UNOFFICIAL";
@ -3950,6 +3948,7 @@ Unused sets are archived when you add more.";
"WallpaperPreview.Title" = "Background Preview";
"WallpaperPreview.PreviewTopText" = "Press Set to apply the background";
"WallpaperPreview.PreviewBottomText" = "Enjoy the view";
"WallpaperPreview.SwipeTopText" = "Swipe left or right to preview more backgrounds";
"WallpaperPreview.SwipeBottomText" = "Backgrounds for the god of backgrounds!";
"WallpaperPreview.SwipeColorsTopText" = "Swipe left or right to see more colors";
@ -4430,6 +4429,8 @@ Sorry for the inconvenience.";
"Appearance.AppIconClassicX" = "Classic X";
"Appearance.AppIconFilled" = "Filled";
"Appearance.AppIconFilledX" = "Filled X";
"Appearance.AppIconNew1" = "Sunset";
"Appearance.AppIconNew2" = "Aqua";
"Appearance.ThemeCarouselClassic" = "Classic";
"Appearance.ThemeCarouselDay" = "Day";
@ -5742,6 +5743,7 @@ Sorry for the inconvenience.";
"Notification.VoiceChatStarted" = "%1$@ started a voice chat";
"Notification.VoiceChatEnded" = "Voice chat ended (%@)";
"Notification.VoiceChatEndedGroup" = "%1$@ ended the voice chat (%2$@)";
"VoiceChat.Panel.TapToJoin" = "Tap to join";
"VoiceChat.Panel.Members_0" = "%@ participants";
@ -5774,10 +5776,13 @@ Sorry for the inconvenience.";
"VoiceChat.CreateNewVoiceChatText" = "Voice chat ended. Start a new one?";
"VoiceChat.CreateNewVoiceChatStart" = "Start";
"VoiceChat.CreateNewVoiceChatStartNow" = "Start Now";
"VoiceChat.CreateNewVoiceChatSchedule" = "Schedule";
"PUSH_CHAT_VOICECHAT_START" = "%2$@|%1$@ started a voice chat";
"PUSH_CHAT_VOICECHAT_INVITE" = "%2$@|%1$@ invited %3$@ to the voice chat";
"PUSH_CHAT_VOICECHAT_INVITE_YOU" = "%2$|@%1$@ invited you to the voice chat";
"PUSH_CHAT_VOICECHAT_INVITE_YOU" = "%2$@|%1$@ invited you to the voice chat";
"PUSH_CHAT_VOICECHAT_END" = "%2$@|%1$@ has ended the voice chat";
"Call.VoiceChatInProgressTitle" = "Voice Chat in Progress";
"Call.VoiceChatInProgressMessageCall" = "Leave voice chat in %1$@ and start a call with %2$@?";
@ -6037,7 +6042,6 @@ Sorry for the inconvenience.";
"Conversation.ForwardTooltip.TwoChats.Many" = "Messages forwarded to **%@** and **%@**";
"Conversation.ForwardTooltip.ManyChats.One" = "Message forwarded to **%@** and %@ others";
"Conversation.ForwardTooltip.ManyChats.Many" = "Messages forwarded to **%@** and %@ others";
"Conversation.ForwardTooltip.SavedMessages.One" = "Message forwarded to **Saved Messages**";
"Conversation.ForwardTooltip.SavedMessages.Many" = "Messages forwarded to **Saved Messages**";
@ -6255,6 +6259,7 @@ Sorry for the inconvenience.";
"VoiceChat.YouCanNowSpeak" = "You can now speak";
"VoiceChat.YouCanNowSpeakIn" = "You can now speak in **%@**";
"VoiceChat.UserCanNowSpeak" = "**%@** can now speak";
"VoiceChat.MutedByAdmin" = "Muted by Admin";
"VoiceChat.MutedByAdminHelp" = "Tap if you want to speak";
@ -6292,7 +6297,277 @@ Sorry for the inconvenience.";
"VoiceChat.LeaveConfirmation" = "Are you sure you want to leave this voice chat?";
"VoiceChat.LeaveVoiceChat" = "Leave Voice Chat";
"VoiceChat.LeaveAndEndVoiceChat" = "End Voice Chat";
"VoiceChat.LeaveAndCancelVoiceChat" = "Abort Voice Chat";
"VoiceChat.ForwardTooltip.Chat" = "Invite link forwarded to **%@**";
"VoiceChat.ForwardTooltip.TwoChats" = "Invite link forwarded to **%@** and **%@**";
"VoiceChat.ForwardTooltip.ManyChats" = "Invite link forwarded to **%@** and %@ others";
"GroupRemoved.ViewChannelInfo" = "View Channel";
"UserInfo.ContactForwardTooltip.Chat.One" = "Contact forwarded to **%@**";
"UserInfo.ContactForwardTooltip.TwoChats.One" = "Contact forwarded to **%@** and **%@**";
"UserInfo.ContactForwardTooltip.ManyChats.One" = "Contact forwarded to **%@** and %@ others";
"UserInfo.ContactForwardTooltip.SavedMessages.One" = "Contact forwarded to **Saved Messages**";
"UserInfo.LinkForwardTooltip.Chat.One" = "Link forwarded to **%@**";
"UserInfo.LinkForwardTooltip.TwoChats.One" = "Link forwarded to **%@** and **%@**";
"UserInfo.LinkForwardTooltip.ManyChats.One" = "Link forwarded to **%@** and %@ others";
"UserInfo.LinkForwardTooltip.SavedMessages.One" = "Link forwarded to **Saved Messages**";
"VoiceChat.You" = "this is you";
"VoiceChat.ChangePhoto" = "Change Photo";
"VoiceChat.EditBio" = "Edit Bio";
"VoiceChat.EditBioTitle" = "Bio";
"VoiceChat.EditBioText" = "Any details such as age, occupation or city.";
"VoiceChat.EditBioPlaceholder" = "Bio";
"VoiceChat.EditBioSave" = "Save";
"VoiceChat.EditBioSuccess" = "Your bio is changed.";
"VoiceChat.EditDescription" = "Edit Description";
"VoiceChat.EditDescriptionTitle" = "Description";
"VoiceChat.EditDescriptionText" = "Any details such as age, occupation or city.";
"VoiceChat.EditDescriptionPlaceholder" = "Description";
"VoiceChat.EditDescriptionSave" = "Save";
"VoiceChat.EditDescriptionSuccess" = "Description is changed.";
"VoiceChat.SendPublicLinkText" = "%1$@ isn't a member of \"%2$@\" yet. Send them a public invite link instead?";
"VoiceChat.SendPublicLinkSend" = "Send";
"VoiceChat.TapToAddPhotoOrBio" = "tap to add photo or bio";
"VoiceChat.TapToAddPhoto" = "tap to add photo";
"VoiceChat.TapToAddBio" = "tap to add bio";
"VoiceChat.ImproveYourProfileText" = "You can improve your profile by adding missing information.";
"VoiceChat.AddPhoto" = "Add Photo";
"VoiceChat.AddBio" = "Add Bio";
"VoiceChat.ChangeName" = "Change Name";
"VoiceChat.ChangeNameTitle" = "Change Name";
"VoiceChat.EditNameSuccess" = "Your name is changed.";
"VoiceChat.Video" = "video";
"VoiceChat.PinVideo" = "Pin Video";
"VoiceChat.UnpinVideo" = "Unpin Video";
"Notification.VoiceChatScheduledChannel" = "Voice chat scheduled for %@";
"Notification.VoiceChatScheduled" = "%1$@ scheduled a voice chat for %2$@";
"Notification.VoiceChatScheduledTodayChannel" = "Voice chat scheduled for today at %@";
"Notification.VoiceChatScheduledToday" = "%1$@ scheduled a voice chat for today at %2$@";
"Notification.VoiceChatScheduledTomorrowChannel" = "Voice chat scheduled for tomorrow at %@";
"Notification.VoiceChatScheduledTomorrow" = "%1$@ scheduled a voice chat for tomorrow at %2$@";
"VoiceChat.StartsIn" = "Starts in";
"VoiceChat.LateBy" = "Late by";
"VoiceChat.StatusStartsIn" = "starts in %@";
"VoiceChat.StatusLateBy" = "late by %@";
"VoiceChat.Scheduled" = "Scheduled";
"VoiceChat.StartNow" = "Start Now";
"VoiceChat.SetReminder" = "Set Reminder";
"VoiceChat.CancelReminder" = "Cancel Reminder";
"VoiceChat.ShareShort" = "share";
"VoiceChat.TapToEditTitle" = "Tap to edit title";
"ChannelInfo.ScheduleVoiceChat" = "Schedule Voice Chat";
"ScheduleVoiceChat.Title" = "Schedule Voice Chat";
"ScheduleVoiceChat.GroupText" = "The members of the group will be notified that the voice chat will start in %@.";
"ScheduleVoiceChat.ChannelText" = "The members of the channel will be notified that the voice chat will start in %@.";
"ScheduleVoiceChat.ScheduleToday" = "Start today at %@";
"ScheduleVoiceChat.ScheduleTomorrow" = "Start tomorrow at %@";
"ScheduleVoiceChat.ScheduleOn" = "Start on %@ at %@";
"Conversation.ScheduledVoiceChat" = "Scheduled Voice Chat";
"Conversation.ScheduledVoiceChatStartsOn" = "Voice chat starts on %@";
"Conversation.ScheduledVoiceChatStartsOnShort" = "Starts on %@";
"Conversation.ScheduledVoiceChatStartsToday" = "Voice chat starts today at %@";
"Conversation.ScheduledVoiceChatStartsTodayShort" = "Starts today at %@";
"Conversation.ScheduledVoiceChatStartsTomorrow" = "Voice chat starts tomorrow at %@";
"Conversation.ScheduledVoiceChatStartsTomorrowShort" = "Starts tomorrow at %@";
"VoiceChat.CancelVoiceChat" = "Abort Voice Chat";
"VoiceChat.CancelConfirmationTitle" = "Abort Voice Chat";
"VoiceChat.CancelConfirmationText" = "Do you want to abort the scheduled voice chat?";
"VoiceChat.CancelConfirmationEnd" = "Abort";
"ScheduledIn.Seconds_1" = "%@ second";
"ScheduledIn.Seconds_2" = "%@ seconds";
"ScheduledIn.Seconds_3_10" = "%@ seconds";
"ScheduledIn.Seconds_any" = "%@ seconds";
"ScheduledIn.Seconds_many" = "%@ seconds";
"ScheduledIn.Seconds_0" = "%@ seconds";
"ScheduledIn.Minutes_1" = "%@ minute";
"ScheduledIn.Minutes_2" = "%@ minutes";
"ScheduledIn.Minutes_3_10" = "%@ minutes";
"ScheduledIn.Minutes_any" = "%@ minutes";
"ScheduledIn.Minutes_many" = "%@ minutes";
"ScheduledIn.Minutes_0" = "%@ minutes";
"ScheduledIn.Hours_1" = "%@ hour";
"ScheduledIn.Hours_2" = "%@ hours";
"ScheduledIn.Hours_3_10" = "%@ hours";
"ScheduledIn.Hours_any" = "%@ hours";
"ScheduledIn.Hours_many" = "%@ hours";
"ScheduledIn.Hours_0" = "%@ hours";
"ScheduledIn.Days_1" = "%@ day";
"ScheduledIn.Days_2" = "%@ days";
"ScheduledIn.Days_3_10" = "%@ days";
"ScheduledIn.Days_any" = "%@ days";
"ScheduledIn.Days_many" = "%@ days";
"ScheduledIn.Days_0" = "%@ days";
"ScheduledIn.Weeks_1" = "%@ week";
"ScheduledIn.Weeks_2" = "%@ weeks";
"ScheduledIn.Weeks_3_10" = "%@ weeks";
"ScheduledIn.Weeks_any" = "%@ weeks";
"ScheduledIn.Weeks_many" = "%@ weeks";
"ScheduledIn.Weeks_0" = "%@ weeks";
"ScheduledIn.Months_1" = "%@ month";
"ScheduledIn.Months_2" = "%@ months";
"ScheduledIn.Months_3_10" = "%@ months";
"ScheduledIn.Months_any" = "%@ months";
"ScheduledIn.Months_many" = "%@ months";
"ScheduledIn.Months_0" = "%@ months";
"ScheduledIn.Years_1" = "%@ year";
"ScheduledIn.Years_2" = "%@ years";
"ScheduledIn.Years_3_10" = "%@ years";
"ScheduledIn.Years_any" = "%@ years";
"ScheduledIn.Months_many" = "%@ years";
"Checkout.PaymentLiabilityAlert" = "Neither Telegram, nor {target} will have access to your credit card information. Credit card details will be handled only by the payment system, {payment_system}.\n\nPayments will go directly to the developer of {target}. Telegram cannot provide any guarantees, so proceed at your own risk. In case of problems, please contact the developer of {target} or your bank.";
"Checkout.OptionalTipItem" = "Tip (Optional)";
"Checkout.TipItem" = "Tip";
"Checkout.OptionalTipItemPlaceholder" = "Enter Custom";
"VoiceChat.ReminderNotify" = "We will notify you when it starts.";
"Checkout.SuccessfulTooltip" = "You paid %1$@ for %2$@.";
"Privacy.ContactsReset.ContactsDeleted" = "All synced contacts deleted.";
"Privacy.DeleteDrafts.DraftsDeleted" = "All cloud drafts deleted.";
"Privacy.PaymentsClear.PaymentInfoCleared" = "Payment info cleared.";
"Privacy.PaymentsClear.ShippingInfoCleared" = "Shipping info cleared.";
"Privacy.PaymentsClear.AllInfoCleared" = "Payment and shipping info cleared.";
"Settings.Tips" = "Telegram Features";
"Settings.TipsUsername" = "TelegramTips";
"Calls.NoVoiceAndVideoCallsPlaceholder" = "Your recent voice and video calls will appear here.";
"Calls.StartNewCall" = "Start New Call";
"VoiceChat.VideoPreviewTitle" = "Video Preview";
"VoiceChat.VideoPreviewDescription" = "Are you sure you want to share your video?";
"VoiceChat.VideoPreviewShareCamera" = "Share Camera Video";
"VoiceChat.VideoPreviewShareScreen" = "Share Screen";
"VoiceChat.VideoPreviewStopScreenSharing" = "Stop Screen Sharing";
"VoiceChat.TapToViewCameraVideo" = "Tap to view camera video";
"VoiceChat.TapToViewScreenVideo" = "Tap to view screen sharing";
"VoiceChat.ShareScreen" = "Share Screen";
"VoiceChat.StopScreenSharing" = "Stop Screen Sharing";
"VoiceChat.ParticipantIsSpeaking" = "%1$@ is speaking";
"WallpaperPreview.WallpaperColors" = "Colors";
"VoiceChat.UnmuteSuggestion" = "You are on mute. Tap here to speak.";
"VoiceChat.ContextAudio" = "Audio";
"VoiceChat.VideoPaused" = "Video is paused";
"VoiceChat.YouAreSharingScreen" = "You are sharing your screen";
"VoiceChat.StopScreenSharingShort" = "Stop Sharing";
"VoiceChat.OpenGroup" = "Open Group";
"VoiceChat.NoiseSuppression" = "Noise Suppression";
"VoiceChat.NoiseSuppressionEnabled" = "Enabled";
"VoiceChat.NoiseSuppressionDisabled" = "Disabled";
"VoiceChat.Unpin" = "Unpin";
"VoiceChat.VideoParticipantsLimitExceeded" = "Video is only available\nfor the first %@ members";
"ImportStickerPack.StickerCount_1" = "1 Sticker";
"ImportStickerPack.StickerCount_2" = "2 Stickers";
"ImportStickerPack.StickerCount_3_10" = "%@ Stickers";
"ImportStickerPack.StickerCount_any" = "%@ Stickers";
"ImportStickerPack.StickerCount_many" = "%@ Stickers";
"ImportStickerPack.StickerCount_0" = "%@ Stickers";
"ImportStickerPack.CreateStickerSet" = "Create Sticker Set";
"ImportStickerPack.CreateNewStickerSet" = "Create a New Sticker Set";
"ImportStickerPack.AddToExistingStickerSet" = "Add to an Existing Sticker Set";
"ImportStickerPack.ChooseStickerSet" = "Choose Sticker Set";
"ImportStickerPack.RemoveFromImport" = "Remove From Import";
"ImportStickerPack.ChooseName" = "Choose Name";
"ImportStickerPack.ChooseNameDescription" = "Please choose a name for your set.";
"ImportStickerPack.NamePlaceholder" = "Name";
"ImportStickerPack.GeneratingLink" = "generating link...";
"ImportStickerPack.CheckingLink" = "checking availability...";
"ImportStickerPack.ChooseLink" = "Choose Link";
"ImportStickerPack.ChooseLinkDescription" = "You can use a-z, 0-9 and underscores.";
"ImportStickerPack.LinkTaken" = "Sorry, this link is already taken.";
"ImportStickerPack.LinkAvailable" = "Link is available.";
"ImportStickerPack.ImportingStickers" = "Importing Stickers";
"ImportStickerPack.Of" = "%1$@ of %2$@ Imported";
"ImportStickerPack.InProgress" = "Please keep this window open\nuntil the import is completed.";
"ImportStickerPack.Create" = "Create";
"WallpaperPreview.PreviewBottomTextAnimatable" = "Tap the play button to view the background animation.";
"Conversation.InputMenu" = "Menu";
"Conversation.MessageDoesntExist" = "Message doesn't exist";
"Settings.CheckPasswordTitle" = "Your Password";
"Settings.CheckPasswordText" = "Your account is protected by 2-Step Verification. Do you still remember your password?";
"Settings.KeepPassword" = "Yes, definitely";
"Settings.TryEnterPassword" = "Not sure, let me try";
"TwoFactorSetup.PasswordRecovery.Title" = "Create New Password";
"TwoFactorSetup.PasswordRecovery.Text" = "You can now set a new password that will be used to log into your account.";
"TwoFactorSetup.PasswordRecovery.PlaceholderPassword" = "New Password";
"TwoFactorSetup.PasswordRecovery.PlaceholderConfirmPassword" = "Re-enter New Password";
"TwoFactorSetup.PasswordRecovery.Action" = "Continue";
"TwoFactorSetup.PasswordRecovery.Skip" = "Skip";
"TwoFactorSetup.PasswordRecovery.SkipAlertTitle" = "Attention!";
"TwoFactorSetup.PasswordRecovery.SkipAlertText" = "Skipping this step will disable 2-step verification for your account. Are you sure you want to skip?";
"TwoFactorSetup.PasswordRecovery.SkipAlertAction" = "Skip";
"TwoStepAuth.RecoveryUnavailableResetTitle" = "Reset Password";
"TwoStepAuth.RecoveryUnavailableResetText" = "Since you didnt provide a recovery email when setting up your password, your remaining options are either to remember your password or wait 7 days until your password is reset.";
"TwoStepAuth.RecoveryEmailResetText" = "If you don't have access to your recovery email, your remaining options are either to remember your password or wait 7 days until your password resets.";
"TwoStepAuth.RecoveryUnavailableResetAction" = "Reset";
"TwoStepAuth.ResetPendingText" = "You can reset your password in %@.";
"TwoStepAuth.CancelResetTitle" = "Cancel Reset";
"TwoStepAuth.ResetAction" = "Reset Password";
"TwoStepAuth.CancelResetText" = "Cancel the password reset process? If you request a new reset later, it will take another 7 days.";
"TwoStepAuth.RecoveryEmailResetNoAccess" = "Cant access your email?";
"TwoFactorSetup.ResetDone.Title" = "New Password Set!";
"TwoFactorSetup.ResetDone.Text" = "This password will be required when you log in on a new device in addition to the code you get via SMS.";
"TwoFactorSetup.ResetDone.Action" = "Continue";
"TwoFactorSetup.ResetDone.TitleNoPassword" = "Password Removed";
"TwoFactorSetup.ResetDone.TextNoPassword" = "You can always set a new password in\n\n\nSettings>Privacy & Security>Two-Step Verification";
"TwoFactorSetup.ResetFloodWait" = "You recently requested a password reset that was cancelled. Please wait %@ before making a new request.";
"TwoFactorSetup.ResetFloodWait" = "You have recently requested a password reset that was canceled. Please wait for %@ before making a new request.";
"TwoFactorRemember.Title" = "Enter Your Password";
"TwoFactorRemember.Text" = "Do you still remeber your password?";
"TwoFactorRemember.Placeholder" = "Password";
"TwoFactorRemember.Forgot" = "Forgot Password?";
"TwoFactorRemember.CheckPassword" = "Check Password";
"TwoFactorRemember.WrongPassword" = "This password is incorrect.";
"TwoFactorRemember.Done.Title" = "Perfect!";
"TwoFactorRemember.Done.Text" = "You still remember your password.";
"TwoFactorRemember.Done.Action" = "Back to Settings";

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>${APP_NAME}</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>$(PRODUCT_BUNDLE_SHORT_VERSION)</string>
<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widget-extension</string>
<key>NSExtensionPrincipalClass</key>
<string>TodayViewController</string>
</dict>
</dict>
</plist>

View File

@ -1,172 +0,0 @@
import Foundation
import UIKit
import WidgetItems
private extension UIColor {
convenience init(rgb: UInt32) {
self.init(red: CGFloat((rgb >> 16) & 0xff) / 255.0, green: CGFloat((rgb >> 8) & 0xff) / 255.0, blue: CGFloat(rgb & 0xff) / 255.0, alpha: 1.0)
}
}
private let UIScreenScale = UIScreen.main.scale
private func floorToScreenPixels(_ value: CGFloat) -> CGFloat {
return floor(value * UIScreenScale) / UIScreenScale
}
private let gradientColors: [NSArray] = [
[UIColor(rgb: 0xff516a).cgColor, UIColor(rgb: 0xff885e).cgColor],
[UIColor(rgb: 0xffa85c).cgColor, UIColor(rgb: 0xffcd6a).cgColor],
[UIColor(rgb: 0x665fff).cgColor, UIColor(rgb: 0x82b1ff).cgColor],
[UIColor(rgb: 0x54cb68).cgColor, UIColor(rgb: 0xa0de7e).cgColor],
[UIColor(rgb: 0x4acccd).cgColor, UIColor(rgb: 0x00fcfd).cgColor],
[UIColor(rgb: 0x2a9ef1).cgColor, UIColor(rgb: 0x72d5fd).cgColor],
[UIColor(rgb: 0xd669ed).cgColor, UIColor(rgb: 0xe0a2f3).cgColor],
]
private func avatarRoundImage(size: CGSize, source: UIImage) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
let context = UIGraphicsGetCurrentContext()
context?.beginPath()
context?.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
context?.clip()
source.draw(in: CGRect(origin: CGPoint(), size: size))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
private let deviceColorSpace: CGColorSpace = {
if #available(iOSApplicationExtension 9.3, *) {
if let colorSpace = CGColorSpace(name: CGColorSpace.displayP3) {
return colorSpace
} else {
return CGColorSpaceCreateDeviceRGB()
}
} else {
return CGColorSpaceCreateDeviceRGB()
}
}()
private func avatarViewLettersImage(size: CGSize, peerId: Int64, accountPeerId: Int64, letters: [String]) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
let context = UIGraphicsGetCurrentContext()
context?.beginPath()
context?.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
context?.clip()
let colorIndex = abs(Int(accountPeerId + peerId))
let colorsArray = gradientColors[colorIndex % gradientColors.count]
var locations: [CGFloat] = [1.0, 0.0]
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray, locations: &locations)!
context?.drawLinearGradient(gradient, start: CGPoint(), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
context?.setBlendMode(.normal)
let string = letters.count == 0 ? "" : (letters[0] + (letters.count == 1 ? "" : letters[1]))
let attributedString = NSAttributedString(string: string, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 20.0), NSAttributedString.Key.foregroundColor: UIColor.white])
let line = CTLineCreateWithAttributedString(attributedString)
let lineBounds = CTLineGetBoundsWithOptions(line, .useGlyphPathBounds)
let lineOffset = CGPoint(x: string == "B" ? 1.0 : 0.0, y: 0.0)
let lineOrigin = CGPoint(x: floorToScreenPixels(-lineBounds.origin.x + (size.width - lineBounds.size.width) / 2.0) + lineOffset.x, y: floorToScreenPixels(-lineBounds.origin.y + (size.height - lineBounds.size.height) / 2.0))
context?.translateBy(x: size.width / 2.0, y: size.height / 2.0)
context?.scaleBy(x: 1.0, y: -1.0)
context?.translateBy(x: -size.width / 2.0, y: -size.height / 2.0)
context?.translateBy(x: lineOrigin.x, y: lineOrigin.y)
if let context = context {
CTLineDraw(line, context)
}
context?.translateBy(x: -lineOrigin.x, y: -lineOrigin.y)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
private let avatarSize = CGSize(width: 50.0, height: 50.0)
private final class AvatarView: UIImageView {
init(accountPeerId: Int64, peer: WidgetDataPeer, size: CGSize) {
super.init(frame: CGRect())
if let path = peer.avatarPath, let image = UIImage(contentsOfFile: path), let roundImage = avatarRoundImage(size: size, source: image) {
self.image = roundImage
} else {
self.image = avatarViewLettersImage(size: size, peerId: peer.id, accountPeerId: accountPeerId, letters: peer.letters)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
final class PeerView: UIView {
let peer: WidgetDataPeer
private let avatarView: AvatarView
private let titleLabel: UILabel
private let tapped: () -> Void
init(primaryColor: UIColor, accountPeerId: Int64, peer: WidgetDataPeer, tapped: @escaping () -> Void) {
self.peer = peer
self.tapped = tapped
self.avatarView = AvatarView(accountPeerId: accountPeerId, peer: peer, size: avatarSize)
self.titleLabel = UILabel()
var title = peer.name
if let lastName = peer.lastName, !lastName.isEmpty {
title.append("\n")
title.append(lastName)
}
let systemFontSize = UIFont.preferredFont(forTextStyle: .body).pointSize
let fontSize = floor(systemFontSize * 11.0 / 17.0)
self.titleLabel.text = title
if #available(iOSApplicationExtension 13.0, *) {
self.titleLabel.textColor = UIColor.label
} else {
self.titleLabel.textColor = primaryColor
}
self.titleLabel.font = UIFont.systemFont(ofSize: fontSize)
self.titleLabel.lineBreakMode = .byTruncatingTail
self.titleLabel.numberOfLines = 2
self.titleLabel.textAlignment = .center
super.init(frame: CGRect())
self.addSubview(self.avatarView)
self.addSubview(self.titleLabel)
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func updateLayout(size: CGSize) {
self.avatarView.frame = CGRect(origin: CGPoint(x: floor((size.width - avatarSize.width) / 2.0), y: 0.0), size: avatarSize)
var titleSize = self.titleLabel.sizeThatFits(size)
titleSize.width = min(size.width - 6.0, ceil(titleSize.width))
titleSize.height = ceil(titleSize.height)
self.titleLabel.frame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: avatarSize.height + 5.0), size: titleSize)
}
@objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
self.tapped()
}
}
}

View File

@ -1,171 +0,0 @@
import UIKit
import NotificationCenter
import BuildConfig
import WidgetItems
import AppLockState
private func rootPathForBasePath(_ appGroupPath: String) -> String {
return appGroupPath + "/telegram-data"
}
@objc(TodayViewController)
class TodayViewController: UIViewController, NCWidgetProviding {
private var initializedInterface = false
private var buildConfig: BuildConfig?
private var primaryColor: UIColor = .black
private var placeholderLabel: UILabel?
override func viewDidLoad() {
super.viewDidLoad()
let appBundleIdentifier = Bundle.main.bundleIdentifier!
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
return
}
let baseAppBundleId = String(appBundleIdentifier[..<lastDotRange.lowerBound])
let buildConfig = BuildConfig(baseAppBundleId: baseAppBundleId)
self.buildConfig = buildConfig
let appGroupName = "group.\(baseAppBundleId)"
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
guard let appGroupUrl = maybeAppGroupUrl else {
return
}
let rootPath = rootPathForBasePath(appGroupUrl.path)
let presentationData: WidgetPresentationData
if let data = try? Data(contentsOf: URL(fileURLWithPath: widgetPresentationDataPath(rootPath: rootPath))), let value = try? JSONDecoder().decode(WidgetPresentationData.self, from: data) {
presentationData = value
} else {
presentationData = WidgetPresentationData(applicationLockedString: "Unlock the app to use the widget", applicationStartRequiredString: "Open the app to use the widget", widgetGalleryTitle: "", widgetGalleryDescription: "")
}
if let data = try? Data(contentsOf: URL(fileURLWithPath: appLockStatePath(rootPath: rootPath))), let state = try? JSONDecoder().decode(LockState.self, from: data), isAppLocked(state: state) {
self.setPlaceholderText(presentationData.applicationLockedString)
return
}
if self.initializedInterface {
return
}
self.initializedInterface = true
let dataPath = rootPath + "/widget-data"
if let data = try? Data(contentsOf: URL(fileURLWithPath: dataPath)), let widgetData = try? JSONDecoder().decode(WidgetData.self, from: data) {
self.setWidgetData(widgetData: widgetData, presentationData: presentationData)
}
}
private func setPlaceholderText(_ text: String) {
let fontSize = UIFont.preferredFont(forTextStyle: .body).pointSize
let placeholderLabel = UILabel()
if #available(iOSApplicationExtension 13.0, *) {
placeholderLabel.textColor = UIColor.label
} else {
placeholderLabel.textColor = self.primaryColor
}
placeholderLabel.font = UIFont.systemFont(ofSize: fontSize)
placeholderLabel.text = text
placeholderLabel.sizeToFit()
self.placeholderLabel = placeholderLabel
self.view.addSubview(placeholderLabel)
}
func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) {
completionHandler(.newData)
}
@available(iOSApplicationExtension 10.0, *)
func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize) {
}
private var widgetData: WidgetData?
private func setWidgetData(widgetData: WidgetData, presentationData: WidgetPresentationData) {
self.widgetData = widgetData
self.peerViews.forEach {
$0.removeFromSuperview()
}
self.peerViews = []
switch widgetData {
case .notAuthorized, .disabled:
break
case let .peers(peers):
for peer in peers.peers {
let peerView = PeerView(primaryColor: self.primaryColor, accountPeerId: peers.accountPeerId, peer: peer, tapped: { [weak self] in
if let strongSelf = self, let buildConfig = strongSelf.buildConfig {
if let url = URL(string: "\(buildConfig.appSpecificUrlScheme)://localpeer?id=\(peer.id)") {
strongSelf.extensionContext?.open(url, completionHandler: nil)
}
}
})
self.view.addSubview(peerView)
self.peerViews.append(peerView)
}
}
if self.peerViews.isEmpty {
self.setPlaceholderText(presentationData.applicationStartRequiredString)
} else {
self.placeholderLabel?.removeFromSuperview()
self.placeholderLabel = nil
}
if let size = self.validLayout {
self.updateLayout(size: size)
}
}
private var validLayout: CGSize?
private var peerViews: [PeerView] = []
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.updateLayout(size: self.view.bounds.size)
}
private func updateLayout(size: CGSize) {
self.validLayout = size
if let placeholderLabel = self.placeholderLabel {
placeholderLabel.frame = CGRect(origin: CGPoint(x: floor((size.width - placeholderLabel.bounds.width) / 2.0), y: floor((size.height - placeholderLabel.bounds.height) / 2.0)), size: placeholderLabel.bounds.size)
}
let peerSize = CGSize(width: 70.0, height: 100.0)
var peerFrames: [CGRect] = []
var offset: CGFloat = 0.0
for _ in self.peerViews {
let peerFrame = CGRect(origin: CGPoint(x: offset, y: 10.0), size: peerSize)
offset += peerFrame.size.width
if peerFrame.maxX > size.width {
break
}
peerFrames.append(peerFrame)
}
var totalSize: CGFloat = 0.0
for i in 0 ..< peerFrames.count {
totalSize += peerFrames[i].width
}
let spacing: CGFloat = floor((size.width - totalSize) / CGFloat(peerFrames.count))
offset = floor(spacing / 2.0)
for i in 0 ..< peerFrames.count {
let peerView = self.peerViews[i]
peerView.frame = CGRect(origin: CGPoint(x: offset, y: 16.0), size: peerFrames[i].size)
peerView.updateLayout(size: peerFrames[i].size)
offset += peerFrames[i].width + spacing
}
}
}

View File

@ -1,4 +0,0 @@
#ifndef Widget_Bridging_Header_h
#define Widget_Bridging_Header_h
#endif

View File

@ -1 +0,0 @@
"CFBundleDisplayName" = "الأشخاص";

View File

@ -1 +0,0 @@
"CFBundleDisplayName" = "Leute";

View File

@ -1 +0,0 @@
"CFBundleDisplayName" = "People";

View File

@ -1,2 +0,0 @@
"Widget.NoUsers" = "No users here yet...";
"Widget.AuthRequired" = "Open Telegram and log in.";

View File

@ -1 +0,0 @@
"CFBundleDisplayName" = "Personas";

View File

@ -1 +0,0 @@
"CFBundleDisplayName" = "Persone";

View File

@ -1 +0,0 @@
"CFBundleDisplayName" = "사람";

View File

@ -1 +0,0 @@
"CFBundleDisplayName" = "Mensen";

View File

@ -1 +0,0 @@
"CFBundleDisplayName" = "Pessoas";

View File

@ -1 +0,0 @@
"CFBundleDisplayName" = "Люди";

View File

@ -92,7 +92,7 @@ private func getCommonTimeline(friends: [Friend]?, in context: TimelineProviderC
let rootPath = rootPathForBasePath(appGroupUrl.path)
TempBox.initializeShared(basePath: rootPath, processType: "widget", launchSpecificId: arc4random64())
TempBox.initializeShared(basePath: rootPath, processType: "widget", launchSpecificId: Int64.random(in: Int64.min ... Int64.max))
let logsPath = rootPath + "/widget-logs"
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
@ -130,7 +130,7 @@ private func getCommonTimeline(friends: [Friend]?, in context: TimelineProviderC
var friendsByAccount: [Signal<[ParsedPeer], NoError>] = []
for (accountId, items) in itemsByAccount {
friendsByAccount.append(accountTransaction(rootPath: rootPath, id: AccountRecordId(rawValue: accountId), encryptionParameters: encryptionParameters, isReadOnly: true, useCopy: true, transaction: { postbox, transaction -> [ParsedPeer] in
friendsByAccount.append(accountTransaction(rootPath: rootPath, id: AccountRecordId(rawValue: accountId), encryptionParameters: encryptionParameters, isReadOnly: true, useCopy: false, transaction: { postbox, transaction -> [ParsedPeer] in
guard let state = transaction.getState() as? AuthorizedAccountState else {
return []
}

View File

@ -56,3 +56,10 @@ http_file(
urls = ["https://github.com/Kitware/CMake/releases/download/v3.19.2/cmake-3.19.2-macos-universal.tar.gz"],
sha256 = "50afa2cb66bea6a0314ef28034f3ff1647325e30cf5940f97906a56fd9640bd8",
)
http_archive(
name = "appcenter_sdk",
urls = ["https://github.com/microsoft/appcenter-sdk-apple/releases/download/4.1.1/AppCenter-SDK-Apple-4.1.1.zip"],
sha256 = "032907801dc7784744a1ca8fd40d3eecc34a2e27a93a4b3993f617cca204a9f3",
build_file = "@//third-party/AppCenter:AppCenter.BUILD",
)

View File

@ -106,6 +106,15 @@ class BazelCommandLine:
def set_build_number(self, build_number):
self.build_number = build_number
def set_custom_target(self, target_name):
self.custom_target = target_name
def set_continue_on_error(self, continue_on_error):
self.continue_on_error = continue_on_error
def set_enable_sandbox(self, enable_sandbox):
self.enable_sandbox = enable_sandbox
def set_split_swiftmodules(self, value):
self.split_submodules = value
@ -260,10 +269,18 @@ class BazelCommandLine:
self.build_environment.bazel_path
]
combined_arguments += self.get_startup_bazel_arguments()
combined_arguments += [
'build',
'Telegram/Telegram'
]
combined_arguments += ['build']
if self.custom_target is not None:
combined_arguments += [self.custom_target]
else:
combined_arguments += ['Telegram/Telegram']
if self.continue_on_error:
combined_arguments += ['--keep_going']
if self.enable_sandbox:
combined_arguments += ['--spawn_strategy=sandboxed']
if self.configuration_path is None:
raise Exception('configuration_path is not defined')
@ -353,10 +370,15 @@ def generate_project(arguments):
bazel_command_line.set_build_number(arguments.buildNumber)
disable_extensions = False
disable_provisioning_profiles = False
generate_dsym = False
if arguments.disableExtensions is not None:
disable_extensions = arguments.disableExtensions
if arguments.disableProvisioningProfiles is not None:
disable_provisioning_profiles = arguments.disableProvisioningProfiles
if arguments.generateDsym is not None:
generate_dsym = arguments.generateDsym
call_executable(['killall', 'Xcode'], check_result=False)
@ -364,6 +386,7 @@ def generate_project(arguments):
build_environment=bazel_command_line.build_environment,
disable_extensions=disable_extensions,
disable_provisioning_profiles=disable_provisioning_profiles,
generate_dsym=generate_dsym,
configuration_path=bazel_command_line.configuration_path,
bazel_app_arguments=bazel_command_line.get_project_generation_arguments()
)
@ -386,6 +409,9 @@ def build(arguments):
bazel_command_line.set_configuration(arguments.configuration)
bazel_command_line.set_build_number(arguments.buildNumber)
bazel_command_line.set_custom_target(arguments.target)
bazel_command_line.set_continue_on_error(arguments.continueOnError)
bazel_command_line.set_enable_sandbox(arguments.sandbox)
bazel_command_line.set_split_swiftmodules(not arguments.disableParallelSwiftmoduleGeneration)
@ -512,6 +538,15 @@ if __name__ == '__main__':
'''
)
generateProjectParser.add_argument(
'--generateDsym',
action='store_true',
default=False,
help='''
This improves profiling experinence by generating DSYM files. Keep disabled for better build performance.
'''
)
buildParser = subparsers.add_parser('build', help='Build the app')
buildParser.add_argument(
'--buildNumber',
@ -540,6 +575,24 @@ if __name__ == '__main__':
default=False,
help='Generate .swiftmodule files in parallel to building modules, can speed up compilation on multi-core systems.'
)
buildParser.add_argument(
'--target',
type=str,
help='A custom bazel target name to build.',
metavar='target_name'
)
buildParser.add_argument(
'--continueOnError',
action='store_true',
default=False,
help='Continue build process after an error.',
)
buildParser.add_argument(
'--sandbox',
action='store_true',
default=False,
help='Enable sandbox.',
)
if len(sys.argv) < 2:
parser.print_help()

View File

@ -10,7 +10,7 @@ def remove_directory(path):
shutil.rmtree(path)
def generate(build_environment: BuildEnvironment, disable_extensions, disable_provisioning_profiles, configuration_path, bazel_app_arguments):
def generate(build_environment: BuildEnvironment, disable_extensions, disable_provisioning_profiles, generate_dsym, configuration_path, bazel_app_arguments):
project_path = os.path.join(build_environment.base_path, 'build-input/gen/project')
app_target = 'Telegram'
@ -81,6 +81,8 @@ def generate(build_environment: BuildEnvironment, disable_extensions, disable_pr
bazel_build_arguments += ['--//Telegram:disableExtensions']
if disable_provisioning_profiles:
bazel_build_arguments += ['--//Telegram:disableProvisioningProfiles']
if generate_dsym:
bazel_build_arguments += ['--apple_generate_dsym']
call_executable([
tulsi_path,

View File

@ -8,4 +8,5 @@ exports_files([
"WatchApp.mobileprovision",
"WatchExtension.mobileprovision",
"Widget.mobileprovision",
"BroadcastUpload.mobileprovision",
])

1
build_number_offset Normal file
View File

@ -0,0 +1 @@
2300

View File

@ -79,7 +79,8 @@ COMMIT_ID="$(git rev-parse HEAD)"
COMMIT_AUTHOR=$(git log -1 --pretty=format:'%an')
if [ -z "$2" ]; then
COMMIT_COUNT=$(git rev-list --count HEAD)
COMMIT_COUNT="$(($COMMIT_COUNT+2000))"
BUILD_NUMBER_OFFSET="$(cat build_number_offset)"
COMMIT_COUNT="$(($COMMIT_COUNT+$BUILD_NUMBER_OFFSET))"
BUILD_NUMBER="$COMMIT_COUNT"
else
BUILD_NUMBER="$2"

View File

@ -3,84 +3,11 @@
set -e
set -x
API_HOST="https://api.appcenter.ms"
IPA_PATH="build/artifacts/Telegram.ipa"
DSYM_PATH="build/artifacts/Telegram.DSYMs.zip"
upload_ipa() {
GROUP_DATA=$(curl \
-X GET \
--header "X-API-Token: $API_TOKEN" \
"$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/distribution_groups/Internal" \
)
GROUP_ID=$(echo "$GROUP_DATA" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["id"];')
UPLOAD_TOKEN=$(curl \
-X POST \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-API-Token: $API_TOKEN" \
"$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/release_uploads" \
)
UPLOAD_URL=$(echo "$UPLOAD_TOKEN" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["upload_url"];')
UPLOAD_ID=$(echo "$UPLOAD_TOKEN" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["upload_id"];')
curl --progress-bar -F "ipa=@${IPA_PATH}" "$UPLOAD_URL"
RELEASE_TOKEN=$(curl \
-X PATCH \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-API-Token: $API_TOKEN" \
-d '{ "status": "committed" }' \
"$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/release_uploads/$UPLOAD_ID" \
)
RELEASE_URL=$(echo "$RELEASE_TOKEN" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["release_url"];')
RELEASE_ID=$(echo "$RELEASE_TOKEN" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["release_id"];')
curl \
-X POST \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-API-Token: $API_TOKEN" \
-d "{ \"id\": \"$GROUP_ID\", \"mandatory_update\": false, \"notify_testers\": false }" \
"$API_HOST/$RELEASE_URL/groups"
}
upload_dsym() {
UPLOAD_DSYM_DATA=$(curl \
-X POST \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-API-Token: $API_TOKEN" \
-d "{ \"symbol_type\": \"Apple\"}" \
"$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/symbol_uploads" \
)
DSYM_UPLOAD_URL=$(echo "$UPLOAD_DSYM_DATA" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["upload_url"];')
DSYM_UPLOAD_ID=$(echo "$UPLOAD_DSYM_DATA" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["symbol_upload_id"];')
curl \
--progress-bar \
--header "x-ms-blob-type: BlockBlob" \
--upload-file "${DSYM_PATH}" \
"$DSYM_UPLOAD_URL"
curl \
-X PATCH \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--header "X-API-Token: $API_TOKEN" \
-d '{ "status": "committed" }' \
"$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/symbol_uploads/$DSYM_UPLOAD_ID"
}
APPCENTER="/usr/local/bin/appcenter"
$APPCENTER login --token "$API_TOKEN"
$APPCENTER distribute release --app "$API_USER_NAME/$API_APP_NAME" -f "$IPA_PATH" -g Internal
$APPCENTER crashes upload-symbols --app "$API_USER_NAME/$API_APP_NAME" --symbol "$DSYM_PATH"

View File

@ -30,6 +30,7 @@ public enum AccessType {
public final class TelegramApplicationBindings {
public let isMainApp: Bool
public let appBundleId: String
public let containerPath: String
public let appSpecificScheme: String
public let openUrl: (String) -> Void
@ -52,9 +53,11 @@ public final class TelegramApplicationBindings {
public let getAvailableAlternateIcons: () -> [PresentationAppIcon]
public let getAlternateIconName: () -> String?
public let requestSetAlternateIconName: (String?, @escaping (Bool) -> Void) -> Void
public let forceOrientation: (UIInterfaceOrientation) -> Void
public init(isMainApp: Bool, containerPath: String, appSpecificScheme: String, openUrl: @escaping (String) -> Void, openUniversalUrl: @escaping (String, TelegramApplicationOpenUrlCompletion) -> Void, canOpenUrl: @escaping (String) -> Bool, getTopWindow: @escaping () -> UIWindow?, displayNotification: @escaping (String) -> Void, applicationInForeground: Signal<Bool, NoError>, applicationIsActive: Signal<Bool, NoError>, clearMessageNotifications: @escaping ([MessageId]) -> Void, pushIdleTimerExtension: @escaping () -> Disposable, openSettings: @escaping () -> Void, openAppStorePage: @escaping () -> Void, registerForNotifications: @escaping (@escaping (Bool) -> Void) -> Void, requestSiriAuthorization: @escaping (@escaping (Bool) -> Void) -> Void, siriAuthorization: @escaping () -> AccessType, getWindowHost: @escaping () -> WindowHost?, presentNativeController: @escaping (UIViewController) -> Void, dismissNativeController: @escaping () -> Void, getAvailableAlternateIcons: @escaping () -> [PresentationAppIcon], getAlternateIconName: @escaping () -> String?, requestSetAlternateIconName: @escaping (String?, @escaping (Bool) -> Void) -> Void) {
public init(isMainApp: Bool, appBundleId: String, containerPath: String, appSpecificScheme: String, openUrl: @escaping (String) -> Void, openUniversalUrl: @escaping (String, TelegramApplicationOpenUrlCompletion) -> Void, canOpenUrl: @escaping (String) -> Bool, getTopWindow: @escaping () -> UIWindow?, displayNotification: @escaping (String) -> Void, applicationInForeground: Signal<Bool, NoError>, applicationIsActive: Signal<Bool, NoError>, clearMessageNotifications: @escaping ([MessageId]) -> Void, pushIdleTimerExtension: @escaping () -> Disposable, openSettings: @escaping () -> Void, openAppStorePage: @escaping () -> Void, registerForNotifications: @escaping (@escaping (Bool) -> Void) -> Void, requestSiriAuthorization: @escaping (@escaping (Bool) -> Void) -> Void, siriAuthorization: @escaping () -> AccessType, getWindowHost: @escaping () -> WindowHost?, presentNativeController: @escaping (UIViewController) -> Void, dismissNativeController: @escaping () -> Void, getAvailableAlternateIcons: @escaping () -> [PresentationAppIcon], getAlternateIconName: @escaping () -> String?, requestSetAlternateIconName: @escaping (String?, @escaping (Bool) -> Void) -> Void, forceOrientation: @escaping (UIInterfaceOrientation) -> Void) {
self.isMainApp = isMainApp
self.appBundleId = appBundleId
self.containerPath = containerPath
self.appSpecificScheme = appSpecificScheme
self.openUrl = openUrl
@ -77,6 +80,7 @@ public final class TelegramApplicationBindings {
self.getAvailableAlternateIcons = getAvailableAlternateIcons
self.getAlternateIconName = getAlternateIconName
self.requestSetAlternateIconName = requestSetAlternateIconName
self.forceOrientation = forceOrientation
}
}
@ -150,9 +154,9 @@ public struct ChatAvailableMessageActions {
}
public enum WallpaperUrlParameter {
case slug(String, WallpaperPresentationOptions, UIColor?, UIColor?, Int32?, Int32?)
case slug(String, WallpaperPresentationOptions, [UInt32], Int32?, Int32?)
case color(UIColor)
case gradient(UIColor, UIColor, Int32?)
case gradient([UInt32], Int32?)
}
public enum ResolvedUrlSettingsSection {
@ -167,7 +171,7 @@ public enum ResolvedUrl {
case inaccessiblePeer
case botStart(peerId: PeerId, payload: String)
case groupBotStart(peerId: PeerId, payload: String)
case channelMessage(peerId: PeerId, messageId: MessageId)
case channelMessage(peerId: PeerId, messageId: MessageId, timecode: Double?)
case replyThreadMessage(replyThreadMessage: ChatReplyThreadMessage, messageId: MessageId)
case stickerPack(name: String)
case instantView(TelegramMediaWebpage, String?)
@ -184,6 +188,7 @@ public enum ResolvedUrl {
#endif
case settings(ResolvedUrlSettingsSection)
case joinVoiceChat(PeerId, String?)
case importStickers
}
public enum NavigateToChatKeepStack {
@ -216,17 +221,14 @@ public final class ChatPeerNearbyData: Equatable {
public final class ChatGreetingData: Equatable {
public static func == (lhs: ChatGreetingData, rhs: ChatGreetingData) -> Bool {
if let lhsSticker = lhs.sticker, let rhsSticker = rhs.sticker, !lhsSticker.isEqual(to: rhsSticker) {
return false
} else if (lhs.sticker == nil) != (rhs.sticker == nil) {
return false
}
return true
return lhs.uuid == rhs.uuid
}
public let sticker: TelegramMediaFile?
public let uuid: UUID
public let sticker: Signal<TelegramMediaFile?, NoError>
public init(sticker: TelegramMediaFile?) {
public init(uuid: UUID, sticker: Signal<TelegramMediaFile?, NoError>) {
self.uuid = uuid
self.sticker = sticker
}
}
@ -282,14 +284,13 @@ public final class NavigateToChatControllerParams {
public let activateMessageSearch: (ChatSearchDomain, String)?
public let peekData: ChatPeekTimeout?
public let peerNearbyData: ChatPeerNearbyData?
public let greetingData: ChatGreetingData?
public let reportReason: ReportReason?
public let animated: Bool
public let options: NavigationAnimationOptions
public let parentGroupId: PeerGroupId?
public let completion: (ChatController) -> Void
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: Bool = false, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, greetingData: ChatGreetingData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, completion: @escaping (ChatController) -> Void = { _ in }) {
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: Bool = false, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, completion: @escaping (ChatController) -> Void = { _ in }) {
self.navigationController = navigationController
self.chatController = chatController
self.chatLocationContextHolder = chatLocationContextHolder
@ -306,7 +307,6 @@ public final class NavigateToChatControllerParams {
self.activateMessageSearch = activateMessageSearch
self.peekData = peekData
self.peerNearbyData = peerNearbyData
self.greetingData = greetingData
self.reportReason = reportReason
self.animated = animated
self.options = options
@ -471,15 +471,17 @@ public final class ContactSelectionControllerParams {
public let options: [ContactListAdditionalOption]
public let displayDeviceContacts: Bool
public let displayCallIcons: Bool
public let multipleSelection: Bool
public let confirmation: (ContactListPeer) -> Signal<Bool, NoError>
public init(context: AccountContext, autoDismiss: Bool = true, title: @escaping (PresentationStrings) -> String, options: [ContactListAdditionalOption] = [], displayDeviceContacts: Bool = false, displayCallIcons: Bool = false, confirmation: @escaping (ContactListPeer) -> Signal<Bool, NoError> = { _ in .single(true) }) {
public init(context: AccountContext, autoDismiss: Bool = true, title: @escaping (PresentationStrings) -> String, options: [ContactListAdditionalOption] = [], displayDeviceContacts: Bool = false, displayCallIcons: Bool = false, multipleSelection: Bool = false, confirmation: @escaping (ContactListPeer) -> Signal<Bool, NoError> = { _ in .single(true) }) {
self.context = context
self.autoDismiss = autoDismiss
self.title = title
self.options = options
self.displayDeviceContacts = displayDeviceContacts
self.displayCallIcons = displayCallIcons
self.multipleSelection = multipleSelection
self.confirmation = confirmation
}
}
@ -509,7 +511,7 @@ public enum ChatListSearchFilter: Equatable {
case .voice:
return 5
case let .peer(peerId, _, _, _):
return peerId.id
return peerId.id._internalGetInt32Value()
case let .date(_, date, _):
return date
}
@ -544,6 +546,7 @@ public protocol RecentSessionsController: class {
}
public protocol SharedAccountContext: class {
var sharedContainerPath: String { get }
var basePath: String { get }
var mainWindow: Window1? { get }
var accountManager: AccountManager { get }
@ -588,7 +591,7 @@ public protocol SharedAccountContext: class {
func makeComposeController(context: AccountContext) -> ViewController
func makeChatListController(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool, previewing: Bool, enableDebugActions: Bool) -> ChatListController
func makeChatController(context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject?, botStart: ChatControllerInitialBotStart?, mode: ChatControllerPresentationMode) -> ChatController
func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)?) -> ListViewItem
func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)?, backgroundNode: ASDisplayNode?) -> ListViewItem
func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader
func makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController?
func makeContactSelectionController(_ params: ContactSelectionControllerParams) -> ContactSelectionController
@ -604,7 +607,7 @@ public protocol SharedAccountContext: class {
func openExternalUrl(context: AccountContext, urlContext: OpenURLContext, url: String, forceExternal: Bool, presentationData: PresentationData, navigationController: NavigationController?, dismissInput: @escaping () -> Void)
func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messageIds: Set<MessageId>) -> Signal<ChatAvailableMessageActions, NoError>
func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messageIds: Set<MessageId>, messages: [MessageId: Message], peers: [PeerId: Peer]) -> Signal<ChatAvailableMessageActions, NoError>
func resolveUrl(account: Account, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError>
func resolveUrl(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError>
func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?)
func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)
func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void)
@ -709,10 +712,12 @@ public protocol AccountGroupCallContextCache: class {
public protocol AccountContext: class {
var sharedContext: SharedAccountContext { get }
var account: Account { get }
var engine: TelegramEngine { get }
var liveLocationManager: LiveLocationManager? { get }
var peersNearbyManager: PeersNearbyManager? { get }
var fetchManager: FetchManager { get }
var prefetchManager: PrefetchManager? { get }
var downloadedMediaStoreManager: DownloadedMediaStoreManager { get }
var peerChannelMemberCategoriesContextsManager: PeerChannelMemberCategoriesContextsManager { get }
var wallpaperUploadManager: WallpaperUploadManager? { get }
@ -731,6 +736,7 @@ public protocol AccountContext: class {
func chatLocationOutgoingReadState(for location: ChatLocation, contextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<MessageId?, NoError>
func applyMaxReadIndex(for location: ChatLocation, contextHolder: Atomic<ChatLocationContextHolder?>, messageIndex: MessageIndex)
func scheduleGroupCall(peerId: PeerId)
func joinGroupCall(peerId: PeerId, invite: String?, requestJoinAsPeerId: ((@escaping (PeerId?) -> Void) -> Void)?, activeCall: CachedChannelData.ActiveCall)
func requestCall(peerId: PeerId, isVideo: Bool, completion: @escaping () -> Void)
}

Some files were not shown because too many files have changed in this diff Show More