Fixed CallKit API

Fixed auth code entry layout
Added passcode lock confirmation
Fixed auth code url handling
Fixed instagram video gallery thumbnails
This commit is contained in:
Peter
2018-11-20 04:04:38 +03:00
parent 0aa45a4b87
commit 6d1c9a1ce3
13 changed files with 2111 additions and 2048 deletions

View File

@@ -47,6 +47,17 @@ final class AuthorizationSequenceCodeEntryController: ViewController {
self.statusBar.statusBarStyle = theme.statusBarStyle self.statusBar.statusBarStyle = theme.statusBarStyle
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed)) self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
self.attemptNavigation = { [weak self] f in
guard let strongSelf = self else {
return true
}
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(authTheme: theme), title: nil, text: strings.Login_CancelPhoneVerification, actions: [TextAlertAction(type: .genericAction, title: strings.Login_CancelPhoneVerificationContinue, action: {
}), TextAlertAction(type: .defaultAction, title: strings.Login_CancelPhoneVerificationStop, action: {
f()
})]), in: .window(.root))
return false
}
} }
required init(coder aDecoder: NSCoder) { required init(coder aDecoder: NSCoder) {

View File

@@ -274,7 +274,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
var items: [AuthorizationLayoutItem] = [] var items: [AuthorizationLayoutItem] = []
if let codeType = self.codeType, case .otherSession = codeType { if let codeType = self.codeType, case .otherSession = codeType {
self.titleIconNode.isHidden = false self.titleIconNode.isHidden = false
items.append(AuthorizationLayoutItem(node: self.titleIconNode, size: self.titleIconNode.image!.size, spacingBefore: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.titleIconNode, size: self.titleIconNode.image!.size, spacingBefore: AuthorizationLayoutItemSpacing(weight: 41.0, maxValue: 41.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
items.append(AuthorizationLayoutItem(node: self.titleNode, size: titleSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 18.0, maxValue: 18.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.titleNode, size: titleSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 18.0, maxValue: 18.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
items.append(AuthorizationLayoutItem(node: self.currentOptionNode, size: currentOptionSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 10.0, maxValue: 10.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.currentOptionNode, size: currentOptionSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 10.0, maxValue: 10.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
items.append(AuthorizationLayoutItem(node: self.codeField, size: CGSize(width: layout.size.width - 88.0, height: 44.0), spacingBefore: AuthorizationLayoutItemSpacing(weight: 40.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.codeField, size: CGSize(width: layout.size.width - 88.0, height: 44.0), spacingBefore: AuthorizationLayoutItemSpacing(weight: 40.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))

View File

@@ -74,27 +74,7 @@ public final class AuthorizationSequenceController: NavigationController {
let masterDatacenterId = strongSelf.account.masterDatacenterId let masterDatacenterId = strongSelf.account.masterDatacenterId
let isTestingEnvironment = strongSelf.account.testingEnvironment let isTestingEnvironment = strongSelf.account.testingEnvironment
var countryId: String? = nil let countryCode = defaultCountryCode()
let networkInfo = CTTelephonyNetworkInfo()
if let carrier = networkInfo.subscriberCellularProvider {
countryId = carrier.isoCountryCode
}
if countryId == nil {
countryId = (Locale.current as NSLocale).object(forKey: .countryCode) as? String
}
var countryCode: Int32 = 1
if let countryId = countryId {
let normalizedId = countryId.uppercased()
for (code, idAndName) in countryCodeToIdAndName {
if idAndName.0 == normalizedId {
countryCode = Int32(code)
break
}
}
}
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: isTestingEnvironment, masterDatacenterId: masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))) transaction.setState(UnauthorizedAccountState(isTestingEnvironment: isTestingEnvironment, masterDatacenterId: masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: "")))
@@ -637,7 +617,7 @@ public final class AuthorizationSequenceController: NavigationController {
case let .phoneEntry(countryCode, number): case let .phoneEntry(countryCode, number):
self.setViewControllers([self.splashController(), self.phoneEntryController(countryCode: countryCode, number: number)], animated: !self.viewControllers.isEmpty) self.setViewControllers([self.splashController(), self.phoneEntryController(countryCode: countryCode, number: number)], animated: !self.viewControllers.isEmpty)
case let .confirmationCodeEntry(number, type, _, timeout, nextType, termsOfService): case let .confirmationCodeEntry(number, type, _, timeout, nextType, termsOfService):
self.setViewControllers([self.splashController(), self.codeEntryController(number: number, type: type, nextType: nextType, timeout: timeout, termsOfService: termsOfService)], animated: !self.viewControllers.isEmpty) self.setViewControllers([self.splashController(), self.phoneEntryController(countryCode: defaultCountryCode(), number: ""), self.codeEntryController(number: number, type: type, nextType: nextType, timeout: timeout, termsOfService: termsOfService)], animated: !self.viewControllers.isEmpty)
case let .passwordEntry(hint, _, _): case let .passwordEntry(hint, _, _):
self.setViewControllers([self.splashController(), self.passwordEntryController(hint: hint)], animated: !self.viewControllers.isEmpty) self.setViewControllers([self.splashController(), self.passwordEntryController(hint: hint)], animated: !self.viewControllers.isEmpty)
case let .passwordRecovery(_, _, _, emailPattern): case let .passwordRecovery(_, _, _, emailPattern):
@@ -665,3 +645,29 @@ public final class AuthorizationSequenceController: NavigationController {
} }
} }
} }
private func defaultCountryCode() -> Int32 {
var countryId: String? = nil
let networkInfo = CTTelephonyNetworkInfo()
if let carrier = networkInfo.subscriberCellularProvider {
countryId = carrier.isoCountryCode
}
if countryId == nil {
countryId = (Locale.current as NSLocale).object(forKey: .countryCode) as? String
}
var countryCode: Int32 = 1
if let countryId = countryId {
let normalizedId = countryId.uppercased()
for (code, idAndName) in countryCodeToIdAndName {
if idAndName.0 == normalizedId {
countryCode = Int32(code)
break
}
}
}
return countryCode
}

View File

@@ -197,11 +197,11 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
let disposable = MetaDisposable() let disposable = MetaDisposable()
self.disposableSet.add(disposable) self.disposableSet.add(disposable)
disposable.set((self.startCall(action.callUUID, action.handle.value) disposable.set((self.startCall(action.callUUID, action.handle.value)
|> deliverOnMainQueue |> deliverOnMainQueue
|> afterDisposed { [weak self, weak disposable] in |> afterDisposed { [weak self, weak disposable] in
if let strongSelf = self, let disposable = disposable { if let strongSelf = self, let disposable = disposable {
strongSelf.disposableSet.remove(disposable) strongSelf.disposableSet.remove(disposable)
} }
}).start(next: { result in }).start(next: { result in
if result { if result {
action.fulfill() action.fulfill()

View File

@@ -181,7 +181,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
self.titleView.toggleIsLocked = { [weak self] in self.titleView.toggleIsLocked = { [weak self] in
if let strongSelf = self { if let strongSelf = self {
let _ = strongSelf.account.postbox.transaction({ transaction -> Void in let _ = (strongSelf.account.postbox.transaction({ transaction -> Void in
var data = transaction.getAccessChallengeData() var data = transaction.getAccessChallengeData()
if data.isLockable { if data.isLockable {
if data.autolockDeadline != 0 { if data.autolockDeadline != 0 {
@@ -191,7 +191,12 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
} }
transaction.setAccessChallengeData(data) transaction.setAccessChallengeData(data)
} }
}).start() }) |> deliverOnMainQueue).start(completed: {
guard let strongSelf = self else {
return
}
strongSelf.present(OverlayStatusController(theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, type: .shieldSuccess(strongSelf.presentationData.strings.Passcode_AppLockedAlert)), in: .window(.root))
})
} }
} }

View File

@@ -171,22 +171,15 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
cutout = TextNodeCutout(bottomRight: statusSize) cutout = TextNodeCutout(bottomRight: statusSize)
} }
let (textLayout, textApply) = textLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: cutout, insets: UIEdgeInsets())) let textInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 5.0, right: 0.0)
var textFrame = CGRect(origin: CGPoint(), size: textLayout.size) let (textLayout, textApply) = textLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: cutout, insets: textInsets))
let textSize = textLayout.size
var textFrame = CGRect(origin: CGPoint(x: -textInsets.left, y: -textInsets.top), size: textLayout.size)
var statusFrame: CGRect? var statusFrame: CGRect?
if let statusSize = statusSize { if let statusSize = statusSize {
var frame = CGRect(origin: CGPoint(x: textFrame.maxX - statusSize.width, y: textFrame.maxY - statusSize.height), size: statusSize) statusFrame = CGRect(origin: CGPoint(x: textFrame.maxX - textInsets.right - statusSize.width, y: textFrame.maxY - textInsets.bottom - statusSize.height), size: statusSize)
/*let trailingLineWidth = textLayout.trailingLineWidth
if textSize.width - trailingLineWidth >= statusSize.width {
frame.origin = CGPoint(x: textFrame.maxX - statusSize.width, y: textFrame.maxY - statusSize.height)
} else if trailingLineWidth + statusSize.width < textConstrainedSize.width {
frame.origin = CGPoint(x: textFrame.minX + trailingLineWidth, y: textFrame.maxY - statusSize.height)
}*/
statusFrame = frame
} }
textFrame = textFrame.offsetBy(dx: layoutConstants.text.bubbleInsets.left, dy: layoutConstants.text.bubbleInsets.top) textFrame = textFrame.offsetBy(dx: layoutConstants.text.bubbleInsets.left, dy: layoutConstants.text.bubbleInsets.top)

View File

@@ -457,6 +457,22 @@ public func openExternalUrl(account: Account, context: OpenURLContext = .generic
return return
} }
} }
} else if parsedUrl.host == "login" {
if let components = URLComponents(string: "/?" + query) {
var code: String?
if let queryItems = components.queryItems {
for queryItem in queryItems {
if let value = queryItem.value {
if queryItem.name == "code" {
code = value
}
}
}
}
if let code = code {
convertedUrl = "https://t.me/login/\(code)"
}
}
} }
if parsedUrl.host == "resolve" { if parsedUrl.host == "resolve" {

View File

@@ -6,14 +6,14 @@ import LegacyComponents
enum OverlayStatusControllerType { enum OverlayStatusControllerType {
case loading(cancelled: (() -> Void)?) case loading(cancelled: (() -> Void)?)
case success case success
case proxySettingSuccess case shieldSuccess(String)
case genericSuccess(String) case genericSuccess(String)
} }
private enum OverlayStatusContentController { private enum OverlayStatusContentController {
case loading(TGProgressWindowController) case loading(TGProgressWindowController)
case progress(TGProgressWindowController) case progress(TGProgressWindowController)
case proxy(TGProxyWindowController) case shieldSuccess(TGProxyWindowController)
case genericSuccess(TGProxyWindowController) case genericSuccess(TGProxyWindowController)
var view: UIView { var view: UIView {
@@ -22,7 +22,7 @@ private enum OverlayStatusContentController {
return controller.view return controller.view
case let .progress(controller): case let .progress(controller):
return controller.view return controller.view
case let .proxy(controller): case let .shieldSuccess(controller):
return controller.view return controller.view
case let .genericSuccess(controller): case let .genericSuccess(controller):
return controller.view return controller.view
@@ -35,7 +35,7 @@ private enum OverlayStatusContentController {
controller.updateLayout() controller.updateLayout()
case let .progress(controller): case let .progress(controller):
controller.updateLayout() controller.updateLayout()
case let .proxy(controller): case let .shieldSuccess(controller):
controller.updateLayout() controller.updateLayout()
case let .genericSuccess(controller): case let .genericSuccess(controller):
controller.updateLayout() controller.updateLayout()
@@ -48,7 +48,7 @@ private enum OverlayStatusContentController {
controller.show(true) controller.show(true)
case let .progress(controller): case let .progress(controller):
controller.dismiss(success: success) controller.dismiss(success: success)
case let .proxy(controller): case let .shieldSuccess(controller):
controller.dismiss(success: success) controller.dismiss(success: success)
case let .genericSuccess(controller): case let .genericSuccess(controller):
controller.dismiss(success: success) controller.dismiss(success: success)
@@ -82,8 +82,8 @@ private final class OverlayStatusControllerNode: ViewControllerTracingNode {
self.contentController = .loading(controller) self.contentController = .loading(controller)
case .success: case .success:
self.contentController = .progress(TGProgressWindowController(light: theme.actionSheet.backgroundType == .light)) self.contentController = .progress(TGProgressWindowController(light: theme.actionSheet.backgroundType == .light))
case .proxySettingSuccess: case let .shieldSuccess(text):
self.contentController = .proxy(TGProxyWindowController(light: theme.actionSheet.backgroundType == .light, text: strings.SocksProxySetup_ProxyEnabled, shield: true)) self.contentController = .shieldSuccess(TGProxyWindowController(light: theme.actionSheet.backgroundType == .light, text: text, shield: true))
case let .genericSuccess(text): case let .genericSuccess(text):
self.contentController = .genericSuccess(TGProxyWindowController(light: theme.actionSheet.backgroundType == .light, text: text, shield: false)) self.contentController = .genericSuccess(TGProxyWindowController(light: theme.actionSheet.backgroundType == .light, text: text, shield: false))
} }

View File

@@ -16,7 +16,7 @@ public func largestRepresentationForPhoto(_ photo: TelegramMediaImage) -> Telegr
return photo.representationForDisplayAtSize(CGSize(width: 1280.0, height: 1280.0)) return photo.representationForDisplayAtSize(CGSize(width: 1280.0, height: 1280.0))
} }
private func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaReference, fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0), autoFetchFullSize: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> { private func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaReference, fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0), autoFetchFullSize: Bool = false, tryAdditionalRepresentations: Bool = false) -> Signal<(Data?, Data?, Bool), NoError> {
if let smallestRepresentation = smallestImageRepresentation(photoReference.media.representations), let largestRepresentation = photoReference.media.representationForDisplayAtSize(fullRepresentationSize) { if let smallestRepresentation = smallestImageRepresentation(photoReference.media.representations), let largestRepresentation = photoReference.media.representationForDisplayAtSize(fullRepresentationSize) {
let maybeFullSize = postbox.mediaBox.resourceData(largestRepresentation.resource) let maybeFullSize = postbox.mediaBox.resourceData(largestRepresentation.resource)
@@ -28,7 +28,19 @@ private func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaR
let fetchedThumbnail = fetchedMediaResource(postbox: postbox, reference: photoReference.resourceReference(smallestRepresentation.resource), statsCategory: .image) let fetchedThumbnail = fetchedMediaResource(postbox: postbox, reference: photoReference.resourceReference(smallestRepresentation.resource), statsCategory: .image)
let fetchedFullSize = fetchedMediaResource(postbox: postbox, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image) let fetchedFullSize = fetchedMediaResource(postbox: postbox, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image)
let thumbnail = Signal<Data?, NoError> { subscriber in let anyThumbnail: [Signal<MediaResourceData, NoError>]
if tryAdditionalRepresentations {
anyThumbnail = photoReference.media.representations.filter({ representation in
return representation != largestRepresentation
}).map({ representation -> Signal<MediaResourceData, NoError> in
return postbox.mediaBox.resourceData(representation.resource)
|> take(1)
})
} else {
anyThumbnail = []
}
let mainThumbnail = Signal<Data?, NoError> { subscriber in
let fetchedDisposable = fetchedThumbnail.start() let fetchedDisposable = fetchedThumbnail.start()
let thumbnailDisposable = postbox.mediaBox.resourceData(smallestRepresentation.resource).start(next: { next in let thumbnailDisposable = postbox.mediaBox.resourceData(smallestRepresentation.resource).start(next: { next in
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: [])) subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
@@ -40,6 +52,16 @@ private func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaR
} }
} }
let thumbnail = combineLatest(anyThumbnail)
|> mapToSignal { thumbnails -> Signal<Data?, NoError> in
for thumbnail in thumbnails {
if thumbnail.size != 0, let data = try? Data(contentsOf: URL(fileURLWithPath: thumbnail.path), options: []) {
return .single(data)
}
}
return mainThumbnail
}
let fullSizeData: Signal<(Data?, Bool), NoError> let fullSizeData: Signal<(Data?, Bool), NoError>
if autoFetchFullSize { if autoFetchFullSize {
@@ -1363,7 +1385,7 @@ func mediaGridMessageVideo(postbox: Postbox, videoReference: FileMediaReference)
func internalMediaGridMessageVideo(postbox: Postbox, videoReference: FileMediaReference, imageReference: ImageMediaReference? = nil) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> { func internalMediaGridMessageVideo(postbox: Postbox, videoReference: FileMediaReference, imageReference: ImageMediaReference? = nil) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> {
let signal: Signal<(Data?, (Data, String)?, Bool), NoError> let signal: Signal<(Data?, (Data, String)?, Bool), NoError>
if let imageReference = imageReference { if let imageReference = imageReference {
signal = chatMessagePhotoDatas(postbox: postbox, photoReference: imageReference) signal = chatMessagePhotoDatas(postbox: postbox, photoReference: imageReference, tryAdditionalRepresentations: true)
|> map { (thumbnailData, fullSizeData, fullSizeComplete) -> (Data?, (Data, String)?, Bool) in |> map { (thumbnailData, fullSizeData, fullSizeComplete) -> (Data?, (Data, String)?, Bool) in
return (thumbnailData, fullSizeData.flatMap({ ($0, "") }), fullSizeComplete) return (thumbnailData, fullSizeData.flatMap({ ($0, "") }), fullSizeComplete)
} }
@@ -1534,6 +1556,12 @@ func internalMediaGridMessageVideo(postbox: Postbox, videoReference: FileMediaRe
} }
c.setBlendMode(.copy) c.setBlendMode(.copy)
if blurredThumbnailImage == nil, fullSizeImage == nil, let emptyColor = arguments.emptyColor {
c.setFillColor(emptyColor.cgColor)
c.fill(arguments.drawingRect)
}
if let blurredThumbnailImage = blurredThumbnailImage, let cgImage = blurredThumbnailImage.cgImage { if let blurredThumbnailImage = blurredThumbnailImage, let cgImage = blurredThumbnailImage.cgImage {
c.interpolationQuality = .default c.interpolationQuality = .default
drawImage(context: c, image: cgImage, orientation: imageOrientation, in: fittedRect) drawImage(context: c, image: cgImage, orientation: imageOrientation, in: fittedRect)

View File

@@ -256,7 +256,7 @@ public final class PresentationCallManager {
if let call = self.currentCall, !endCurrentIfAny { if let call = self.currentCall, !endCurrentIfAny {
return .alreadyInProgress(call.peerId) return .alreadyInProgress(call.peerId)
} }
if let _ = self.callKitIntegration { if let _ = callKitIntegrationIfEnabled(self.callKitIntegration, settings: self.callSettings?.0) {
let (presentationData, present, openSettings) = self.getDeviceAccessData() let (presentationData, present, openSettings) = self.getDeviceAccessData()
let accessEnabledSignal: Signal<Bool, NoError> = Signal { subscriber in let accessEnabledSignal: Signal<Bool, NoError> = Signal { subscriber in
@@ -317,7 +317,7 @@ public final class PresentationCallManager {
if !accessEnabled { if !accessEnabled {
return .single(false) return .single(false)
} }
return (combineLatest(callSessionManager.request(peerId: peerId, internalId: internalId), networkType |> take(1), postbox.peerView(id: peerId) |> take(1) |> map({ peerView -> Bool in return (combineLatest(queue: .mainQueue(), callSessionManager.request(peerId: peerId, internalId: internalId), networkType |> take(1), postbox.peerView(id: peerId) |> take(1) |> map({ peerView -> Bool in
return peerView.peerIsContact return peerView.peerIsContact
}) |> take(1)) }) |> take(1))
|> deliverOnMainQueue |> deliverOnMainQueue

File diff suppressed because it is too large Load Diff

View File

@@ -37,7 +37,7 @@ final class ProxyServerActionSheetController: ActionSheetController {
} }
strongSelf.isDismissed = true strongSelf.isDismissed = true
if success { if success {
strongSelf.present(OverlayStatusController(theme: theme, strings: strings, type: .proxySettingSuccess), in: .window(.root)) strongSelf.present(OverlayStatusController(theme: theme, strings: strings, type: .shieldSuccess(strings.SocksProxySetup_ProxyEnabled)), in: .window(.root))
} }
strongSelf.dismissAnimated() strongSelf.dismissAnimated()
}, present: { [weak self] c, a in }, present: { [weak self] c, a in