mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-04 18:41:00 +00:00
Merge commit 'dfe1dbd825ea321903a7d63e19577109c2cfa35b'
This commit is contained in:
commit
5d3e3b9ebe
@ -6339,3 +6339,25 @@ Sorry for the inconvenience.";
|
||||
"VoiceChat.UnpinVideo" = "Unpin Video";
|
||||
|
||||
"Notification.VoiceChatScheduled" = "Voice chat scheduled";
|
||||
|
||||
"VoiceChat.EditStartTime" = "Edit Start Time";
|
||||
"VoiceChat.StartsIn" = "Starts in";
|
||||
|
||||
"VoiceChat.SetReminder" = "Set Reminder";
|
||||
"VoiceChat.CancelReminder" = "Cancel Reminder";
|
||||
|
||||
"VoiceChat.ShareShort" = "share";
|
||||
|
||||
"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" = "Remind today at %@";
|
||||
"ScheduleVoiceChat.ScheduleTomorrow" = "Remind tomorrow at %@";
|
||||
"ScheduleVoiceChat.ScheduleOn" = "Remind on %@ at %@";
|
||||
|
||||
"Conversation.ScheduledVoiceChat" = "Scheduled Voice Chat";
|
||||
"Conversation.ScheduledVoiceChatStartsInShort" = "Voice chat starts %@";
|
||||
"Conversation.ScheduledVoiceChatStartsInShort" = "Starts %@";
|
||||
|
@ -12,8 +12,10 @@ import AlertUI
|
||||
import PresentationDataUtils
|
||||
import CountrySelectionUI
|
||||
import PhoneNumberFormat
|
||||
import CoreTelephony
|
||||
import MessageUI
|
||||
|
||||
final class ChangePhoneNumberController: ViewController {
|
||||
final class ChangePhoneNumberController: ViewController, MFMailComposeViewControllerDelegate {
|
||||
private var controllerNode: ChangePhoneNumberControllerNode {
|
||||
return self.displayNode as! ChangePhoneNumberControllerNode
|
||||
}
|
||||
@ -133,6 +135,9 @@ final class ChangePhoneNumberController: ViewController {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let text: String
|
||||
var actions: [TextAlertAction] = [
|
||||
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})
|
||||
]
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
text = presentationData.strings.Login_CodeFloodError
|
||||
@ -140,11 +145,26 @@ final class ChangePhoneNumberController: ViewController {
|
||||
text = presentationData.strings.Login_InvalidPhoneError
|
||||
case .phoneNumberOccupied:
|
||||
text = presentationData.strings.ChangePhone_ErrorOccupied(formatPhoneNumber(phoneNumber)).0
|
||||
case .phoneBanned:
|
||||
text = presentationData.strings.Login_PhoneBannedError
|
||||
actions.append(TextAlertAction(type: .defaultAction, title: presentationData.strings.Login_PhoneNumberHelp, action: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let formattedNumber = formatPhoneNumber(number)
|
||||
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
|
||||
let systemVersion = UIDevice.current.systemVersion
|
||||
let locale = Locale.current.identifier
|
||||
let carrier = CTCarrier()
|
||||
let mnc = carrier.mobileNetworkCode ?? "none"
|
||||
|
||||
strongSelf.presentEmailComposeController(address: "login@stel.com", subject: presentationData.strings.Login_PhoneBannedEmailSubject(formattedNumber).0, body: presentationData.strings.Login_PhoneBannedEmailBody(formattedNumber, appVersion, systemVersion, locale, mnc).0)
|
||||
}))
|
||||
case .generic:
|
||||
text = presentationData.strings.Login_UnknownError
|
||||
}
|
||||
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: actions), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
@ -152,4 +172,22 @@ final class ChangePhoneNumberController: ViewController {
|
||||
self.controllerNode.animateError()
|
||||
}
|
||||
}
|
||||
|
||||
private func presentEmailComposeController(address: String, subject: String, body: String) {
|
||||
if MFMailComposeViewController.canSendMail() {
|
||||
let composeController = MFMailComposeViewController()
|
||||
composeController.setToRecipients([address])
|
||||
composeController.setSubject(subject)
|
||||
composeController.setMessageBody(body, isHTML: false)
|
||||
composeController.mailComposeDelegate = self
|
||||
|
||||
self.view.window?.rootViewController?.present(composeController, animated: true, completion: nil)
|
||||
} else {
|
||||
self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Login_EmailNotConfiguredError, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
}
|
||||
|
||||
public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
|
||||
controller.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
@ -1322,7 +1322,7 @@ public final class VoiceChatController: ViewController {
|
||||
maxBioLength = 100
|
||||
}
|
||||
let controller = voiceChatTitleEditController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, forceTheme: strongSelf.darkTheme, title: presentationData.strings.VoiceChat_EditBioTitle, text: presentationData.strings.VoiceChat_EditBioText, placeholder: presentationData.strings.VoiceChat_EditBioPlaceholder, doneButtonTitle: presentationData.strings.VoiceChat_EditBioSave, value: entry.about, maxLength: maxBioLength, apply: { bio in
|
||||
if let strongSelf = self {
|
||||
if let strongSelf = self, let bio = bio {
|
||||
let _ = (updateAbout(account: strongSelf.context.account, about: bio)
|
||||
|> `catch` { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
@ -1345,8 +1345,8 @@ public final class VoiceChatController: ViewController {
|
||||
f(.default)
|
||||
|
||||
Queue.mainQueue().after(0.1) {
|
||||
let controller = voiceChatUserNameController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, forceTheme: strongSelf.darkTheme, title: presentationData.strings.VoiceChat_ChangeNameTitle, firstNamePlaceholder: presentationData.strings.UserInfo_FirstNamePlaceholder, lastNamePlaceholder: presentationData.strings.UserInfo_LastNamePlaceholder, doneButtonTitle: presentationData.strings.VoiceChat_EditBioSave, firstName: peer.firstName, lastName: peer.lastName, maxLength: 128, apply: { firstName, lastName in
|
||||
if let strongSelf = self {
|
||||
let controller = voiceChatUserNameController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, forceTheme: strongSelf.darkTheme, title: presentationData.strings.VoiceChat_ChangeNameTitle, firstNamePlaceholder: presentationData.strings.UserInfo_FirstNamePlaceholder, lastNamePlaceholder: presentationData.strings.UserInfo_LastNamePlaceholder, doneButtonTitle: presentationData.strings.VoiceChat_EditBioSave, firstName: peer.firstName, lastName: peer.lastName, maxLength: 128, apply: { firstAndLastName in
|
||||
if let strongSelf = self, let (firstName, lastName) = firstAndLastName {
|
||||
let _ = updateAccountPeerName(account: context.account, firstName: firstName, lastName: lastName).start()
|
||||
|
||||
strongSelf.presentUndoOverlay(content: .info(text: strongSelf.presentationData.strings.VoiceChat_EditNameSuccess), action: { _ in return false })
|
||||
@ -1995,6 +1995,15 @@ public final class VoiceChatController: ViewController {
|
||||
})))
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_EditPermissions, icon: { theme -> UIImage? in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Restrict"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { c, _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
c.setItems(strongSelf.contextMenuPermissionItems())
|
||||
})))
|
||||
|
||||
if let inviteLinks = inviteLinks {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_Share, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.actionSheet.primaryTextColor)
|
||||
@ -3748,7 +3757,7 @@ public final class VoiceChatController: ViewController {
|
||||
mixin.didFinishWithVideo = { [weak self] image, asset, adjustments in
|
||||
if let image = image, let asset = asset {
|
||||
completion()
|
||||
// self?.updateProfileVideo(image, asset: asset, adjustments: adjustments)
|
||||
self?.updateProfileVideo(image, asset: asset, adjustments: adjustments)
|
||||
}
|
||||
}
|
||||
mixin.didFinishWithDelete = {
|
||||
@ -3756,55 +3765,42 @@ public final class VoiceChatController: ViewController {
|
||||
return
|
||||
}
|
||||
|
||||
// let proceed = {
|
||||
// if let item = item {
|
||||
// strongSelf.deleteAvatar(item, remove: false)
|
||||
// }
|
||||
//
|
||||
// let _ = strongSelf.currentAvatarMixin.swap(nil)
|
||||
// if let _ = peer.smallProfileImage {
|
||||
// strongSelf.state = strongSelf.state.withUpdatingAvatar(nil)
|
||||
// if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||
// strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
// }
|
||||
// }
|
||||
// let postbox = strongSelf.context.account.postbox
|
||||
// strongSelf.updateAvatarDisposable.set((updatePeerPhoto(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, stateManager: strongSelf.context.account.stateManager, accountPeerId: strongSelf.context.account.peerId, peerId: strongSelf.peerId, photo: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
// return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
// })
|
||||
// |> deliverOnMainQueue).start(next: { result in
|
||||
// guard let strongSelf = self else {
|
||||
// return
|
||||
// }
|
||||
// switch result {
|
||||
// case .complete:
|
||||
// strongSelf.state = strongSelf.state.withUpdatingAvatar(nil)
|
||||
// if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||
// strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
// }
|
||||
// case .progress:
|
||||
// break
|
||||
// }
|
||||
// }))
|
||||
// }
|
||||
//
|
||||
// let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
// let items: [ActionSheetItem] = [
|
||||
// ActionSheetButtonItem(title: presentationData.strings.Settings_RemoveConfirmation, color: .destructive, action: { [weak actionSheet] in
|
||||
// actionSheet?.dismissAnimated()
|
||||
// proceed()
|
||||
// })
|
||||
// ]
|
||||
//
|
||||
// actionSheet.setItemGroups([
|
||||
// ActionSheetItemGroup(items: items),
|
||||
// ActionSheetItemGroup(items: [
|
||||
// ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
// actionSheet?.dismissAnimated()
|
||||
// })
|
||||
// ])
|
||||
// ])
|
||||
// strongSelf.controller?.present(actionSheet, in: .window(.root))
|
||||
let proceed = {
|
||||
let _ = strongSelf.currentAvatarMixin.swap(nil)
|
||||
let postbox = strongSelf.context.account.postbox
|
||||
strongSelf.updateAvatarDisposable.set((updatePeerPhoto(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, stateManager: strongSelf.context.account.stateManager, accountPeerId: strongSelf.context.account.peerId, peerId: peerId, photo: nil, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations)
|
||||
})
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch result {
|
||||
case .complete:
|
||||
break
|
||||
case .progress:
|
||||
break
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
let items: [ActionSheetItem] = [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Settings_RemoveConfirmation, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
proceed()
|
||||
})
|
||||
]
|
||||
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])
|
||||
])
|
||||
strongSelf.controller?.present(actionSheet, in: .window(.root))
|
||||
}
|
||||
mixin.didDismiss = { [weak legacyController] in
|
||||
guard let strongSelf = self else {
|
||||
@ -3856,6 +3852,125 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? ([], nil), invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
|
||||
}
|
||||
|
||||
private func updateProfileVideo(_ image: UIImage, asset: Any?, adjustments: TGVideoEditAdjustments?) {
|
||||
guard let data = image.jpegData(compressionQuality: 0.6), let peerId = self.callState?.myPeerId else {
|
||||
return
|
||||
}
|
||||
|
||||
let photoResource = LocalFileMediaResource(fileId: arc4random64())
|
||||
self.context.account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
|
||||
let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: photoResource, progressiveSizes: [], immediateThumbnailData: nil)
|
||||
|
||||
self.currentUpdatingAvatar = representation
|
||||
self.updateAvatarPromise.set(.single((representation, 0.0)))
|
||||
|
||||
var videoStartTimestamp: Double? = nil
|
||||
if let adjustments = adjustments, adjustments.videoStartValue > 0.0 {
|
||||
videoStartTimestamp = adjustments.videoStartValue - adjustments.trimStartValue
|
||||
}
|
||||
|
||||
let account = self.context.account
|
||||
let signal = Signal<TelegramMediaResource, UploadPeerPhotoError> { [weak self] subscriber in
|
||||
let entityRenderer: LegacyPaintEntityRenderer? = adjustments.flatMap { adjustments in
|
||||
if let paintingData = adjustments.paintingData, paintingData.hasAnimation {
|
||||
return LegacyPaintEntityRenderer(account: account, adjustments: adjustments)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
let uploadInterface = LegacyLiveUploadInterface(account: account)
|
||||
let signal: SSignal
|
||||
if let asset = asset as? AVAsset {
|
||||
signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, watcher: uploadInterface, entityRenderer: entityRenderer)!
|
||||
} else if let url = asset as? URL, let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer {
|
||||
let durationSignal: SSignal = SSignal(generator: { subscriber in
|
||||
let disposable = (entityRenderer.duration()).start(next: { duration in
|
||||
subscriber?.putNext(duration)
|
||||
subscriber?.putCompletion()
|
||||
})
|
||||
|
||||
return SBlockDisposable(block: {
|
||||
disposable.dispose()
|
||||
})
|
||||
})
|
||||
signal = durationSignal.map(toSignal: { duration -> SSignal? in
|
||||
if let duration = duration as? Double {
|
||||
return TGMediaVideoConverter.renderUIImage(image, duration: duration, adjustments: adjustments, watcher: nil, entityRenderer: entityRenderer)!
|
||||
} else {
|
||||
return SSignal.single(nil)
|
||||
}
|
||||
})
|
||||
|
||||
} else {
|
||||
signal = SSignal.complete()
|
||||
}
|
||||
|
||||
let signalDisposable = signal.start(next: { next in
|
||||
if let result = next as? TGMediaVideoConversionResult {
|
||||
if let image = result.coverImage, let data = image.jpegData(compressionQuality: 0.7) {
|
||||
account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
|
||||
}
|
||||
|
||||
if let timestamp = videoStartTimestamp {
|
||||
videoStartTimestamp = max(0.0, min(timestamp, result.duration - 0.05))
|
||||
}
|
||||
|
||||
var value = stat()
|
||||
if stat(result.fileURL.path, &value) == 0 {
|
||||
if let data = try? Data(contentsOf: result.fileURL) {
|
||||
let resource: TelegramMediaResource
|
||||
if let liveUploadData = result.liveUploadData as? LegacyLiveUploadInterfaceResult {
|
||||
resource = LocalFileMediaResource(fileId: liveUploadData.id)
|
||||
} else {
|
||||
resource = LocalFileMediaResource(fileId: arc4random64())
|
||||
}
|
||||
account.postbox.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||
subscriber.putNext(resource)
|
||||
}
|
||||
}
|
||||
subscriber.putCompletion()
|
||||
} else if let strongSelf = self, let progress = next as? NSNumber {
|
||||
Queue.mainQueue().async {
|
||||
strongSelf.updateAvatarPromise.set(.single((representation, Float(truncating: progress) * 0.25)))
|
||||
}
|
||||
}
|
||||
}, error: { _ in
|
||||
}, completed: nil)
|
||||
|
||||
let disposable = ActionDisposable {
|
||||
signalDisposable?.dispose()
|
||||
}
|
||||
|
||||
return ActionDisposable {
|
||||
disposable.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
self.updateAvatarDisposable.set((signal
|
||||
|> mapToSignal { videoResource -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
|
||||
if peerId.namespace == Namespaces.Peer.CloudUser {
|
||||
return updateAccountPhoto(account: account, resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
||||
})
|
||||
} else {
|
||||
return updatePeerPhoto(postbox: account.postbox, network: account.network, stateManager: account.stateManager, accountPeerId: account.peerId, peerId: peerId, photo: uploadedPeerPhoto(postbox: account.postbox, network: account.network, resource: photoResource), video: uploadedPeerVideo(postbox: account.postbox, network: account.network, messageMediaPreuploadManager: account.messageMediaPreuploadManager, resource: videoResource) |> map(Optional.init), videoStartTimestamp: videoStartTimestamp, mapResourceToAvatarSizes: { resource, representations in
|
||||
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
|
||||
})
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch result {
|
||||
case .complete:
|
||||
strongSelf.updateAvatarPromise.set(.single(nil))
|
||||
case let .progress(value):
|
||||
strongSelf.updateAvatarPromise.set(.single((representation, 0.25 + value * 0.75)))
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
private let sharedContext: SharedAccountContext
|
||||
|
@ -710,7 +710,7 @@ private final class VoiceChatUserNameEditAlertContentNode: AlertContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
func voiceChatUserNameController(sharedContext: SharedAccountContext, account: Account, forceTheme: PresentationTheme?, title: String, firstNamePlaceholder: String, lastNamePlaceholder: String, doneButtonTitle: String? = nil, firstName: String?, lastName: String?, maxLength: Int, apply: @escaping (String, String) -> Void) -> AlertController {
|
||||
func voiceChatUserNameController(sharedContext: SharedAccountContext, account: Account, forceTheme: PresentationTheme?, title: String, firstNamePlaceholder: String, lastNamePlaceholder: String, doneButtonTitle: String? = nil, firstName: String?, lastName: String?, maxLength: Int, apply: @escaping ((String, String)?) -> Void) -> AlertController {
|
||||
var presentationData = sharedContext.currentPresentationData.with { $0 }
|
||||
if let forceTheme = forceTheme {
|
||||
presentationData = presentationData.withUpdated(theme: forceTheme)
|
||||
@ -733,14 +733,24 @@ func voiceChatUserNameController(sharedContext: SharedAccountContext, account: A
|
||||
guard let contentNode = contentNode else {
|
||||
return
|
||||
}
|
||||
dismissImpl?(true)
|
||||
|
||||
let previousFirstName = firstName ?? ""
|
||||
let previousLastName = firstName ?? ""
|
||||
|
||||
let previousLastName = lastName ?? ""
|
||||
let newFirstName = contentNode.firstName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let newLastName = contentNode.lastName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
apply(newFirstName, newLastName)
|
||||
|
||||
if newFirstName.isEmpty {
|
||||
contentNode.animateError()
|
||||
return
|
||||
}
|
||||
|
||||
dismissImpl?(true)
|
||||
|
||||
if previousFirstName != newFirstName || previousLastName != newLastName {
|
||||
apply((newFirstName, newLastName))
|
||||
} else {
|
||||
apply(nil)
|
||||
}
|
||||
}
|
||||
|
||||
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
|
||||
|
@ -33,6 +33,7 @@ public enum RequestChangeAccountPhoneNumberVerificationError {
|
||||
case invalidPhoneNumber
|
||||
case limitExceeded
|
||||
case phoneNumberOccupied
|
||||
case phoneBanned
|
||||
case generic
|
||||
}
|
||||
|
||||
@ -45,6 +46,8 @@ public func requestChangeAccountPhoneNumberVerification(account: Account, phoneN
|
||||
return .invalidPhoneNumber
|
||||
} else if error.errorDescription == "PHONE_NUMBER_OCCUPIED" {
|
||||
return .phoneNumberOccupied
|
||||
} else if error.errorDescription == "PHONE_NUMBER_BANNED" {
|
||||
return .phoneBanned
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -54,7 +54,7 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode {
|
||||
let referenceNode: ContextReferenceContentNode
|
||||
let containerNode: ContextControllerSourceNode
|
||||
private let backgroundNode: ASImageNode
|
||||
private let backgroundWithIconNode: ASImageNode
|
||||
private let iconNode: ASImageNode
|
||||
private let textNode: ImmediateTextNode
|
||||
private var animationNode: AnimationNode?
|
||||
|
||||
@ -73,11 +73,10 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode {
|
||||
self.backgroundNode = ASImageNode()
|
||||
self.backgroundNode.displaysAsynchronously = false
|
||||
self.backgroundNode.displayWithoutProcessing = true
|
||||
self.backgroundNode.isHidden = true
|
||||
|
||||
self.backgroundWithIconNode = ASImageNode()
|
||||
self.backgroundWithIconNode.displaysAsynchronously = false
|
||||
self.backgroundWithIconNode.displayWithoutProcessing = true
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.displaysAsynchronously = false
|
||||
self.iconNode.displayWithoutProcessing = true
|
||||
|
||||
self.textNode = ImmediateTextNode()
|
||||
self.textNode.displaysAsynchronously = false
|
||||
@ -88,7 +87,7 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode {
|
||||
|
||||
self.containerNode.addSubnode(self.referenceNode)
|
||||
self.referenceNode.addSubnode(self.backgroundNode)
|
||||
self.referenceNode.addSubnode(self.backgroundWithIconNode)
|
||||
self.referenceNode.addSubnode(self.iconNode)
|
||||
self.addSubnode(self.containerNode)
|
||||
self.addSubnode(self.textNode)
|
||||
|
||||
@ -126,13 +125,12 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode {
|
||||
func update(size: CGSize, text: String, icon: PeerInfoHeaderButtonIcon, isActive: Bool, isExpanded: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) {
|
||||
let previousIcon = self.icon
|
||||
let iconUpdated = self.icon != icon
|
||||
if self.theme != presentationData.theme || self.icon != icon || self.isActive != isActive {
|
||||
let isActiveUpdated = self.isActive != isActive
|
||||
self.isActive = isActive
|
||||
if self.theme != presentationData.theme || self.icon != icon {
|
||||
self.theme = presentationData.theme
|
||||
self.icon = icon
|
||||
|
||||
let isActiveUpdated = self.isActive != isActive
|
||||
self.isActive = isActive
|
||||
|
||||
var isGestureEnabled = false
|
||||
if [.mute, .voiceChat, .more].contains(icon) {
|
||||
isGestureEnabled = true
|
||||
@ -195,17 +193,13 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode {
|
||||
}
|
||||
} else {
|
||||
animationNode = AnimationNode(animation: animationName, colors: colors, scale: 1.0)
|
||||
self.addSubnode(animationNode)
|
||||
self.referenceNode.addSubnode(animationNode)
|
||||
self.animationNode = animationNode
|
||||
}
|
||||
animationNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
self.backgroundWithIconNode.isHidden = true
|
||||
self.backgroundNode.isHidden = false
|
||||
} else if let animationNode = self.animationNode {
|
||||
self.animationNode = nil
|
||||
animationNode.removeFromSupernode()
|
||||
self.backgroundWithIconNode.isHidden = false
|
||||
self.backgroundNode.isHidden = true
|
||||
}
|
||||
|
||||
if playOnce {
|
||||
@ -214,34 +208,9 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode {
|
||||
self.animationNode?.seekToEnd()
|
||||
}
|
||||
|
||||
if isActiveUpdated, !self.containerNode.alpha.isZero {
|
||||
let backgroundNode = !self.backgroundNode.isHidden ? self.backgroundNode : self.backgroundWithIconNode
|
||||
if let snapshotView = backgroundNode.view.snapshotContentTree() {
|
||||
snapshotView.frame = backgroundNode.view.frame
|
||||
if let animationNode = self.animationNode {
|
||||
self.view.insertSubview(snapshotView, belowSubview: animationNode.view)
|
||||
} else {
|
||||
self.view.addSubview(snapshotView)
|
||||
}
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
if !isExpanded, let snapshotView = self.textNode.view.snapshotContentTree() {
|
||||
snapshotView.frame = self.textNode.view.frame
|
||||
self.view.addSubview(snapshotView)
|
||||
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
self.backgroundNode.image = generateFilledCircleImage(diameter: 40.0, color: isActive ? presentationData.theme.list.itemAccentColor : presentationData.theme.list.itemDisabledTextColor)
|
||||
self.backgroundWithIconNode.image = generateImage(CGSize(width: 40.0, height: 40.0), contextGenerator: { size, context in
|
||||
self.backgroundNode.image = generateFilledCircleImage(diameter: 40.0, color: presentationData.theme.list.itemAccentColor)
|
||||
self.iconNode.image = generateImage(CGSize(width: 40.0, height: 40.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(isActive ? presentationData.theme.list.itemAccentColor.cgColor : presentationData.theme.list.itemDisabledTextColor.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
context.setBlendMode(.normal)
|
||||
context.setFillColor(presentationData.theme.list.itemCheckColors.foregroundColor.cgColor)
|
||||
let imageName: String?
|
||||
@ -275,15 +244,22 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode {
|
||||
})
|
||||
}
|
||||
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(12.0), textColor: isActive ? presentationData.theme.list.itemAccentColor : presentationData.theme.list.itemDisabledTextColor)
|
||||
let alpha: CGFloat = isActive ? 1.0 : 0.3
|
||||
if isActiveUpdated, !self.containerNode.alpha.isZero {
|
||||
let alphaTransition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||
alphaTransition.updateAlpha(node: self.backgroundNode, alpha: isActive ? 1.0 : 0.3)
|
||||
alphaTransition.updateAlpha(node: self.textNode, alpha: isActive ? 1.0 : 0.3)
|
||||
}
|
||||
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(12.0), textColor: presentationData.theme.list.itemAccentColor)
|
||||
self.accessibilityLabel = text
|
||||
let titleSize = self.textNode.updateLayout(CGSize(width: 120.0, height: .greatestFiniteMagnitude))
|
||||
|
||||
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
transition.updateFrame(node: self.backgroundWithIconNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
transition.updateFrame(node: self.iconNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
transition.updateFrameAdditiveToCenter(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: size.height + 6.0), size: titleSize))
|
||||
transition.updateAlpha(node: self.textNode, alpha: isExpanded ? 0.0 : 1.0)
|
||||
transition.updateAlpha(node: self.textNode, alpha: isExpanded ? 0.0 : alpha)
|
||||
|
||||
self.referenceNode.frame = self.containerNode.bounds
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user