Merge commit 'f82e4c1c7cb2aeea71aff222ec247eae880960b6'

This commit is contained in:
Peter 2018-09-20 22:32:09 +01:00
commit 4e7b02568e
37 changed files with 2356 additions and 2023 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 814 B

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "CallRouteBluetooth@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "CallRouteBluetooth@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "CallRouteSpeaker@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "CallRouteSpeaker@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -36,6 +36,7 @@
09874E592107BD4100E190B8 /* GenericEmbedImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09874E4021075C1700E190B8 /* GenericEmbedImplementation.swift */; };
09AE3823214C110900850BFD /* LegacySecureIdScanController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09AE3822214C110800850BFD /* LegacySecureIdScanController.swift */; };
09C500242142BA6400EF253E /* ItemListWebsiteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C500232142BA6400EF253E /* ItemListWebsiteItem.swift */; };
09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */; };
D007019C2029E8F2006B9E34 /* LegqacyICloudFileController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019B2029E8F2006B9E34 /* LegqacyICloudFileController.swift */; };
D007019E2029EFDD006B9E34 /* ICloudResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019D2029EFDD006B9E34 /* ICloudResources.swift */; };
D00701A12029F6D0006B9E34 /* TGMimeTypeMap.h in Headers */ = {isa = PBXBuildFile; fileRef = D007019F2029F6D0006B9E34 /* TGMimeTypeMap.h */; };
@ -1053,6 +1054,7 @@
09874E4421075C3F00E190B8 /* StreamableEmbedImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamableEmbedImplementation.swift; sourceTree = "<group>"; };
09AE3822214C110800850BFD /* LegacySecureIdScanController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacySecureIdScanController.swift; sourceTree = "<group>"; };
09C500232142BA6400EF253E /* ItemListWebsiteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemListWebsiteItem.swift; sourceTree = "<group>"; };
09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallRouteActionSheetItem.swift; sourceTree = "<group>"; };
D00219051DDD1C9E00BE708A /* ImageContainingNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageContainingNode.swift; sourceTree = "<group>"; };
D002A0D01E9B99F500A81812 /* SoftwareVideoSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SoftwareVideoSource.swift; sourceTree = "<group>"; };
D002A0D21E9BBE6700A81812 /* MultiplexedSoftwareVideoSourceManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiplexedSoftwareVideoSourceManager.swift; sourceTree = "<group>"; };
@ -3711,6 +3713,7 @@
D0F0AAE31EC21AAA005EE2A5 /* CallControllerButtonsNode.swift */,
D0F0AAE51EC21B68005EE2A5 /* CallControllerButton.swift */,
D0ACCB191EC5E0C20079D8BF /* CallControllerKeyPreviewNode.swift */,
09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */,
);
name = Call;
sourceTree = "<group>";
@ -5202,6 +5205,7 @@
D0EC6DD81EB9F58900EBF1C3 /* VerticalListContextResultsChatInputPanelButtonItem.swift in Sources */,
D04281F4200E5AB0009DDE36 /* ChatRecentActionsController.swift in Sources */,
D0B2F76220506E2A00D3BFB9 /* MediaInputSettings.swift in Sources */,
09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */,
D0BFAE4E20AB1D7B00793CF2 /* DisabledContextResultsChatInputContextPanelNode.swift in Sources */,
D064EF871F69A06F00AC0398 /* MessageContentKind.swift in Sources */,
D020A9DA1FEAE675008C66F7 /* OverlayPlayerController.swift in Sources */,

View File

@ -119,17 +119,22 @@ public final class CallController: ViewController {
var items: [ActionSheetItem] = []
for output in availableOutputs {
let title: String
var icon: UIImage?
switch output {
case .builtin:
title = UIDevice.current.model
case .speaker:
title = strongSelf.presentationData.strings.Call_AudioRouteSpeaker
icon = UIImage(bundleImageName: "Call/CallRouteSpeaker")
case .headphones:
title = strongSelf.presentationData.strings.Call_AudioRouteHeadphones
case let .port(port):
title = port.name
if port.type == .bluetooth {
icon = UIImage(bundleImageName: "Call/CallRouteBluetooth")
}
}
items.append(ActionSheetButtonItem(title: title, color: .accent, action: { [weak actionSheet] in
items.append(CallRouteActionSheetItem(title: title, icon: icon, selected: output == currentOutput, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
self?.call.setCurrentAudioOutput(output)
}))

View File

@ -0,0 +1,142 @@
import Foundation
import AsyncDisplayKit
import Display
public class CallRouteActionSheetItem: ActionSheetItem {
public let title: String
public let icon: UIImage?
public let selected: Bool
public let action: () -> Void
public init(title: String, icon: UIImage?, selected: Bool, action: @escaping () -> Void) {
self.title = title
self.icon = icon
self.selected = selected
self.action = action
}
public func node(theme: ActionSheetControllerTheme) -> ActionSheetItemNode {
let node = CallRouteActionSheetItemNode(theme: theme)
node.setItem(self)
return node
}
public func updateNode(_ node: ActionSheetItemNode) {
guard let node = node as? CallRouteActionSheetItemNode else {
assertionFailure()
return
}
node.setItem(self)
}
}
public class CallRouteActionSheetItemNode: ActionSheetItemNode {
private let theme: ActionSheetControllerTheme
public static let defaultFont: UIFont = Font.regular(20.0)
private var item: CallRouteActionSheetItem?
private let button: HighlightTrackingButton
private let label: ASTextNode
private let iconNode: ASImageNode
private let checkNode: ASImageNode
override public init(theme: ActionSheetControllerTheme) {
self.theme = theme
self.button = HighlightTrackingButton()
self.label = ASTextNode()
self.label.isLayerBacked = true
self.label.maximumNumberOfLines = 1
self.label.displaysAsynchronously = false
self.label.truncationMode = .byTruncatingTail
self.iconNode = ASImageNode()
self.iconNode.isUserInteractionEnabled = false
self.iconNode.displayWithoutProcessing = true
self.iconNode.displaysAsynchronously = false
self.checkNode = ASImageNode()
self.checkNode.isUserInteractionEnabled = false
self.checkNode.displayWithoutProcessing = true
self.checkNode.displaysAsynchronously = false
self.checkNode.image = generateImage(CGSize(width: 14.0, height: 11.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setStrokeColor(theme.controlAccentColor.cgColor)
context.setLineWidth(2.0)
context.move(to: CGPoint(x: 12.0, y: 1.0))
context.addLine(to: CGPoint(x: 4.16482734, y: 9.0))
context.addLine(to: CGPoint(x: 1.0, y: 5.81145833))
context.strokePath()
})
super.init(theme: theme)
self.view.addSubview(self.button)
self.label.isUserInteractionEnabled = false
self.addSubnode(self.label)
self.addSubnode(self.iconNode)
self.addSubnode(self.checkNode)
self.button.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
strongSelf.backgroundNode.backgroundColor = strongSelf.theme.itemHighlightedBackgroundColor
} else {
UIView.animate(withDuration: 0.3, animations: {
strongSelf.backgroundNode.backgroundColor = strongSelf.theme.itemBackgroundColor
})
}
}
}
self.button.addTarget(self, action: #selector(self.buttonPressed), for: .touchUpInside)
}
func setItem(_ item: CallRouteActionSheetItem) {
self.item = item
self.label.attributedText = NSAttributedString(string: item.title, font: ActionSheetButtonNode.defaultFont, textColor: self.theme.standardActionTextColor)
if let icon = item.icon {
self.iconNode.image = generateTintedImage(image: icon, color: self.theme.standardActionTextColor)
} else {
self.iconNode.isHidden = true
}
self.checkNode.isHidden = !item.selected
self.setNeedsLayout()
}
public override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 57.0)
}
public override func layout() {
super.layout()
let size = self.bounds.size
self.button.frame = CGRect(origin: CGPoint(), size: size)
let labelSize = self.label.measure(CGSize(width: max(1.0, size.width - 10.0), height: size.height))
self.label.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - labelSize.width) / 2.0), y: floorToScreenPixels((size.height - labelSize.height) / 2.0)), size: labelSize)
if let image = self.iconNode.image {
self.iconNode.frame = CGRect(origin: CGPoint(x: 12.0, y: floor((size.height - image.size.height) / 2.0)), size: image.size)
}
if let image = self.checkNode.image {
self.checkNode.frame = CGRect(origin: CGPoint(x: size.width - image.size.width - 13.0, y: floor((size.height - image.size.height) / 2.0)), size: image.size)
}
}
@objc func buttonPressed() {
if let item = self.item {
item.action()
}
}
}

View File

@ -503,10 +503,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode {
var preferredAction = ShareControllerPreferredAction.default
if let generalMessageContentKind = generalMessageContentKind {
switch generalMessageContentKind {
case .image, .video:
preferredAction = .saveToCameraRoll
default:
break
case .image, .video:
preferredAction = .saveToCameraRoll
default:
break
}
}
@ -517,13 +517,17 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode {
subject = .image(image.representations)
} else if let webpage = m as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content, let _ = content.image {
preferredAction = .saveToCameraRoll
} else if let file = m as? TelegramMediaFile, file.isAnimated {
preferredAction = .custom(action: ShareControllerAction(title: presentationData.strings.Preview_SaveGif, action: { [weak self] in
if let strongSelf = self {
let message = messages[0]
let _ = addSavedGif(postbox: strongSelf.account.postbox, fileReference: .message(message: MessageReference(message), media: file)).start()
}
}))
} else if let file = m as? TelegramMediaFile {
if file.isAnimated {
preferredAction = .custom(action: ShareControllerAction(title: presentationData.strings.Preview_SaveGif, action: { [weak self] in
if let strongSelf = self {
let message = messages[0]
let _ = addSavedGif(postbox: strongSelf.account.postbox, fileReference: .message(message: MessageReference(message), media: file)).start()
}
}))
} else if file.mimeType.hasPrefix("image/") || file.mimeType.hasPrefix("video/") {
preferredAction = .saveToCameraRoll
}
}
}
let shareController = ShareController(account: strongSelf.account, subject: subject, preferredAction: preferredAction)

View File

@ -1471,8 +1471,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
switch gesture {
case .tap:
if let avatarNode = self.accessoryItemNode as? ChatMessageAvatarAccessoryItemNode, avatarNode.frame.contains(location) {
if let avatarNode = self.accessoryItemNode as? ChatMessageAvatarAccessoryItemNode, avatarNode.frame.contains(location) {
if let item = self.item, let author = item.content.firstMessage.author {
let navigate: ChatControllerInteractionNavigateToPeer
if item.content.firstMessage.id.peerId == item.account.peerId {

View File

@ -70,8 +70,8 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
var textString: NSAttributedString?
var updatedContactInfo: String?
var displayName: String = ""
if let selectedContact = selectedContact {
let displayName: String
if !selectedContact.firstName.isEmpty && !selectedContact.lastName.isEmpty {
displayName = "\(selectedContact.firstName) \(selectedContact.lastName)"
} else if !selectedContact.firstName.isEmpty {
@ -79,13 +79,16 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
} else {
displayName = selectedContact.lastName
}
titleString = NSAttributedString(string: displayName, font: titleFont, textColor: item.message.effectivelyIncoming(item.account.peerId) ? item.presentationData.theme.theme.chat.bubble.incomingAccentTextColor : item.presentationData.theme.theme.chat.bubble.outgoingAccentTextColor)
let info: String
if let previousContact = previousContact, previousContact.isEqual(to: selectedContact), let contactInfo = previousContactInfo {
info = contactInfo
} else {
if let vCard = selectedContact.vCardData, let vCardData = vCard.data(using: .utf8), let contactData = DeviceContactExtendedData(vcard: vCardData) {
if displayName.isEmpty && !contactData.organization.isEmpty {
displayName = contactData.organization
}
let infoLineLimit = 5
var infoComponents: [String] = []
if !contactData.basicData.phoneNumbers.isEmpty {
@ -105,7 +108,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
}
}
if infoComponents.count < infoLineLimit {
if !contactData.organization.isEmpty && (!contactData.basicData.firstName.isEmpty || !contactData.basicData.lastName.isEmpty) {
if !contactData.organization.isEmpty && displayName != contactData.organization {
infoComponents.append(contactData.organization)
}
}
@ -117,6 +120,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
updatedContactInfo = info
titleString = NSAttributedString(string: displayName, font: titleFont, textColor: item.message.effectivelyIncoming(item.account.peerId) ? item.presentationData.theme.theme.chat.bubble.incomingAccentTextColor : item.presentationData.theme.theme.chat.bubble.outgoingAccentTextColor)
textString = NSAttributedString(string: info, font: textFont, textColor: item.message.effectivelyIncoming(item.account.peerId) ? item.presentationData.theme.theme.chat.bubble.incomingPrimaryTextColor : item.presentationData.theme.theme.chat.bubble.outgoingPrimaryTextColor)
} else {
updatedContactInfo = nil
@ -230,6 +234,8 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
customLetters = [String(firstName[..<firstName.index(after: firstName.startIndex)]).uppercased()]
} else if !lastName.isEmpty {
customLetters = [String(lastName[..<lastName.index(after: lastName.startIndex)]).uppercased()]
} else {
customLetters = [String(displayName[..<displayName.index(after: displayName.startIndex)]).uppercased()]
}
}

View File

@ -330,9 +330,12 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
return result
}
if let webPage = self.webPage, case let .Loaded(content) = webPage.content {
if content.instantPage != nil {
return .instantPage
if let webPage = self.webPage, case let .Loaded(content) = webPage.content, content.instantPage != nil {
switch instantPageType(of: content) {
case .album:
return .none
default:
return .instantPage
}
}
if self.contentNode.hasActionAtPoint(point.offsetBy(dx: -contentNodeFrame.minX, dy: -contentNodeFrame.minY)) {

View File

@ -65,7 +65,7 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
let contentRightInset: CGFloat = 18.0 + rightInset
let closeButtonSize = self.closeButton.measure(CGSize(width: 100.0, height: 100.0))
transition.updateFrame(node: self.closeButton, frame: CGRect(origin: CGPoint(x: width - contentRightInset - closeButtonSize.width, y: 14.0), size: closeButtonSize))
transition.updateFrame(node: self.closeButton, frame: CGRect(origin: CGPoint(x: width - contentRightInset - closeButtonSize.width, y: floorToScreenPixels((panelHeight - closeButtonSize.height) / 2.0)), size: closeButtonSize))
let updatedButtons: [ChatReportPeerTitleButton]
if let _ = interfaceState.renderedPeer?.peer {

View File

@ -308,16 +308,21 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
self.infoNode.attributedText = string
shouldUpdateLayout = true
}
} else if let peer = peerViewMainPeer(peerView), let presence = peerView.peerPresences[peer.id] as? TelegramUserPresence {
} else if let peer = peerViewMainPeer(peerView) {
let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
let (string, activity) = stringAndActivityForUserPresence(strings: self.strings, timeFormat: self.timeFormat, presence: presence, relativeTo: Int32(timestamp))
let userPresence: TelegramUserPresence
if let presence = peerView.peerPresences[peer.id] as? TelegramUserPresence {
userPresence = presence
self.presenceManager?.reset(presence: presence)
} else {
userPresence = TelegramUserPresence(status: .none)
}
let (string, activity) = stringAndActivityForUserPresence(strings: self.strings, timeFormat: self.timeFormat, presence: userPresence, relativeTo: Int32(timestamp))
let attributedString = NSAttributedString(string: string, font: Font.regular(13.0), textColor: activity ? self.theme.rootController.navigationBar.accentTextColor : self.theme.rootController.navigationBar.secondaryTextColor)
if self.infoNode.attributedText == nil || !self.infoNode.attributedText!.isEqual(to: attributedString) {
self.infoNode.attributedText = attributedString
shouldUpdateLayout = true
}
self.presenceManager?.reset(presence: presence)
} else {
let string = NSAttributedString(string: "", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)
if self.infoNode.attributedText == nil || !self.infoNode.attributedText!.isEqual(to: string) {

View File

@ -468,12 +468,11 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
case .none:
break
case let .presence(presence, timeFormat):
if let presence = presence as? TelegramUserPresence {
userPresence = presence
let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
let (string, activity) = stringAndActivityForUserPresence(strings: item.strings, timeFormat: timeFormat, presence: presence, relativeTo: Int32(timestamp))
statusAttributedString = NSAttributedString(string: string, font: statusFont, textColor: activity ? item.theme.list.itemAccentColor : item.theme.list.itemSecondaryTextColor)
}
let presence = (presence as? TelegramUserPresence) ?? TelegramUserPresence(status: .none)
userPresence = presence
let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
let (string, activity) = stringAndActivityForUserPresence(strings: item.strings, timeFormat: timeFormat, presence: presence, relativeTo: Int32(timestamp))
statusAttributedString = NSAttributedString(string: string, font: statusFont, textColor: activity ? item.theme.list.itemAccentColor : item.theme.list.itemSecondaryTextColor)
case let .addressName(suffix):
if let addressName = peer.addressName {
let addressNameString = NSAttributedString(string: "@" + addressName, font: statusFont, textColor: item.theme.list.itemAccentColor)

View File

@ -14,7 +14,7 @@ final class DateSelectionActionSheetController: ActionSheetController {
return self._ready
}
init(theme: PresentationTheme, strings: PresentationStrings, currentValue: Int32, minimumDate: Date? = nil, maximumDate: Date? = nil, emptyTitle: String? = nil, applyValue: @escaping (Int32?) -> Void) {
init(theme: PresentationTheme, strings: PresentationStrings, title: String?, currentValue: Int32, minimumDate: Date? = nil, maximumDate: Date? = nil, emptyTitle: String? = nil, applyValue: @escaping (Int32?) -> Void) {
self.theme = theme
self.strings = strings
@ -24,6 +24,9 @@ final class DateSelectionActionSheetController: ActionSheetController {
var updatedValue = currentValue
var items: [ActionSheetItem] = []
if let title = title {
items.append(ActionSheetTextItem(title: title))
}
items.append(DateSelectionActionSheetItem(strings: strings, currentValue: currentValue, minimumDate: minimumDate, maximumDate: maximumDate, valueChanged: { value in
updatedValue = value
}))

View File

@ -315,7 +315,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
func item(_ arguments: DeviceContactInfoControllerArguments) -> ListViewItem {
switch self {
case let .info(_, theme, strings, peer, state, jobSummary):
return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, mode: .generic, peer: peer, presence: nil, label: jobSummary, cachedData: nil, state: state, sectionId: self.section, style: .plain, editingNameUpdated: { editingName in
return ItemListAvatarAndNameInfoItem(account: arguments.account, theme: theme, strings: strings, mode: .contact, peer: peer, presence: nil, label: jobSummary, cachedData: nil, state: state, sectionId: self.section, style: .plain, editingNameUpdated: { editingName in
arguments.updateEditingName(editingName)
}, avatarTapped: {
}, context: nil, call: nil)

View File

@ -137,6 +137,8 @@ final class FormControllerTextInputItemNode: FormBlockItemNode<FormControllerTex
self.textField.textField.returnKeyType = item.returnKeyType
}
self.textField.textField.keyboardAppearance = theme.chatList.searchBarKeyboardColor.keyboardAppearance
let attributedPlaceholder = NSAttributedString(string: item.placeholder, font: textFont, textColor: theme.list.itemPlaceholderTextColor)
if !(self.textField.textField.attributedPlaceholder?.isEqual(to: attributedPlaceholder) ?? false) {
self.textField.textField.attributedPlaceholder = attributedPlaceholder

View File

@ -2,14 +2,14 @@ import Foundation
import Postbox
import SwiftSignalKit
enum InstantPageThemeType: Int32 {
public enum InstantPageThemeType: Int32 {
case light = 0
case dark = 1
case sepia = 2
case gray = 3
}
enum InstantPagePresentationFontSize: Int32 {
public enum InstantPagePresentationFontSize: Int32 {
case small = 0
case standard = 1
case large = 2
@ -17,36 +17,36 @@ enum InstantPagePresentationFontSize: Int32 {
case xxlarge = 4
}
final class InstantPagePresentationSettings: PreferencesEntry, Equatable {
static var defaultSettings = InstantPagePresentationSettings(themeType: .light, fontSize: .standard, forceSerif: false, autoNightMode: true)
public final class InstantPagePresentationSettings: PreferencesEntry, Equatable {
public static var defaultSettings = InstantPagePresentationSettings(themeType: .light, fontSize: .standard, forceSerif: false, autoNightMode: true)
let themeType: InstantPageThemeType
let fontSize: InstantPagePresentationFontSize
let forceSerif: Bool
let autoNightMode: Bool
public var themeType: InstantPageThemeType
public var fontSize: InstantPagePresentationFontSize
public var forceSerif: Bool
public var autoNightMode: Bool
init(themeType: InstantPageThemeType, fontSize: InstantPagePresentationFontSize, forceSerif: Bool, autoNightMode: Bool) {
public init(themeType: InstantPageThemeType, fontSize: InstantPagePresentationFontSize, forceSerif: Bool, autoNightMode: Bool) {
self.themeType = themeType
self.fontSize = fontSize
self.forceSerif = forceSerif
self.autoNightMode = autoNightMode
}
init(decoder: PostboxDecoder) {
public init(decoder: PostboxDecoder) {
self.themeType = InstantPageThemeType(rawValue: decoder.decodeInt32ForKey("themeType", orElse: 0))!
self.fontSize = InstantPagePresentationFontSize(rawValue: decoder.decodeInt32ForKey("fontSize", orElse: 0))!
self.forceSerif = decoder.decodeInt32ForKey("forceSerif", orElse: 0) != 0
self.autoNightMode = decoder.decodeInt32ForKey("autoNightMode", orElse: 0) != 0
}
func encode(_ encoder: PostboxEncoder) {
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt32(self.themeType.rawValue, forKey: "themeType")
encoder.encodeInt32(self.fontSize.rawValue, forKey: "fontSize")
encoder.encodeInt32(self.forceSerif ? 1 : 0, forKey: "forceSerif")
encoder.encodeInt32(self.autoNightMode ? 1 : 0, forKey: "autoNightMode")
}
func isEqual(to: PreferencesEntry) -> Bool {
public func isEqual(to: PreferencesEntry) -> Bool {
if let to = to as? InstantPagePresentationSettings {
return self == to
} else {
@ -54,7 +54,7 @@ final class InstantPagePresentationSettings: PreferencesEntry, Equatable {
}
}
static func ==(lhs: InstantPagePresentationSettings, rhs: InstantPagePresentationSettings) -> Bool {
public static func ==(lhs: InstantPagePresentationSettings, rhs: InstantPagePresentationSettings) -> Bool {
if lhs.themeType != rhs.themeType {
return false
}

View File

@ -143,6 +143,7 @@ enum ItemListAvatarAndNameInfoItemUpdatingAvatar: Equatable {
enum ItemListAvatarAndNameInfoItemMode {
case generic
case contact
case settings
case editSettings
}
@ -402,14 +403,15 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite
statusText += "@\(username)"
}
statusColor = item.theme.list.itemSecondaryTextColor
case .generic, .editSettings:
case .generic, .contact, .editSettings:
if let label = item.label {
statusText = label
statusColor = item.theme.list.itemSecondaryTextColor
} else if let _ = peer.botInfo {
statusText = item.strings.Bot_GenericBotStatus
statusColor = item.theme.list.itemSecondaryTextColor
} else if let presence = item.presence as? TelegramUserPresence {
} else if case .generic = item.mode {
let presence = (item.presence as? TelegramUserPresence) ?? TelegramUserPresence(status: .none)
let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
let (string, activity) = stringAndActivityForUserPresence(strings: item.strings, timeFormat: .regular, presence: presence, relativeTo: Int32(timestamp))
statusText = string

View File

@ -175,7 +175,7 @@ final class ListMessageSnippetItemNode: ListMessageNode {
selectedMedia = webpage
if case let .Loaded(content) = webpage.content {
if content.instantPage != nil {
if content.instantPage != nil && instantPageType(of: content) != .album {
isInstantView = true
}

View File

@ -24,9 +24,9 @@ public enum AudioPlaybackRate: Int32 {
}
public struct MusicPlaybackSettings: PreferencesEntry, Equatable {
public let order: MusicPlaybackSettingsOrder
public let looping: MusicPlaybackSettingsLooping
public let voicePlaybackRate: AudioPlaybackRate
public var order: MusicPlaybackSettingsOrder
public var looping: MusicPlaybackSettingsLooping
public var voicePlaybackRate: AudioPlaybackRate
public static var defaultSettings: MusicPlaybackSettings {
return MusicPlaybackSettings(order: .regular, looping: .none, voicePlaybackRate: .x1)

View File

@ -15,8 +15,6 @@ public enum PresentationPersonNameOrder {
case lastFirst
}
public final class PresentationData: Equatable {
public let strings: PresentationStrings
public let theme: PresentationTheme
@ -370,3 +368,12 @@ public func updatedPresentationData(postbox: Postbox) -> Signal<PresentationData
}
}
}
public func defaultPresentationData() -> PresentationData {
let timeFormat = currentTimeFormat()
let nameDisplayOrder = currentPersonNameDisplayOrder()
let nameSortOrder = currentPersonNameSortOrder()
let themeSettings = PresentationThemeSettings.defaultSettings
return PresentationData(strings: defaultPresentationStrings, theme: defaultPresentationTheme, chatWallpaper: .builtin, fontSize: themeSettings.fontSize, timeFormat: timeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder)
}

View File

@ -318,7 +318,7 @@ struct PresentationResourcesChat {
static func chatInputPanelEncircledCloseIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatInputPanelEncircledCloseIconImage.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/EncircledCloseButton"), color: theme.chat.serviceMessage.serviceMessagePrimaryTextColor)
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/EncircledCloseButton"), color: theme.chat.inputPanel.panelControlAccentColor)
})
}

File diff suppressed because it is too large Load Diff

View File

@ -12,8 +12,9 @@ private final class ProxySettingsControllerArguments {
let removeServer: (ProxyServerSettings) -> Void
let setServerWithRevealedOptions: (ProxyServerSettings?, ProxyServerSettings?) -> Void
let toggleUseForCalls: (Bool) -> Void
let shareProxyList: () -> Void
init(toggleEnabled: @escaping (Bool) -> Void, addNewServer: @escaping () -> Void, activateServer: @escaping (ProxyServerSettings) -> Void, editServer: @escaping (ProxyServerSettings) -> Void, removeServer: @escaping (ProxyServerSettings) -> Void, setServerWithRevealedOptions: @escaping (ProxyServerSettings?, ProxyServerSettings?) -> Void, toggleUseForCalls: @escaping (Bool) -> Void) {
init(toggleEnabled: @escaping (Bool) -> Void, addNewServer: @escaping () -> Void, activateServer: @escaping (ProxyServerSettings) -> Void, editServer: @escaping (ProxyServerSettings) -> Void, removeServer: @escaping (ProxyServerSettings) -> Void, setServerWithRevealedOptions: @escaping (ProxyServerSettings?, ProxyServerSettings?) -> Void, toggleUseForCalls: @escaping (Bool) -> Void, shareProxyList: @escaping () -> Void) {
self.toggleEnabled = toggleEnabled
self.addNewServer = addNewServer
self.activateServer = activateServer
@ -21,6 +22,7 @@ private final class ProxySettingsControllerArguments {
self.removeServer = removeServer
self.setServerWithRevealedOptions = setServerWithRevealedOptions
self.toggleUseForCalls = toggleUseForCalls
self.shareProxyList = shareProxyList
}
}
@ -52,6 +54,7 @@ private enum ProxySettingsControllerEntry: ItemListNodeEntry {
case serversHeader(PresentationTheme, String)
case addServer(PresentationTheme, String, Bool)
case server(Int, PresentationTheme, PresentationStrings, ProxyServerSettings, Bool, DisplayProxyServerStatus, ProxySettingsServerItemEditing, Bool)
case shareProxyList(PresentationTheme, String)
case useForCalls(PresentationTheme, String, Bool)
case useForCallsInfo(PresentationTheme, String)
@ -59,7 +62,7 @@ private enum ProxySettingsControllerEntry: ItemListNodeEntry {
switch self {
case .enabled:
return ProxySettingsControllerSection.enabled.rawValue
case .serversHeader, .addServer, .server:
case .serversHeader, .addServer, .server, .shareProxyList:
return ProxySettingsControllerSection.servers.rawValue
case .useForCalls, .useForCallsInfo:
return ProxySettingsControllerSection.calls.rawValue
@ -76,10 +79,12 @@ private enum ProxySettingsControllerEntry: ItemListNodeEntry {
return .index(2)
case let .server(_, _, _, settings, _, _, _, _):
return .server(settings.host, settings.port, settings.connection)
case .useForCalls:
case .shareProxyList:
return .index(3)
case .useForCallsInfo:
case .useForCalls:
return .index(4)
case .useForCallsInfo:
return .index(5)
}
}
@ -109,6 +114,12 @@ private enum ProxySettingsControllerEntry: ItemListNodeEntry {
} else {
return false
}
case let .shareProxyList(lhsTheme, lhsText):
if case let .shareProxyList(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .useForCalls(lhsTheme, lhsText, lhsValue):
if case let .useForCalls(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
@ -156,12 +167,19 @@ private enum ProxySettingsControllerEntry: ItemListNodeEntry {
default:
return true
}
case .useForCalls:
case .shareProxyList:
switch rhs {
case .enabled, .serversHeader, .addServer, .server, .useForCalls:
return false
default:
return true
}
case .useForCalls:
switch rhs {
case .enabled, .serversHeader, .addServer, .server, .shareProxyList, .useForCalls:
return false
default:
return true
}
case .useForCallsInfo:
return false
@ -181,7 +199,7 @@ private enum ProxySettingsControllerEntry: ItemListNodeEntry {
case let .serversHeader(theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .addServer(theme, text, editing):
return ProxySettingsActionItem(theme: theme, title: text, sectionId: self.section, editing: editing, action: {
return ProxySettingsActionItem(theme: theme, title: text, sectionId: self.section, editing: false, action: {
arguments.addNewServer()
})
case let .server(_, theme, strings, settings, active, status, editing, enabled):
@ -194,6 +212,10 @@ private enum ProxySettingsControllerEntry: ItemListNodeEntry {
}, removeServer: { _ in
arguments.removeServer(settings)
})
case let .shareProxyList(theme, text):
return ProxySettingsActionItem(theme: theme, title: text, sectionId: self.section, editing: false, action: {
arguments.shareProxyList()
})
case let .useForCalls(theme, text, value):
return ItemListSwitchItem(theme: theme, title: text, value: value, enableInteractiveChanges: true, enabled: true, sectionId: self.section, style: .blocks, updated: { value in
arguments.toggleUseForCalls(value)
@ -229,19 +251,32 @@ private func proxySettingsControllerEntries(theme: PresentationTheme, strings: P
displayStatus = DisplayProxyServerStatus(activity: false, text: text, textActive: true)
}
} else {
var text: String
switch server.connection {
case .socks5:
text = strings.ChatSettings_ConnectionType_UseSocks5
case .mtp:
text = strings.SocksProxySetup_ProxyTelegram
}
switch status {
case .notAvailable:
displayStatus = DisplayProxyServerStatus(activity: false, text: strings.SocksProxySetup_ProxyStatusUnavailable, textActive: false)
text = text + ", " + strings.SocksProxySetup_ProxyStatusUnavailable
displayStatus = DisplayProxyServerStatus(activity: false, text: text, textActive: false)
case .checking:
displayStatus = DisplayProxyServerStatus(activity: false, text: strings.SocksProxySetup_ProxyStatusChecking, textActive: false)
text = text + ", " + strings.SocksProxySetup_ProxyStatusChecking
displayStatus = DisplayProxyServerStatus(activity: false, text: text, textActive: false)
case let .available(rtt):
let pingTime: Int = Int(rtt * 1000.0)
displayStatus = DisplayProxyServerStatus(activity: false, text: strings.SocksProxySetup_ProxyStatusPing("\(pingTime)").0, textActive: false)
text = text + ", \(strings.SocksProxySetup_ProxyStatusPing("\(pingTime)").0)"
displayStatus = DisplayProxyServerStatus(activity: false, text: text, textActive: false)
}
}
entries.append(.server(index, theme, strings, server, server == proxySettings.activeServer, displayStatus, ProxySettingsServerItemEditing(editable: true, editing: state.editing, revealed: state.revealedServer == server), proxySettings.enabled))
index += 1
}
if !proxySettings.servers.isEmpty {
entries.append(.shareProxyList(theme, strings.SocksProxySetup_ShareProxyList))
}
if let activeServer = proxySettings.activeServer, case .socks5 = activeServer.connection {
entries.append(.useForCalls(theme, strings.SocksProxySetup_UseForCalls, proxySettings.useForCalls))
@ -285,6 +320,8 @@ public func proxySettingsController(postbox: Postbox, network: Network, mode: Pr
}
}
var shareProxyListImpl: (() -> Void)?
let arguments = ProxySettingsControllerArguments(toggleEnabled: { value in
let _ = updateProxySettingsInteractively(postbox: postbox, network: network, { current in
var current = current
@ -332,17 +369,19 @@ public func proxySettingsController(postbox: Postbox, network: Network, mode: Pr
current.useForCalls = value
return current
}).start()
}, shareProxyList: {
shareProxyListImpl?()
})
let proxySettings = Promise<ProxySettings>()
proxySettings.set(postbox.preferencesView(keys: [PreferencesKeys.proxySettings])
|> map { preferencesView -> ProxySettings in
if let value = preferencesView.values[PreferencesKeys.proxySettings] as? ProxySettings {
return value
} else {
return ProxySettings.defaultSettings
}
})
|> map { preferencesView -> ProxySettings in
if let value = preferencesView.values[PreferencesKeys.proxySettings] as? ProxySettings {
return value
} else {
return ProxySettings.defaultSettings
}
})
let statusesContext = ProxyServersStatuses(network: network, servers: proxySettings.get()
|> map { proxySettings -> [ProxyServerSettings] in
@ -444,5 +483,45 @@ public func proxySettingsController(postbox: Postbox, network: Network, mode: Pr
return current
}).start()
}
shareProxyListImpl = { [weak controller] in
guard let strongController = controller else {
return
}
let _ = (proxySettings.get()
|> take(1)
|> deliverOnMainQueue).start(next: { settings in
var result = ""
for server in settings.servers {
if !result.isEmpty {
result += "\n\n"
}
var string: String
switch server.connection {
case let .mtp(secret):
let secret = hexString(secret)
string = "https://t.me/proxy?server=\(server.host)&port=\(server.port)"
string += "&secret=\((secret as NSString).addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryValueAllowed) ?? "")"
case let .socks5(username, password):
string = "https://t.me/socks?server=\(server.host)&port=\(server.port)"
if let username = username, let password = password {
string += "&user=\((username as NSString).addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryValueAllowed) ?? "")&pass=\((password as NSString).addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryValueAllowed) ?? "")"
}
}
result += string
}
let activityController = UIActivityViewController(activityItems: [result], applicationActivities: nil)
if let window = strongController.view.window, let rootViewController = window.rootViewController {
activityController.popoverPresentationController?.sourceView = window
activityController.popoverPresentationController?.sourceRect = CGRect(origin: CGPoint(x: window.bounds.width / 2.0, y: window.bounds.size.height - 1.0), size: CGSize(width: 1.0, height: 1.0))
rootViewController.present(activityController, animated: true, completion: nil)
}
})
}
return controller
}

View File

@ -268,28 +268,12 @@ func proxyServerSettingsController(theme: PresentationTheme, strings: Presentati
var presentImpl: ((ViewController, Any?) -> Void)?
var dismissImpl: (() -> Void)?
var shareImpl: (() -> Void)?
let arguments = proxyServerSettingsControllerArguments(updateState: { f in
updateState(f)
}, share: {
let state = stateValue.with { $0 }
if state.isComplete {
let presentationData: (theme: PresentationTheme, strings: PresentationStrings) = (theme, strings)
var result: String
switch state.mode {
case .mtp:
result = "https://t.me/proxy?server=\(state.host)&port=\(state.port)"
result += "&secret=\((state.secret as NSString).addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryValueAllowed) ?? "")"
case .socks5:
result = "https://t.me/socks?server=\(state.host)&port=\(state.port)"
if !state.username.isEmpty {
result += "&user=\((state.username as NSString).addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryValueAllowed) ?? "")&pass=\((state.password as NSString).addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryValueAllowed) ?? "")"
}
}
UIPasteboard.general.string = result
presentImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.Username_LinkCopied, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}
shareImpl?()
}, usePasteboardSettings: {
if let pasteboardSettings = pasteboardSettings {
updateState { state in
@ -371,6 +355,36 @@ func proxyServerSettingsController(theme: PresentationTheme, strings: Presentati
dismissImpl = { [weak controller] in
let _ = controller?.dismiss()
}
shareImpl = { [weak controller] in
guard let strongController = controller else {
return
}
let state = stateValue.with { $0 }
if state.isComplete {
var result: String
switch state.mode {
case .mtp:
result = "https://t.me/proxy?server=\(state.host)&port=\(state.port)"
result += "&secret=\((state.secret as NSString).addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryValueAllowed) ?? "")"
case .socks5:
result = "https://t.me/socks?server=\(state.host)&port=\(state.port)"
if !state.username.isEmpty {
result += "&user=\((state.username as NSString).addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryValueAllowed) ?? "")&pass=\((state.password as NSString).addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryValueAllowed) ?? "")"
}
}
let activityController = UIActivityViewController(activityItems: [result], applicationActivities: nil)
if let window = strongController.view.window, let rootViewController = window.rootViewController {
activityController.popoverPresentationController?.sourceView = window
activityController.popoverPresentationController?.sourceRect = CGRect(origin: CGPoint(x: window.bounds.width / 2.0, y: window.bounds.size.height - 1.0), size: CGSize(width: 1.0, height: 1.0))
rootViewController.present(activityController, animated: true, completion: nil)
}
}
}
return controller
}

View File

@ -176,7 +176,9 @@ final class SecureIdAuthController: ViewController {
if appUpdateRequired {
let errorText = strongSelf.presentationData.strings.Passport_UpdateRequiredError
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Application_Update, action: {})]), in: .window(.root))
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Application_Update, action: {
account.telegramApplicationContext.applicationBindings.openAppStorePage()
})]), in: .window(.root))
} else if let callbackUrl = callbackUrl, let peerId = peerId {
let errorText = strongSelf.presentationData.strings.Login_UnknownError
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {

View File

@ -724,27 +724,27 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode {
let primaryLanguageByCountry = list.primaryLanguageByCountry ?? [:]
switch field {
case .personalDetails:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .identity(details: ParsedRequestedPersonalDetails(nativeNames: true), document: nil, selfie: false, translations: false), primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .identity(details: ParsedRequestedPersonalDetails(nativeNames: false), document: nil, selfie: false, translations: false), requestOptionalData: true, primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .passport:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .identity(details: nil, document: .passport, selfie: true, translations: true), primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .identity(details: nil, document: .passport, selfie: false, translations: false), requestOptionalData: true, primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .internalPassport:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .identity(details: nil, document: .internalPassport, selfie: true, translations: true), primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .identity(details: nil, document: .internalPassport, selfie: false, translations: false), requestOptionalData: true, primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .driversLicense:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .identity(details: nil, document: .driversLicense, selfie: true, translations: true), primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .identity(details: nil, document: .driversLicense, selfie: false, translations: false), requestOptionalData: true, primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .idCard:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .identity(details: nil, document: .idCard, selfie: true, translations: true), primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .passportRegistration:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .address(details: false, document: .passportRegistration, translations: true), primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .temporaryRegistration:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .address(details: false, document: .temporaryRegistration, translations: true), primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .identity(details: nil, document: .idCard, selfie: false, translations: false), requestOptionalData: true, primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .address:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .address(details: true, document: nil, translations: false), primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .utilityBill:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .address(details: false, document: .utilityBill, translations: true), primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .address(details: false, document: .utilityBill, translations: false), requestOptionalData: true, primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .bankStatement:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .address(details: false, document: .bankStatement, translations: true), primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .address(details: false, document: .bankStatement, translations: false), requestOptionalData: true, primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .rentalAgreement:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .address(details: false, document: .rentalAgreement, translations: true), primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .address(details: false, document: .rentalAgreement, translations: false), requestOptionalData: true, primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .passportRegistration:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .address(details: false, document: .passportRegistration, translations: false), requestOptionalData: true, primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .temporaryRegistration:
strongSelf.interaction.present(SecureIdDocumentFormController(account: strongSelf.account, context: context, requestedData: .address(details: false, document: .temporaryRegistration, translations: false), requestOptionalData: true, primaryLanguageByCountry: primaryLanguageByCountry, values: values, updatedValues: updatedValues(field)), nil)
case .phone:
break
case .email:

View File

@ -584,17 +584,12 @@ private func fieldTitleAndText(field: SecureIdParsedRequestedFormField, strings:
if let filledDocument = filledDocument, isOneOf {
text = stringForDocumentType(filledDocument.0, strings: strings)
}
if let personalDetails = personalDetails {
if let _ = personalDetails {
if let value = findValue(values, key: .personalDetails), case let .personalDetails(personalDetailsValue) = value.1.value {
if !text.isEmpty {
text.append(", ")
}
let fullName: String
if let nativeName = personalDetailsValue.nativeName, !nativeName.firstName.isEmpty, personalDetails.nativeNames {
fullName = nativeName.firstName + " " + nativeName.lastName
} else {
fullName = personalDetailsValue.latinName.firstName + " " + personalDetailsValue.latinName.lastName
}
let fullName = personalDetailsValue.latinName.firstName + " " + personalDetailsValue.latinName.lastName
text.append(fieldsText(fullName, countryName(code: personalDetailsValue.countryCode, strings: strings)))
}
}

View File

@ -66,6 +66,8 @@ final class SecureIdAuthListContentNode: ASDisplayNode, SecureIdAuthContentNode,
fieldNode.updateValues(values)
}
self.deleteNode.isHidden = values.isEmpty
self.requestLayout()
}

View File

@ -17,16 +17,18 @@ final class SecureIdDocumentFormController: FormController<SecureIdDocumentFormS
private let context: SecureIdAccessContext
private let requestedData: SecureIdDocumentFormRequestedData
private let requestOptionalData: Bool
private let primaryLanguageByCountry: [String: String]
private var values: [SecureIdValueWithContext]
private var doneItem: UIBarButtonItem?
init(account: Account, context: SecureIdAccessContext, requestedData: SecureIdDocumentFormRequestedData, primaryLanguageByCountry: [String: String], values: [SecureIdValueWithContext], updatedValues: @escaping ([SecureIdValueWithContext]) -> Void) {
init(account: Account, context: SecureIdAccessContext, requestedData: SecureIdDocumentFormRequestedData, requestOptionalData: Bool = false, primaryLanguageByCountry: [String: String], values: [SecureIdValueWithContext], updatedValues: @escaping ([SecureIdValueWithContext]) -> Void) {
self.account = account
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
self.context = context
self.requestedData = requestedData
self.requestOptionalData = requestOptionalData
self.primaryLanguageByCountry = primaryLanguageByCountry
self.values = values
self.updatedValues = updatedValues
@ -132,6 +134,6 @@ final class SecureIdDocumentFormController: FormController<SecureIdDocumentFormS
for value in self.values {
values[value.value.key] = value
}
self.controllerNode.updateInnerState(transition: .immediate, with: SecureIdDocumentFormState(requestedData: self.requestedData, values: values, primaryLanguageByCountry: self.primaryLanguageByCountry))
self.controllerNode.updateInnerState(transition: .immediate, with: SecureIdDocumentFormState(requestedData: self.requestedData, values: values, requestOptionalData: self.requestOptionalData, primaryLanguageByCountry: self.primaryLanguageByCountry))
}
}

View File

@ -433,6 +433,7 @@ struct SecureIdDocumentFormState: FormControllerInnerState {
fileprivate var translationsRequired: Bool
fileprivate var translations: [SecureIdVerificationDocument]
fileprivate var actionState: SecureIdDocumentFormActionState
fileprivate var requestOptionalData: Bool
func isEqual(to: SecureIdDocumentFormState) -> Bool {
if !self.documentState.isEqual(to: to.documentState) {
@ -472,6 +473,9 @@ struct SecureIdDocumentFormState: FormControllerInnerState {
return false
}
}
if self.requestOptionalData != to.requestOptionalData {
return false
}
return true
}
@ -506,7 +510,7 @@ struct SecureIdDocumentFormState: FormControllerInnerState {
result.append(.entry(SecureIdDocumentFormEntry.countryCode(.identity, details.countryCode, self.previousValues[.personalDetails]?.errors[.field(.personalDetails(.countryCode))])))
result.append(.entry(SecureIdDocumentFormEntry.residenceCountryCode(details.residenceCountryCode, self.previousValues[.personalDetails]?.errors[.field(.personalDetails(.residenceCountryCode))])))
if details.nativeNameRequired && !details.residenceCountryCode.isEmpty && details.primaryLanguageByCountry[details.residenceCountryCode] != "en" {
if (details.nativeNameRequired || self.requestOptionalData) && !details.residenceCountryCode.isEmpty && details.primaryLanguageByCountry[details.residenceCountryCode] != "en" {
if let last = result.last, case .spacer = last {
} else {
result.append(.spacer)
@ -561,7 +565,7 @@ struct SecureIdDocumentFormState: FormControllerInnerState {
result.append(.entry(SecureIdDocumentFormEntry.expiryDate(document.expiryDate, expiryDateError)))
}
if self.selfieRequired || self.frontSideRequired || self.backSideRequired {
if (self.selfieRequired || self.requestOptionalData) || self.frontSideRequired || self.backSideRequired {
let type = identity.document?.type
if let last = result.last, case .spacer = last {
@ -624,7 +628,7 @@ struct SecureIdDocumentFormState: FormControllerInnerState {
}
}
if self.selfieRequired {
if self.selfieRequired || self.requestOptionalData {
if let document = self.selfieDocument {
var error: String?
if case let .remote(file) = document {
@ -655,7 +659,7 @@ struct SecureIdDocumentFormState: FormControllerInnerState {
result.append(.entry(SecureIdDocumentFormEntry.scansInfo(.identity)))
}
if let document = identity.document, self.translationsRequired {
if let document = identity.document, self.translationsRequired || self.requestOptionalData {
if let last = result.last, case .spacer = last {
} else {
result.append(.spacer)
@ -846,7 +850,7 @@ struct SecureIdDocumentFormState: FormControllerInnerState {
result.append(.spacer)
}
if self.translationsRequired, let document = address.document {
if let document = address.document, self.translationsRequired || self.requestOptionalData {
if let last = result.last, case .spacer = last {
} else {
result.append(.spacer)
@ -1013,7 +1017,7 @@ struct SecureIdDocumentFormState: FormControllerInnerState {
}
extension SecureIdDocumentFormState {
init(requestedData: SecureIdDocumentFormRequestedData, values: [SecureIdValueKey: SecureIdValueWithContext], primaryLanguageByCountry: [String: String]) {
init(requestedData: SecureIdDocumentFormRequestedData, values: [SecureIdValueKey: SecureIdValueWithContext], requestOptionalData: Bool, primaryLanguageByCountry: [String: String]) {
switch requestedData {
case let .identity(details, document, selfie, translations):
var previousValues: [SecureIdValueKey: SecureIdValueWithContext] = [:]
@ -1090,7 +1094,7 @@ extension SecureIdDocumentFormState {
documentState = SecureIdDocumentFormIdentityDocumentState(type: document, identifier: identifier, expiryDate: expiryDate)
}
let formState = SecureIdDocumentFormIdentityState(details: detailsState, document: documentState)
self.init(previousValues: previousValues, documentState: .identity(formState), documents: verificationDocuments, selfieRequired: selfie, selfieDocument: selfieDocument, frontSideRequired: frontSideRequired, frontSideDocument: frontSideDocument, backSideRequired: backSideRequired, backSideDocument: backSideDocument, translationsRequired: translations, translations: translationDocuments, actionState: .none)
self.init(previousValues: previousValues, documentState: .identity(formState), documents: verificationDocuments, selfieRequired: selfie, selfieDocument: selfieDocument, frontSideRequired: frontSideRequired, frontSideDocument: frontSideDocument, backSideRequired: backSideRequired, backSideDocument: backSideDocument, translationsRequired: translations, translations: translationDocuments, actionState: .none, requestOptionalData: requestOptionalData)
case let .address(details, document, translations):
var previousValues: [SecureIdValueKey: SecureIdValueWithContext] = [:]
var detailsState: SecureIdDocumentFormAddressDetailsState?
@ -1142,7 +1146,7 @@ extension SecureIdDocumentFormState {
documentState = document
}
let formState = SecureIdDocumentFormAddressState(details: detailsState, document: documentState)
self.init(previousValues: previousValues, documentState: .address(formState), documents: verificationDocuments, selfieRequired: false, selfieDocument: nil, frontSideRequired: false, frontSideDocument: nil, backSideRequired: false, backSideDocument: nil, translationsRequired: translations, translations: translationDocuments, actionState: .none)
self.init(previousValues: previousValues, documentState: .address(formState), documents: verificationDocuments, selfieRequired: false, selfieDocument: nil, frontSideRequired: false, frontSideDocument: nil, backSideRequired: false, backSideDocument: nil, translationsRequired: translations, translations: translationDocuments, actionState: .none, requestOptionalData: requestOptionalData)
}
}
@ -2233,12 +2237,16 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode<SecureIdDocum
var maximumDate: Date? = nil
let calendar = Calendar(identifier: .gregorian)
let now = Date()
var title: String? = nil
if case .expiry = field {
title = strings.Passport_Identity_ExpiryDate
emptyTitle = strings.Passport_Identity_DoesNotExpire
var deltaComponents = DateComponents()
deltaComponents.month = 6
minimumDate = calendar.date(byAdding: deltaComponents, to: now)
} else if case .birthdate = field {
title = strings.Passport_Identity_DateOfBirth
var components = calendar.dateComponents([.year, .month, .day], from: now)
if let year = components.year {
components.year = year - 18
@ -2248,7 +2256,7 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode<SecureIdDocum
}
}
let controller = DateSelectionActionSheetController(theme: theme, strings: strings, currentValue: current ?? Int32(Date().timeIntervalSince1970), minimumDate: minimumDate, maximumDate: maximumDate, emptyTitle: emptyTitle, applyValue: { value in
let controller = DateSelectionActionSheetController(theme: theme, strings: strings, title: title, currentValue: current ?? Int32(Date().timeIntervalSince1970), minimumDate: minimumDate, maximumDate: maximumDate, emptyTitle: emptyTitle, applyValue: { value in
if let strongSelf = self, var innerState = strongSelf.innerState {
innerState.documentState.updateDateField(type: field, value: value.flatMap(SecureIdDate.init))
var valueKey: SecureIdValueKey?

View File

@ -25,8 +25,9 @@ public final class TelegramApplicationBindings {
public let clearMessageNotifications: ([MessageId]) -> Void
public let pushIdleTimerExtension: () -> Disposable
public let openSettings: () -> Void
public let openAppStorePage: () -> Void
public init(isMainApp: Bool, 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) {
public init(isMainApp: Bool, 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) {
self.isMainApp = isMainApp
self.openUrl = openUrl
self.openUniversalUrl = openUniversalUrl
@ -38,6 +39,7 @@ public final class TelegramApplicationBindings {
self.clearMessageNotifications = clearMessageNotifications
self.pushIdleTimerExtension = pushIdleTimerExtension
self.openSettings = openSettings
self.openAppStorePage = openAppStorePage
}
}

View File

@ -41,7 +41,7 @@ private final class UserInfoControllerArguments {
self.openChat = openChat
self.addContact = addContact
self.shareContact = shareContact
self.shareMyContact = shareContact
self.shareMyContact = shareMyContact
self.startSecretChat = startSecretChat
self.changeNotificationMuteSettings = changeNotificationMuteSettings
self.changeNotificationSoundSettings = changeNotificationSoundSettings

View File

@ -91,7 +91,7 @@ private final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoConte
super.init()
//self.addSubnode(self.playerNode)
self.addSubnode(self.playerNode)
self.addSubnode(self.imageNode)
self._preloadCompleted.set(true)