mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
bed5daf934
16
README.md
16
README.md
@ -17,7 +17,7 @@ There are several things we require from **all developers** for the moment.
|
||||
2. Clone the project from GitHub:
|
||||
|
||||
```
|
||||
git clone --recursive https://github.com/TelegramMessenger/Telegram-iOS.git
|
||||
git clone --recursive -j8 https://github.com/TelegramMessenger/Telegram-iOS.git
|
||||
```
|
||||
|
||||
3. Download Bazel 3.7.0
|
||||
@ -75,7 +75,19 @@ python3 build-system/Make/Make.py \
|
||||
--disableExtensions
|
||||
```
|
||||
|
||||
Tip: use `--disableExtensions` when developing to speed up development by not building application extensions.
|
||||
It is possible to generate a project that does not require any codesigning certificates to be installed: add `--disableProvisioningProfiles` flag:
|
||||
```
|
||||
python3 build-system/Make/Make.py \
|
||||
--bazel="$HOME/bazel-dist/bazel" \
|
||||
--cacheDir="$HOME/telegram-bazel-cache" \
|
||||
generateProject \
|
||||
--configurationPath="$HOME/telegram-configuration" \
|
||||
--disableExtensions \
|
||||
--disableProvisioningProfiles
|
||||
```
|
||||
|
||||
|
||||
Tip: use `--disableExtensions` when developing to speed up development by not building application extensions and the WatchOS app.
|
||||
|
||||
|
||||
# Tips
|
||||
|
@ -41,6 +41,12 @@ bool_flag(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
bool_flag(
|
||||
name = "disableProvisioningProfiles",
|
||||
build_setting_default = False,
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "disableExtensionsSetting",
|
||||
flag_values = {
|
||||
@ -48,6 +54,13 @@ config_setting(
|
||||
},
|
||||
)
|
||||
|
||||
config_setting(
|
||||
name = "disableProvisioningProfilesSetting",
|
||||
flag_values = {
|
||||
":disableProvisioningProfiles": "True",
|
||||
},
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "empty",
|
||||
outs = ["empty.swift"],
|
||||
@ -277,6 +290,12 @@ official_unrestricted_voip_fragment = """
|
||||
"""
|
||||
unrestricted_voip_fragment = official_unrestricted_voip_fragment if telegram_bundle_id in official_bundle_ids else ""
|
||||
|
||||
official_carplay_fragment = """
|
||||
<key>com.apple.developer.carplay-messaging</key>
|
||||
<true/>
|
||||
"""
|
||||
carplay_fragment = official_carplay_fragment if telegram_bundle_id in official_bundle_ids else ""
|
||||
|
||||
telegram_entitlements_template = """
|
||||
<key>com.apple.developer.icloud-services</key>
|
||||
<array>
|
||||
@ -304,7 +323,7 @@ telegram_entitlements_template = """
|
||||
<string>{telegram_team_id}.{telegram_bundle_id}</string>
|
||||
<key>com.apple.developer.icloud-container-environment</key>
|
||||
<string>{telegram_icloud_environment}</string>
|
||||
""" + apple_pay_merchants_fragment + unrestricted_voip_fragment
|
||||
""" + apple_pay_merchants_fragment + unrestricted_voip_fragment + carplay_fragment
|
||||
|
||||
plist_fragment(
|
||||
name = "TelegramEntitlements",
|
||||
@ -486,7 +505,10 @@ watchos_extension(
|
||||
":WatchExtensionNSExtensionInfoPlist",
|
||||
],
|
||||
minimum_os_version = "5.0",
|
||||
provisioning_profile = "@build_configuration//provisioning:WatchExtension.mobileprovision",
|
||||
provisioning_profile = select({
|
||||
":disableProvisioningProfilesSetting": None,
|
||||
"//conditions:default": "@build_configuration//provisioning:WatchExtension.mobileprovision",
|
||||
}),
|
||||
resources = [
|
||||
":TelegramWatchExtensionResources",
|
||||
],
|
||||
@ -514,7 +536,10 @@ watchos_application(
|
||||
":WatchAppCompanionInfoPlist",
|
||||
],
|
||||
minimum_os_version = "5.0",
|
||||
provisioning_profile = "@build_configuration//provisioning:WatchApp.mobileprovision",
|
||||
provisioning_profile = select({
|
||||
":disableProvisioningProfilesSetting": None,
|
||||
"//conditions:default": "@build_configuration//provisioning:WatchApp.mobileprovision",
|
||||
}),
|
||||
resources = [
|
||||
":TelegramWatchAppResources",
|
||||
":TelegramWatchAppAssets",
|
||||
@ -1023,7 +1048,10 @@ ios_extension(
|
||||
":AppNameInfoPlist",
|
||||
],
|
||||
minimum_os_version = "9.0",
|
||||
provisioning_profile = "@build_configuration//provisioning:Share.mobileprovision",
|
||||
provisioning_profile = select({
|
||||
":disableProvisioningProfilesSetting": None,
|
||||
"//conditions:default": "@build_configuration//provisioning:Share.mobileprovision",
|
||||
}),
|
||||
deps = [":ShareExtensionLib"],
|
||||
frameworks = [
|
||||
":TelegramUIFramework"
|
||||
@ -1092,7 +1120,10 @@ ios_extension(
|
||||
":AppNameInfoPlist",
|
||||
],
|
||||
minimum_os_version = "10.0",
|
||||
provisioning_profile = "@build_configuration//provisioning:NotificationContent.mobileprovision",
|
||||
provisioning_profile = select({
|
||||
":disableProvisioningProfilesSetting": None,
|
||||
"//conditions:default": "@build_configuration//provisioning:NotificationContent.mobileprovision",
|
||||
}),
|
||||
deps = [":NotificationContentExtensionLib"],
|
||||
frameworks = [
|
||||
":TelegramUIFramework"
|
||||
@ -1175,7 +1206,10 @@ ios_extension(
|
||||
],
|
||||
minimum_os_version = "14.0",
|
||||
provides_main = True,
|
||||
provisioning_profile = "@build_configuration//provisioning:Widget.mobileprovision",
|
||||
provisioning_profile = select({
|
||||
":disableProvisioningProfilesSetting": None,
|
||||
"//conditions:default": "@build_configuration//provisioning:Widget.mobileprovision",
|
||||
}),
|
||||
deps = [":WidgetExtensionLib"],
|
||||
frameworks = [
|
||||
":SwiftSignalKitFramework",
|
||||
@ -1264,7 +1298,10 @@ ios_extension(
|
||||
":AppNameInfoPlist",
|
||||
],
|
||||
minimum_os_version = "10.0",
|
||||
provisioning_profile = "@build_configuration//provisioning:Intents.mobileprovision",
|
||||
provisioning_profile = select({
|
||||
":disableProvisioningProfilesSetting": None,
|
||||
"//conditions:default": "@build_configuration//provisioning:Intents.mobileprovision",
|
||||
}),
|
||||
deps = [":IntentsExtensionLib"],
|
||||
frameworks = [
|
||||
":SwiftSignalKitFramework",
|
||||
@ -1315,7 +1352,10 @@ ios_extension(
|
||||
":AppNameInfoPlist",
|
||||
],
|
||||
minimum_os_version = "10.0",
|
||||
provisioning_profile = "@build_configuration//provisioning:NotificationService.mobileprovision",
|
||||
provisioning_profile = select({
|
||||
":disableProvisioningProfilesSetting": None,
|
||||
"//conditions:default": "@build_configuration//provisioning:NotificationService.mobileprovision",
|
||||
}),
|
||||
deps = ["//Telegram/NotificationService:NotificationServiceExtensionLib"],
|
||||
frameworks = [
|
||||
":MtProtoKitFramework",
|
||||
@ -1501,7 +1541,10 @@ ios_application(
|
||||
),
|
||||
families = ["iphone", "ipad"],
|
||||
minimum_os_version = "9.0",
|
||||
provisioning_profile = "@build_configuration//provisioning:Telegram.mobileprovision",
|
||||
provisioning_profile = select({
|
||||
":disableProvisioningProfilesSetting": None,
|
||||
"//conditions:default": "@build_configuration//provisioning:Telegram.mobileprovision",
|
||||
}),
|
||||
entitlements = ":TelegramEntitlements.entitlements",
|
||||
infoplists = [
|
||||
":TelegramInfoPlist",
|
||||
@ -1538,7 +1581,10 @@ ios_application(
|
||||
# ":WidgetExtension",
|
||||
],
|
||||
}),
|
||||
watch_application = ":TelegramWatchApp",
|
||||
watch_application = select({
|
||||
":disableExtensionsSetting": None,
|
||||
"//conditions:default": ":TelegramWatchApp",
|
||||
}),
|
||||
deps = [
|
||||
":Main",
|
||||
":Lib",
|
||||
|
@ -4276,7 +4276,9 @@ Unused sets are archived when you add more.";
|
||||
"ChatList.DeleteForEveryoneConfirmationText" = "This will **delete all messages** in this chat for **both participants**.";
|
||||
"ChatList.DeleteForEveryoneConfirmationAction" = "Delete All";
|
||||
"ChatList.DeleteForAllMembers" = "Delete for all members";
|
||||
"ChatList.DeleteForAllSubscribers" = "Delete for all subscribers";
|
||||
"ChatList.DeleteForAllMembersConfirmationText" = "This will **delete all messages** in this chat for **all participants**.";
|
||||
"ChatList.DeleteForAllSubscribersConfirmationText" = "This will **delete all messages** in this channel for **all subscribers**.";
|
||||
|
||||
"ChatList.DeleteSavedMessagesConfirmationTitle" = "Warning!";
|
||||
"ChatList.DeleteSavedMessagesConfirmationText" = "This will **delete all messages** in this chat.";
|
||||
|
@ -297,12 +297,15 @@ def generate_project(arguments):
|
||||
disable_extensions = False
|
||||
if arguments.disableExtensions is not None:
|
||||
disable_extensions = arguments.disableExtensions
|
||||
|
||||
if arguments.disableProvisioningProfiles is not None:
|
||||
disable_provisioning_profiles = arguments.disableProvisioningProfiles
|
||||
|
||||
call_executable(['killall', 'Xcode'], check_result=False)
|
||||
|
||||
generate(
|
||||
build_environment=bazel_command_line.build_environment,
|
||||
disable_extensions=disable_extensions,
|
||||
disable_provisioning_profiles=disable_provisioning_profiles,
|
||||
configuration_path=bazel_command_line.configuration_path,
|
||||
bazel_app_arguments=bazel_command_line.get_project_generation_arguments()
|
||||
)
|
||||
@ -439,6 +442,16 @@ if __name__ == '__main__':
|
||||
'''
|
||||
)
|
||||
|
||||
generateProjectParser.add_argument(
|
||||
'--disableProvisioningProfiles',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='''
|
||||
This allows to build the project for simulator without having any codesigning identities installed.
|
||||
Building for an actual device will fail.
|
||||
'''
|
||||
)
|
||||
|
||||
buildParser = subparsers.add_parser('build', help='Build the app')
|
||||
buildParser.add_argument(
|
||||
'--buildNumber',
|
||||
|
@ -10,7 +10,7 @@ def remove_directory(path):
|
||||
shutil.rmtree(path)
|
||||
|
||||
|
||||
def generate(build_environment: BuildEnvironment, disable_extensions, configuration_path, bazel_app_arguments):
|
||||
def generate(build_environment: BuildEnvironment, disable_extensions, disable_provisioning_profiles, configuration_path, bazel_app_arguments):
|
||||
project_path = os.path.join(build_environment.base_path, 'build-input/gen/project')
|
||||
app_target = 'Telegram'
|
||||
|
||||
@ -43,8 +43,6 @@ def generate(build_environment: BuildEnvironment, disable_extensions, configurat
|
||||
|
||||
bazel_wrapper_arguments = []
|
||||
bazel_wrapper_arguments += ['--override_repository=build_configuration={}'.format(configuration_path)]
|
||||
if disable_extensions and False:
|
||||
bazel_wrapper_arguments += ['--//Telegram:disableExtensions']
|
||||
|
||||
with open(bazel_wrapper_path, 'wb') as bazel_wrapper:
|
||||
bazel_wrapper.write('''#!/bin/sh
|
||||
@ -82,6 +80,8 @@ def generate(build_environment: BuildEnvironment, disable_extensions, configurat
|
||||
bazel_build_arguments += ['--override_repository=build_configuration={}'.format(configuration_path)]
|
||||
if disable_extensions:
|
||||
bazel_build_arguments += ['--//Telegram:disableExtensions']
|
||||
if disable_provisioning_profiles:
|
||||
bazel_build_arguments += ['--//Telegram:disableProvisioningProfiles']
|
||||
|
||||
call_executable([
|
||||
tulsi_path,
|
||||
|
@ -146,7 +146,7 @@ API_AVAILABLE(ios(10))
|
||||
dataDict[@"device_token"] = [appToken base64EncodedStringWithOptions:0];
|
||||
dataDict[@"device_token_type"] = @"voip";
|
||||
}
|
||||
float tzOffset = ([[NSTimeZone systemTimeZone] secondsFromGMT] / 3600.0);
|
||||
float tzOffset = [[NSTimeZone systemTimeZone] secondsFromGMT];
|
||||
dataDict[@"tz_offset"] = @((int)tzOffset);
|
||||
if (signatureDict != nil) {
|
||||
for (id<NSCopying> key in signatureDict.allKeys) {
|
||||
|
@ -23,6 +23,7 @@ swift_library(
|
||||
"//submodules/ChatHistoryImportTasks:ChatHistoryImportTasks",
|
||||
"//submodules/MimeTypes:MimeTypes",
|
||||
"//submodules/ConfettiEffect:ConfettiEffect",
|
||||
"//submodules/TelegramUniversalVideoContent:TelegramUniversalVideoContent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -14,8 +14,15 @@ import AppBundle
|
||||
import ZIPFoundation
|
||||
import MimeTypes
|
||||
import ConfettiEffect
|
||||
import TelegramUniversalVideoContent
|
||||
|
||||
public final class ChatImportActivityScreen: ViewController {
|
||||
private enum State {
|
||||
case progress(CGFloat)
|
||||
case error
|
||||
case done
|
||||
}
|
||||
|
||||
private final class Node: ViewControllerTracingNode {
|
||||
private weak var controller: ChatImportActivityScreen?
|
||||
|
||||
@ -36,10 +43,10 @@ public final class ChatImportActivityScreen: ViewController {
|
||||
|
||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
private var totalProgress: CGFloat = 0.0
|
||||
private let totalBytes: Int
|
||||
private var isDone: Bool = false
|
||||
private var state: State = .progress(0.0)
|
||||
|
||||
private var videoNode: UniversalVideoNode?
|
||||
private var feedback: HapticFeedback?
|
||||
|
||||
init(controller: ChatImportActivityScreen, context: AccountContext, totalBytes: Int) {
|
||||
@ -138,10 +145,32 @@ public final class ChatImportActivityScreen: ViewController {
|
||||
strongSelf.doneAnimationNode.visibility = true
|
||||
strongSelf.doneAnimationNode.isHidden = false
|
||||
}
|
||||
|
||||
if let path = getAppBundle().path(forResource: "BlankVideo", ofType: "m4v"), let size = fileSize(path) {
|
||||
let decoration = ChatBubbleVideoDecoration(corners: ImageCorners(), nativeSize: CGSize(width: 100.0, height: 100.0), contentMode: .aspectFit, backgroundColor: .black)
|
||||
|
||||
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: LocalFileReferenceMediaResource(localFilePath: path, randomId: 12345), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: size, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
|
||||
|
||||
let videoContent = NativeVideoContent(id: .message(1, MediaId(namespace: 0, id: 1)), fileReference: .standalone(media: dummyFile), streamVideo: .none, loopVideo: true, enableSound: false, fetchAutomatically: true, onlyFullSizeThumbnail: false, continuePlayingWithoutSoundOnLostAudioSession: false, placeholderColor: .black)
|
||||
|
||||
let videoNode = UniversalVideoNode(postbox: context.account.postbox, audioSession: context.sharedContext.mediaManager.audioSession, manager: context.sharedContext.mediaManager.universalVideoManager, decoration: decoration, content: videoContent, priority: .embedded)
|
||||
videoNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 2.0, height: 2.0))
|
||||
videoNode.alpha = 0.01
|
||||
self.videoNode = videoNode
|
||||
|
||||
self.addSubnode(videoNode)
|
||||
videoNode.canAttachContent = true
|
||||
videoNode.play()
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func statusButtonPressed() {
|
||||
self.controller?.cancel()
|
||||
switch self.state {
|
||||
case .done, .progress:
|
||||
self.controller?.cancel()
|
||||
case .error:
|
||||
self.controller?.beginImport()
|
||||
}
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
@ -157,20 +186,39 @@ public final class ChatImportActivityScreen: ViewController {
|
||||
let progressStatusSpacing: CGFloat = 14.0
|
||||
let statusButtonSpacing: CGFloat = 19.0
|
||||
|
||||
self.radialStatusText.attributedText = NSAttributedString(string: "\(Int(self.totalProgress * 100.0))%", font: Font.with(size: 42.0, design: .round, weight: .semibold), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||
let effectiveProgress: CGFloat
|
||||
switch state {
|
||||
case let .progress(value):
|
||||
effectiveProgress = value
|
||||
case .error:
|
||||
effectiveProgress = 0.0
|
||||
case .done:
|
||||
effectiveProgress = 1.0
|
||||
}
|
||||
|
||||
self.radialStatusText.attributedText = NSAttributedString(string: "\(Int(effectiveProgress * 100.0))%", font: Font.with(size: 42.0, design: .round, weight: .semibold), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||
let radialStatusTextSize = self.radialStatusText.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
|
||||
|
||||
self.progressText.attributedText = NSAttributedString(string: "\(dataSizeString(Int(self.totalProgress * CGFloat(self.totalBytes)))) of \(dataSizeString(Int(1.0 * CGFloat(self.totalBytes))))", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||
self.progressText.attributedText = NSAttributedString(string: "\(dataSizeString(Int(effectiveProgress * CGFloat(self.totalBytes)))) of \(dataSizeString(Int(1.0 * CGFloat(self.totalBytes))))", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||
let progressTextSize = self.progressText.updateLayout(CGSize(width: layout.size.width - 16.0 * 2.0, height: .greatestFiniteMagnitude))
|
||||
|
||||
self.statusButtonText.attributedText = NSAttributedString(string: "Done", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemAccentColor)
|
||||
switch self.state {
|
||||
case .progress, .done:
|
||||
self.statusButtonText.attributedText = NSAttributedString(string: "Done", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemAccentColor)
|
||||
case .error:
|
||||
self.statusButtonText.attributedText = NSAttributedString(string: "Retry", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemAccentColor)
|
||||
}
|
||||
let statusButtonTextSize = self.statusButtonText.updateLayout(CGSize(width: layout.size.width - 16.0 * 2.0, height: .greatestFiniteMagnitude))
|
||||
|
||||
if !self.isDone {
|
||||
switch self.state {
|
||||
case .progress:
|
||||
self.statusText.attributedText = NSAttributedString(string: "Please keep this window open\nduring the import.", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemSecondaryTextColor)
|
||||
} else {
|
||||
case .error:
|
||||
self.statusText.attributedText = NSAttributedString(string: "An error occurred.", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemDestructiveColor)
|
||||
case .done:
|
||||
self.statusText.attributedText = NSAttributedString(string: "This chat has been imported\nsuccessfully.", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||
}
|
||||
|
||||
let statusTextSize = self.statusText.updateLayout(CGSize(width: layout.size.width - 16.0 * 2.0, height: .greatestFiniteMagnitude))
|
||||
|
||||
let contentHeight: CGFloat
|
||||
@ -201,35 +249,49 @@ public final class ChatImportActivityScreen: ViewController {
|
||||
|
||||
self.progressText.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - progressTextSize.width) / 2.0), y: self.radialStatus.frame.maxY + maxProgressTextSpacing), size: progressTextSize)
|
||||
|
||||
if self.isDone {
|
||||
self.statusText.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - statusTextSize.width) / 2.0), y: self.progressText.frame.minY), size: statusTextSize)
|
||||
} else {
|
||||
if case .progress = self.state {
|
||||
self.statusText.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - statusTextSize.width) / 2.0), y: self.progressText.frame.maxY + progressStatusSpacing), size: statusTextSize)
|
||||
self.statusButtonText.isHidden = true
|
||||
self.statusButton.isHidden = true
|
||||
self.progressText.isHidden = false
|
||||
} else {
|
||||
self.statusText.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - statusTextSize.width) / 2.0), y: self.progressText.frame.minY), size: statusTextSize)
|
||||
self.statusButtonText.isHidden = false
|
||||
self.statusButton.isHidden = false
|
||||
self.progressText.isHidden = true
|
||||
}
|
||||
|
||||
let statusButtonTextFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - statusButtonTextSize.width) / 2.0), y: self.statusText.frame.maxY + statusButtonSpacing), size: statusButtonTextSize)
|
||||
self.statusButtonText.frame = statusButtonTextFrame
|
||||
self.statusButton.frame = statusButtonTextFrame.insetBy(dx: -10.0, dy: -10.0)
|
||||
|
||||
self.statusButtonText.isHidden = !self.isDone
|
||||
self.statusButton.isHidden = !self.isDone
|
||||
self.progressText.isHidden = self.isDone
|
||||
|
||||
if isFirstLayout {
|
||||
self.updateProgress(totalProgress: self.totalProgress, isDone: self.isDone, animated: false)
|
||||
self.updateState(state: self.state, animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
func updateProgress(totalProgress: CGFloat, isDone: Bool, animated: Bool) {
|
||||
self.totalProgress = totalProgress
|
||||
let wasDone = self.isDone
|
||||
self.isDone = isDone
|
||||
func updateState(state: State, animated: Bool) {
|
||||
var wasDone = false
|
||||
if case .done = self.state {
|
||||
wasDone = true
|
||||
}
|
||||
self.state = state
|
||||
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .immediate)
|
||||
self.radialStatus.transitionToState(.progress(color: self.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: max(0.02, self.totalProgress), cancelEnabled: false, animateRotation: false), animated: animated, synchronous: true, completion: {})
|
||||
if isDone {
|
||||
self.radialCheck.transitionToState(.progress(color: .clear, lineWidth: 6.0, value: self.totalProgress, cancelEnabled: false, animateRotation: false), animated: false, synchronous: true, completion: {})
|
||||
|
||||
let effectiveProgress: CGFloat
|
||||
switch state {
|
||||
case let .progress(value):
|
||||
effectiveProgress = value
|
||||
case .error:
|
||||
effectiveProgress = 0.0
|
||||
case .done:
|
||||
effectiveProgress = 1.0
|
||||
}
|
||||
self.radialStatus.transitionToState(.progress(color: self.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: max(0.01, effectiveProgress), cancelEnabled: false, animateRotation: false), animated: animated, synchronous: true, completion: {})
|
||||
if case .done = state {
|
||||
self.radialCheck.transitionToState(.progress(color: .clear, lineWidth: 6.0, value: 1.0, cancelEnabled: false, animateRotation: false), animated: false, synchronous: true, completion: {})
|
||||
self.radialCheck.transitionToState(.check(self.presentationData.theme.list.itemAccentColor), animated: animated, synchronous: true, completion: {})
|
||||
self.radialStatus.layer.animateScale(from: 1.0, to: 1.05, duration: 0.07, delay: 0.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, additive: false, completion: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
@ -274,7 +336,7 @@ public final class ChatImportActivityScreen: ViewController {
|
||||
private let context: AccountContext
|
||||
private var presentationData: PresentationData
|
||||
fileprivate let cancel: () -> Void
|
||||
private let peerId: PeerId
|
||||
private var peerId: PeerId
|
||||
private let archive: Archive
|
||||
private let mainEntry: TempBoxFile
|
||||
private let mainEntrySize: Int
|
||||
@ -369,6 +431,12 @@ public final class ChatImportActivityScreen: ViewController {
|
||||
case generic
|
||||
}
|
||||
|
||||
for (key, value) in self.pendingEntries {
|
||||
self.pendingEntries[key] = (value.0, 0.0)
|
||||
}
|
||||
|
||||
self.controllerNode.updateState(state: .progress(0.0), animated: true)
|
||||
|
||||
let context = self.context
|
||||
let archive = self.archive
|
||||
let mainEntry = self.mainEntry
|
||||
@ -385,7 +453,11 @@ public final class ChatImportActivityScreen: ViewController {
|
||||
}
|
||||
|
||||
self.disposable.set((resolvedPeerId
|
||||
|> mapToSignal { peerId -> Signal<ChatHistoryImport.Session, ImportError> in
|
||||
|> mapToSignal { [weak self] peerId -> Signal<ChatHistoryImport.Session, ImportError> in
|
||||
Queue.mainQueue().async {
|
||||
self?.peerId = peerId
|
||||
}
|
||||
|
||||
return ChatHistoryImport.initSession(account: context.account, peerId: peerId, file: mainEntry, mediaCount: Int32(otherEntries.count))
|
||||
|> mapError { _ -> ImportError in
|
||||
return .generic
|
||||
@ -458,17 +530,17 @@ public final class ChatImportActivityScreen: ViewController {
|
||||
if !strongSelf.otherEntries.isEmpty {
|
||||
totalProgress = CGFloat(totalDoneBytes) / CGFloat(strongSelf.totalBytes)
|
||||
}
|
||||
strongSelf.controllerNode.updateProgress(totalProgress: totalProgress, isDone: false, animated: true)
|
||||
strongSelf.controllerNode.updateState(state: .progress(totalProgress), animated: true)
|
||||
}, error: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.controllerNode.updateProgress(totalProgress: 0.0, isDone: false, animated: true)
|
||||
strongSelf.controllerNode.updateState(state: .error, animated: true)
|
||||
}, completed: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.controllerNode.updateProgress(totalProgress: 1.0, isDone: true, animated: true)
|
||||
strongSelf.controllerNode.updateState(state: .done, animated: true)
|
||||
|
||||
if let application = UIApplication.value(forKeyPath: #keyPath(UIApplication.shared)) as? UIApplication {
|
||||
application.isIdleTimerDisabled = false
|
||||
|
@ -2144,15 +2144,18 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
if case .broadcast = channel.info {
|
||||
canClear = false
|
||||
deleteTitle = strongSelf.presentationData.strings.Channel_LeaveChannel
|
||||
if channel.flags.contains(.isCreator) {
|
||||
canRemoveGlobally = true
|
||||
}
|
||||
} else {
|
||||
deleteTitle = strongSelf.presentationData.strings.Group_DeleteGroup
|
||||
if channel.flags.contains(.isCreator) {
|
||||
canRemoveGlobally = true
|
||||
}
|
||||
}
|
||||
if let addressName = channel.addressName, !addressName.isEmpty {
|
||||
canClear = false
|
||||
}
|
||||
if channel.flags.contains(.isCreator) {
|
||||
canRemoveGlobally = true
|
||||
}
|
||||
} else if let group = chatPeer as? TelegramGroup {
|
||||
if case .creator = group.role {
|
||||
canRemoveGlobally = true
|
||||
@ -2184,12 +2187,27 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
})
|
||||
}))
|
||||
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForAllMembers, color: .destructive, action: { [weak actionSheet] in
|
||||
let deleteForAllText: String
|
||||
if let channel = mainPeer as? TelegramChannel, case .broadcast = channel.info {
|
||||
deleteForAllText = strongSelf.presentationData.strings.ChatList_DeleteForAllSubscribers
|
||||
} else {
|
||||
deleteForAllText = strongSelf.presentationData.strings.ChatList_DeleteForAllMembers
|
||||
}
|
||||
|
||||
items.append(ActionSheetButtonItem(title: deleteForAllText, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationTitle, text: strongSelf.presentationData.strings.ChannelInfo_DeleteGroupConfirmation, actions: [
|
||||
|
||||
let deleteForAllConfirmation: String
|
||||
if let channel = mainPeer as? TelegramChannel, case .broadcast = channel.info {
|
||||
deleteForAllConfirmation = strongSelf.presentationData.strings.ChannelInfo_DeleteChannelConfirmation
|
||||
} else {
|
||||
deleteForAllConfirmation = strongSelf.presentationData.strings.ChannelInfo_DeleteGroupConfirmation
|
||||
}
|
||||
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationTitle, text: deleteForAllConfirmation, actions: [
|
||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
||||
}),
|
||||
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationAction, action: {
|
||||
@ -2268,14 +2286,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
} else {
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak actionSheet] in
|
||||
beginClear(.forEveryone)
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in
|
||||
beginClear(.forLocalPeer)
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak actionSheet] in
|
||||
beginClear(.forEveryone)
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
}
|
||||
|
||||
actionSheet.setItemGroups([
|
||||
@ -2328,12 +2346,27 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
})
|
||||
}))
|
||||
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForAllMembers, color: .destructive, action: { [weak actionSheet] in
|
||||
let deleteForAllText: String
|
||||
if let channel = mainPeer as? TelegramChannel, case .broadcast = channel.info {
|
||||
deleteForAllText = strongSelf.presentationData.strings.ChatList_DeleteForAllSubscribers
|
||||
} else {
|
||||
deleteForAllText = strongSelf.presentationData.strings.ChatList_DeleteForAllMembers
|
||||
}
|
||||
|
||||
items.append(ActionSheetButtonItem(title: deleteForAllText, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationTitle, text: strongSelf.presentationData.strings.ChatList_DeleteForAllMembersConfirmationText, actions: [
|
||||
|
||||
let deleteForAllConfirmation: String
|
||||
if let channel = mainPeer as? TelegramChannel, case .broadcast = channel.info {
|
||||
deleteForAllConfirmation = strongSelf.presentationData.strings.ChatList_DeleteForAllSubscribersConfirmationText
|
||||
} else {
|
||||
deleteForAllConfirmation = strongSelf.presentationData.strings.ChatList_DeleteForAllMembersConfirmationText
|
||||
}
|
||||
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationTitle, text: deleteForAllConfirmation, actions: [
|
||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
||||
}),
|
||||
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationAction, action: {
|
||||
@ -2421,6 +2454,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
completion(true)
|
||||
}))
|
||||
} else {
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
self?.schedulePeerChatRemoval(peer: peer, type: .forLocalPeer, deleteGloballyIfPossible: deleteGloballyIfPossible, completion: {
|
||||
removed()
|
||||
})
|
||||
completion(true)
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
guard let strongSelf = self else {
|
||||
@ -2438,13 +2478,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
})
|
||||
], parseMarkdown: true), in: .window(.root))
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
self?.schedulePeerChatRemoval(peer: peer, type: .forLocalPeer, deleteGloballyIfPossible: deleteGloballyIfPossible, completion: {
|
||||
removed()
|
||||
})
|
||||
completion(true)
|
||||
}))
|
||||
}
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
|
File diff suppressed because it is too large
Load Diff
BIN
submodules/TelegramUI/Resources/BlankVideo.m4v
Normal file
BIN
submodules/TelegramUI/Resources/BlankVideo.m4v
Normal file
Binary file not shown.
Binary file not shown.
@ -415,12 +415,31 @@ public class ShareRootControllerImpl {
|
||||
beginShare()
|
||||
return
|
||||
}
|
||||
guard let _ = archive["_chat.txt"] else {
|
||||
|
||||
let mainFileNames: [NSRegularExpression] = [
|
||||
try! NSRegularExpression(pattern: "_chat\\.txt"),
|
||||
try! NSRegularExpression(pattern: "KakaoTalkChats\\.txt"),
|
||||
try! NSRegularExpression(pattern: "Talk_.*?\\.txt"),
|
||||
]
|
||||
|
||||
var maybeMainFileName: String?
|
||||
mainFileLoop: for entry in archive {
|
||||
let entryFileName = entry.path(using: .utf8).replacingOccurrences(of: "/", with: "_").replacingOccurrences(of: "..", with: "_")
|
||||
let fullRange = NSRange(entryFileName.startIndex ..< entryFileName.endIndex, in: entryFileName)
|
||||
for expression in mainFileNames {
|
||||
if expression.firstMatch(in: entryFileName, options: [], range: fullRange) != nil {
|
||||
maybeMainFileName = entryFileName
|
||||
break mainFileLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guard let mainFileName = maybeMainFileName else {
|
||||
beginShare()
|
||||
return
|
||||
}
|
||||
|
||||
let photoRegex = try! NSRegularExpression(pattern: "[\\d]+-PHOTO-.*?\\.jpg")
|
||||
let photoRegex = try! NSRegularExpression(pattern: ".*?\\.jpg")
|
||||
let videoRegex = try! NSRegularExpression(pattern: "[\\d]+-VIDEO-.*?\\.mp4")
|
||||
let stickerRegex = try! NSRegularExpression(pattern: "[\\d]+-STICKER-.*?\\.webp")
|
||||
let voiceRegex = try! NSRegularExpression(pattern: "[\\d]+-AUDIO-.*?\\.opus")
|
||||
@ -435,7 +454,7 @@ public class ShareRootControllerImpl {
|
||||
continue
|
||||
}
|
||||
let tempFile = TempBox.shared.tempFile(fileName: entryPath)
|
||||
if entryPath == "_chat.txt" {
|
||||
if entryPath == mainFileName {
|
||||
let _ = try archive.extract(entry, to: URL(fileURLWithPath: tempFile.path))
|
||||
mainFile = tempFile
|
||||
} else {
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"app": "7.3.1",
|
||||
"app": "7.4",
|
||||
"bazel": "3.7.0",
|
||||
"xcode": "12.3"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user