Merge commit '5e842163468fc91e3e22ab243415574b62b406de'

This commit is contained in:
Ali 2022-02-24 01:15:20 +04:00
commit 6fb5008c0f
12 changed files with 202 additions and 30 deletions

View File

@ -7326,3 +7326,5 @@ Sorry for the inconvenience.";
"Attachment.DeselectedItems_any" = "%@ items deselected"; "Attachment.DeselectedItems_any" = "%@ items deselected";
"Attachment.DeselectedItems_many" = "%@ items deselected"; "Attachment.DeselectedItems_many" = "%@ items deselected";
"Attachment.DeselectedItems_0" = "%@ items deselected"; "Attachment.DeselectedItems_0" = "%@ items deselected";
"PrivacyPhoneNumberSettings.CustomPublicLink" = "Users who have your number saved in their contacts will also see it on Telegram.\n\nThis public link opens a chat with you:\n[https://t.me/%@]()";

View File

@ -220,6 +220,7 @@ public class AttachmentController: ViewController {
guard self.currentType != type else { guard self.currentType != type else {
if let controller = self.currentController { if let controller = self.currentController {
controller.scrollToTopWithTabBar?() controller.scrollToTopWithTabBar?()
controller.requestAttachmentMenuExpansion()
} }
return return
} }
@ -255,7 +256,7 @@ public class AttachmentController: ViewController {
strongSelf.container.container.view.layer.animatePosition(from: CGPoint(x: ascending ? 70.0 : -70.0, y: 0.0), to: CGPoint(), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true) strongSelf.container.container.view.layer.animatePosition(from: CGPoint(x: ascending ? 70.0 : -70.0, y: 0.0), to: CGPoint(), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
snapshotView?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak snapshotView] _ in snapshotView?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview() snapshotView?.removeFromSuperview()
previousController?.prepareForReuse() previousController?.resetForReuse()
}) })
}) })
} }

View File

@ -204,7 +204,6 @@ func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?,
} }
let legacySheetController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil) let legacySheetController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil)
let controller = TGMediaPickerSendActionSheetController(context: legacyController.context, isDark: true, sendButtonFrame: model.interfaceView.doneButtonFrame, canSendSilently: hasSilentPosting, canSchedule: effectiveHasSchedule, reminder: reminder, hasTimer: hasTimer) let controller = TGMediaPickerSendActionSheetController(context: legacyController.context, isDark: true, sendButtonFrame: model.interfaceView.doneButtonFrame, canSendSilently: hasSilentPosting, canSchedule: effectiveHasSchedule, reminder: reminder, hasTimer: hasTimer)
let dismissImpl = { [weak model] in let dismissImpl = { [weak model] in
model?.dismiss(true, false) model?.dismiss(true, false)
@ -241,8 +240,10 @@ func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?,
legacySheetController?.dismiss() legacySheetController?.dismiss()
} }
legacySheetController.bind(controller: controller) legacySheetController.bind(controller: controller)
present(legacySheetController, nil) present(legacySheetController, nil)
let hapticFeedback = HapticFeedback()
hapticFeedback.impact()
} }
} }
model.interfaceView.setThumbnailSignalForItem { item in model.interfaceView.setThumbnailSignalForItem { item in

View File

@ -66,7 +66,7 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
icon = UIImage(bundleImageName: "Chat/Context Menu/ReportDrugs") icon = UIImage(bundleImageName: "Chat/Context Menu/ReportDrugs")
case .personalDetails: case .personalDetails:
title = presentationData.strings.ReportPeer_ReasonPersonalDetails title = presentationData.strings.ReportPeer_ReasonPersonalDetails
icon = UIImage(bundleImageName: "Chat/Context Menu/User") icon = UIImage(bundleImageName: "Chat/Context Menu/ReportPersonal")
case .other: case .other:
title = presentationData.strings.ReportPeer_ReasonOther title = presentationData.strings.ReportPeer_ReasonOther
icon = UIImage(bundleImageName: "Chat/Context Menu/Report") icon = UIImage(bundleImageName: "Chat/Context Menu/Report")

View File

@ -9,6 +9,7 @@ import TelegramUIPreferences
import ItemListUI import ItemListUI
import PresentationDataUtils import PresentationDataUtils
import AccountContext import AccountContext
import UndoUI
enum SelectivePrivacySettingsKind { enum SelectivePrivacySettingsKind {
case presence case presence
@ -50,8 +51,9 @@ private final class SelectivePrivacySettingsControllerArguments {
let updateCallP2PMode: ((SelectivePrivacySettingType) -> Void)? let updateCallP2PMode: ((SelectivePrivacySettingType) -> Void)?
let updateCallIntegrationEnabled: ((Bool) -> Void)? let updateCallIntegrationEnabled: ((Bool) -> Void)?
let updatePhoneDiscovery: ((Bool) -> Void)? let updatePhoneDiscovery: ((Bool) -> Void)?
let copyPhoneLink: ((String) -> Void)?
init(context: AccountContext, updateType: @escaping (SelectivePrivacySettingType) -> Void, openSelective: @escaping (SelectivePrivacySettingsPeerTarget, Bool) -> Void, updateCallP2PMode: ((SelectivePrivacySettingType) -> Void)?, updateCallIntegrationEnabled: ((Bool) -> Void)?, updatePhoneDiscovery: ((Bool) -> Void)?) { init(context: AccountContext, updateType: @escaping (SelectivePrivacySettingType) -> Void, openSelective: @escaping (SelectivePrivacySettingsPeerTarget, Bool) -> Void, updateCallP2PMode: ((SelectivePrivacySettingType) -> Void)?, updateCallIntegrationEnabled: ((Bool) -> Void)?, updatePhoneDiscovery: ((Bool) -> Void)?, copyPhoneLink: ((String) -> Void)?) {
self.context = context self.context = context
self.updateType = updateType self.updateType = updateType
self.openSelective = openSelective self.openSelective = openSelective
@ -59,6 +61,7 @@ private final class SelectivePrivacySettingsControllerArguments {
self.updateCallP2PMode = updateCallP2PMode self.updateCallP2PMode = updateCallP2PMode
self.updateCallIntegrationEnabled = updateCallIntegrationEnabled self.updateCallIntegrationEnabled = updateCallIntegrationEnabled
self.updatePhoneDiscovery = updatePhoneDiscovery self.updatePhoneDiscovery = updatePhoneDiscovery
self.copyPhoneLink = copyPhoneLink
} }
} }
@ -91,7 +94,7 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
case everybody(PresentationTheme, String, Bool) case everybody(PresentationTheme, String, Bool)
case contacts(PresentationTheme, String, Bool) case contacts(PresentationTheme, String, Bool)
case nobody(PresentationTheme, String, Bool) case nobody(PresentationTheme, String, Bool)
case settingInfo(PresentationTheme, String) case settingInfo(PresentationTheme, String, String)
case exceptionsHeader(PresentationTheme, String) case exceptionsHeader(PresentationTheme, String)
case disableFor(PresentationTheme, String, String) case disableFor(PresentationTheme, String, String)
case enableFor(PresentationTheme, String, String) case enableFor(PresentationTheme, String, String)
@ -109,7 +112,7 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
case phoneDiscoveryHeader(PresentationTheme, String) case phoneDiscoveryHeader(PresentationTheme, String)
case phoneDiscoveryEverybody(PresentationTheme, String, Bool) case phoneDiscoveryEverybody(PresentationTheme, String, Bool)
case phoneDiscoveryMyContacts(PresentationTheme, String, Bool) case phoneDiscoveryMyContacts(PresentationTheme, String, Bool)
case phoneDiscoveryInfo(PresentationTheme, String) case phoneDiscoveryInfo(PresentationTheme, String, String)
var section: ItemListSectionId { var section: ItemListSectionId {
switch self { switch self {
@ -229,8 +232,8 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .settingInfo(lhsTheme, lhsText): case let .settingInfo(lhsTheme, lhsText, lhsLink):
if case let .settingInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .settingInfo(rhsTheme, rhsText, rhsLink) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsLink == rhsLink {
return true return true
} else { } else {
return false return false
@ -331,8 +334,8 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .phoneDiscoveryInfo(lhsTheme, lhsText): case let .phoneDiscoveryInfo(lhsTheme, lhsText, lhsLink):
if case let .phoneDiscoveryInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .phoneDiscoveryInfo(rhsTheme, rhsText, rhsLink) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsLink == rhsLink {
return true return true
} else { } else {
return false return false
@ -365,8 +368,10 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: { return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updateType(.nobody) arguments.updateType(.nobody)
}) })
case let .settingInfo(_, text): case let .settingInfo(_, text, link):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section, linkAction: { _ in
arguments.copyPhoneLink?(link)
})
case let .exceptionsHeader(_, text): case let .exceptionsHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .disableFor(_, title, value): case let .disableFor(_, title, value):
@ -421,8 +426,10 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: { return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updatePhoneDiscovery?(false) arguments.updatePhoneDiscovery?(false)
}) })
case let .phoneDiscoveryInfo(_, text): case let .phoneDiscoveryInfo(_, text, link):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section, linkAction: { _ in
arguments.copyPhoneLink?(link)
})
} }
} }
} }
@ -531,7 +538,7 @@ private struct SelectivePrivacySettingsControllerState: Equatable {
} }
} }
private func selectivePrivacySettingsControllerEntries(presentationData: PresentationData, kind: SelectivePrivacySettingsKind, state: SelectivePrivacySettingsControllerState, peerName: String) -> [SelectivePrivacySettingsEntry] { private func selectivePrivacySettingsControllerEntries(presentationData: PresentationData, kind: SelectivePrivacySettingsKind, state: SelectivePrivacySettingsControllerState, peerName: String, phoneNumber: String) -> [SelectivePrivacySettingsEntry] {
var entries: [SelectivePrivacySettingsEntry] = [] var entries: [SelectivePrivacySettingsEntry] = []
let settingTitle: String let settingTitle: String
@ -569,7 +576,7 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
if state.setting == .nobody { if state.setting == .nobody {
settingInfoText = nil settingInfoText = nil
} else { } else {
settingInfoText = presentationData.strings.PrivacyPhoneNumberSettings_CustomHelp settingInfoText = presentationData.strings.PrivacyPhoneNumberSettings_CustomPublicLink("+\(phoneNumber)").string
} }
disableForText = presentationData.strings.PrivacyLastSeenSettings_NeverShareWith disableForText = presentationData.strings.PrivacyLastSeenSettings_NeverShareWith
enableForText = presentationData.strings.PrivacyLastSeenSettings_AlwaysShareWith enableForText = presentationData.strings.PrivacyLastSeenSettings_AlwaysShareWith
@ -603,15 +610,16 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
case .groupInvitations, .profilePhoto: case .groupInvitations, .profilePhoto:
break break
} }
let phoneLink = "https://t.me/+\(phoneNumber)"
if let settingInfoText = settingInfoText { if let settingInfoText = settingInfoText {
entries.append(.settingInfo(presentationData.theme, settingInfoText)) entries.append(.settingInfo(presentationData.theme, settingInfoText, phoneLink))
} }
if case .phoneNumber = kind, state.setting == .nobody { if case .phoneNumber = kind, state.setting == .nobody {
entries.append(.phoneDiscoveryHeader(presentationData.theme, presentationData.strings.PrivacyPhoneNumberSettings_DiscoveryHeader)) entries.append(.phoneDiscoveryHeader(presentationData.theme, presentationData.strings.PrivacyPhoneNumberSettings_DiscoveryHeader))
entries.append(.phoneDiscoveryEverybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.phoneDiscoveryEnabled != false)) entries.append(.phoneDiscoveryEverybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.phoneDiscoveryEnabled != false))
entries.append(.phoneDiscoveryMyContacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.phoneDiscoveryEnabled == false)) entries.append(.phoneDiscoveryMyContacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.phoneDiscoveryEnabled == false))
entries.append(.phoneDiscoveryInfo(presentationData.theme, state.phoneDiscoveryEnabled != false ? presentationData.strings.PrivacyPhoneNumberSettings_CustomHelp : presentationData.strings.PrivacyPhoneNumberSettings_CustomDisabledHelp)) entries.append(.phoneDiscoveryInfo(presentationData.theme, state.phoneDiscoveryEnabled != false ? presentationData.strings.PrivacyPhoneNumberSettings_CustomPublicLink("+\(phoneNumber)").string : presentationData.strings.PrivacyPhoneNumberSettings_CustomDisabledHelp, phoneLink))
} }
entries.append(.exceptionsHeader(presentationData.theme, presentationData.strings.GroupInfo_Permissions_Exceptions)) entries.append(.exceptionsHeader(presentationData.theme, presentationData.strings.GroupInfo_Permissions_Exceptions))
@ -930,6 +938,11 @@ func selectivePrivacySettingsController(context: AccountContext, kind: Selective
updateState { state in updateState { state in
return state.withUpdatedPhoneDiscoveryEnabled(value) return state.withUpdatedPhoneDiscoveryEnabled(value)
} }
}, copyPhoneLink: { link in
UIPasteboard.general.string = link
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
}) })
let peer = context.account.postbox.transaction { transaction -> Peer? in let peer = context.account.postbox.transaction { transaction -> Peer? in
@ -939,6 +952,7 @@ func selectivePrivacySettingsController(context: AccountContext, kind: Selective
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get(), peer) |> deliverOnMainQueue let signal = combineLatest(context.sharedContext.presentationData, statePromise.get(), peer) |> deliverOnMainQueue
|> map { presentationData, state, peer -> (ItemListControllerState, (ItemListNodeState, Any)) in |> map { presentationData, state, peer -> (ItemListControllerState, (ItemListNodeState, Any)) in
let peerName = peer.flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) let peerName = peer.flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
let phoneNumber = (peer as? TelegramUser)?.phone ?? ""
let title: String let title: String
switch kind { switch kind {
@ -956,7 +970,7 @@ func selectivePrivacySettingsController(context: AccountContext, kind: Selective
title = presentationData.strings.Privacy_PhoneNumber title = presentationData.strings.Privacy_PhoneNumber
} }
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: selectivePrivacySettingsControllerEntries(presentationData: presentationData, kind: kind, state: state, peerName: peerName ?? ""), style: .blocks, animateChanges: false) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: selectivePrivacySettingsControllerEntries(presentationData: presentationData, kind: kind, state: state, peerName: peerName ?? "", phoneNumber: phoneNumber), style: .blocks, animateChanges: false)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} |> afterDisposed { } |> afterDisposed {

View File

@ -0,0 +1,41 @@
import Foundation
import Postbox
public final class CachedResolvedByPhonePeer: Codable {
public let peerId: PeerId?
public let timestamp: Int32
public static func key(name: String) -> ValueBoxKey {
let key: ValueBoxKey
if let nameData = name.data(using: .utf8) {
key = ValueBoxKey(length: nameData.count)
nameData.withUnsafeBytes { rawBytes -> Void in
let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self)
memcpy(key.memory, bytes, nameData.count)
}
} else {
key = ValueBoxKey(length: 0)
}
return key
}
public init(peerId: PeerId?, timestamp: Int32) {
self.peerId = peerId
self.timestamp = timestamp
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: StringCodingKey.self)
self.peerId = (try container.decodeIfPresent(Int64.self, forKey: "p")).flatMap(PeerId.init)
self.timestamp = try container.decode(Int32.self, forKey: "t")
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: StringCodingKey.self)
try container.encodeIfPresent(self.peerId?.toInt64(), forKey: "p")
try container.encode(self.timestamp, forKey: "t")
}
}

View File

@ -82,6 +82,7 @@ public struct Namespaces {
public static let cachedPeerExportedInvitations: Int8 = 17 public static let cachedPeerExportedInvitations: Int8 = 17
public static let cachedSendAsPeers: Int8 = 18 public static let cachedSendAsPeers: Int8 = 18
public static let availableReactions: Int8 = 19 public static let availableReactions: Int8 = 19
public static let resolvedByPhonePeers: Int8 = 20
} }
public struct UnorderedItemList { public struct UnorderedItemList {

View File

@ -77,3 +77,66 @@ func _internal_resolvePeerByName(account: Account, name: String, ageLimit: Int32
} }
} }
} }
private let resolvedByPhonePeersCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 150, highWaterItemCount: 200)
func _internal_resolvePeerByPhone(account: Account, phone: String, ageLimit: Int32 = 2 * 60 * 60 * 24) -> Signal<PeerId?, NoError> {
var normalizedPhone = phone
if normalizedPhone.hasPrefix("+") {
normalizedPhone = String(normalizedPhone[normalizedPhone.index(after: normalizedPhone.startIndex)...])
}
return account.postbox.transaction { transaction -> CachedResolvedByPhonePeer? in
return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByPhonePeers, key: CachedResolvedByPhonePeer.key(name: normalizedPhone)))?.get(CachedResolvedByPhonePeer.self)
} |> mapToSignal { cachedEntry -> Signal<PeerId?, NoError> in
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
if let cachedEntry = cachedEntry, cachedEntry.timestamp <= timestamp && cachedEntry.timestamp >= timestamp - ageLimit {
return .single(cachedEntry.peerId)
} else {
return account.network.request(Api.functions.contacts.resolvePhone(phone: normalizedPhone))
|> mapError { _ -> Void in
return Void()
}
|> mapToSignal { result -> Signal<PeerId?, Void> in
return account.postbox.transaction { transaction -> PeerId? in
var peerId: PeerId? = nil
switch result {
case let .resolvedPeer(apiPeer, chats, users):
var peers: [PeerId: Peer] = [:]
for user in users {
if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
peers[user.id] = user
}
}
for chat in chats {
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
peers[groupOrChannel.id] = groupOrChannel
}
}
if let peer = peers[apiPeer.peerId] {
peerId = peer.id
updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated -> Peer in
return updated
})
}
}
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
if let entry = CodableEntry(CachedResolvedByPhonePeer(peerId: peerId, timestamp: timestamp)) {
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByPhonePeers, key: CachedResolvedByPhonePeer.key(name: normalizedPhone)), entry: entry, collectionSpec: resolvedByNamePeersCollectionSpec)
}
return peerId
}
|> castError(Void.self)
}
|> `catch` { _ -> Signal<PeerId?, NoError> in
return .single(nil)
}
}
}
}

View File

@ -98,6 +98,18 @@ public extension TelegramEngine {
} }
} }
public func resolvePeerByPhone(phone: String, ageLimit: Int32 = 2 * 60 * 60 * 24) -> Signal<EnginePeer?, NoError> {
return _internal_resolvePeerByPhone(account: self.account, phone: phone, ageLimit: ageLimit)
|> mapToSignal { peerId -> Signal<EnginePeer?, NoError> in
guard let peerId = peerId else {
return .single(nil)
}
return self.account.postbox.transaction { transaction -> EnginePeer? in
return transaction.getPeer(peerId).flatMap(EnginePeer.init)
}
}
}
public func updatedRemotePeer(peer: PeerReference) -> Signal<Peer, UpdatedRemotePeerError> { public func updatedRemotePeer(peer: PeerReference) -> Signal<Peer, UpdatedRemotePeerError> {
return _internal_updatedRemotePeer(postbox: self.account.postbox, network: self.account.network, peer: peer) return _internal_updatedRemotePeer(postbox: self.account.postbox, network: self.account.network, peer: peer)
} }

View File

@ -0,0 +1,20 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -605,6 +605,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
if parsedUrl.host == "resolve" { if parsedUrl.host == "resolve" {
if let components = URLComponents(string: "/?" + query) { if let components = URLComponents(string: "/?" + query) {
var phone: String?
var domain: String? var domain: String?
var start: String? var start: String?
var startGroup: String? var startGroup: String?
@ -614,7 +615,9 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
if let queryItems = components.queryItems { if let queryItems = components.queryItems {
for queryItem in queryItems { for queryItem in queryItems {
if let value = queryItem.value { if let value = queryItem.value {
if queryItem.name == "domain" { if queryItem.name == "phone" {
phone = value
} else if queryItem.name == "domain" {
domain = value domain = value
} else if queryItem.name == "start" { } else if queryItem.name == "start" {
start = value start = value
@ -633,7 +636,9 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
} }
} }
if let domain = domain { if let phone = phone {
convertedUrl = "https://t.me/+\(phone)"
} else if let domain = domain {
var result = "https://t.me/\(domain)" var result = "https://t.me/\(domain)"
if let post = post, let postValue = Int(post) { if let post = post, let postValue = Int(post) {
result += "/\(postValue)" result += "/\(postValue)"

View File

@ -41,6 +41,7 @@ public enum ParsedInternalUrl {
case share(url: String?, text: String?, to: String?) case share(url: String?, text: String?, to: String?)
case wallpaper(WallpaperUrlParameter) case wallpaper(WallpaperUrlParameter)
case theme(String) case theme(String)
case phone(String)
} }
private enum ParsedUrl { private enum ParsedUrl {
@ -154,7 +155,12 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
} else if pathComponents[0].hasPrefix(phonebookUsernamePathPrefix), let idValue = Int64(String(pathComponents[0][pathComponents[0].index(pathComponents[0].startIndex, offsetBy: phonebookUsernamePathPrefix.count)...])) { } else if pathComponents[0].hasPrefix(phonebookUsernamePathPrefix), let idValue = Int64(String(pathComponents[0][pathComponents[0].index(pathComponents[0].startIndex, offsetBy: phonebookUsernamePathPrefix.count)...])) {
return .peerId(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(idValue))) return .peerId(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(idValue)))
} else if pathComponents[0].hasPrefix("+") || pathComponents[0].hasPrefix("%20") { } else if pathComponents[0].hasPrefix("+") || pathComponents[0].hasPrefix("%20") {
return .join(String(pathComponents[0].dropFirst())) let component = pathComponents[0].replacingOccurrences(of: "%20", with: "+")
if component.rangeOfCharacter(from: CharacterSet(charactersIn: "0123456789+").inverted) == nil {
return .phone(component.replacingOccurrences(of: "+", with: ""))
} else {
return .join(String(component.dropFirst()))
}
} }
return .peerName(peerName, nil) return .peerName(peerName, nil)
} else if pathComponents.count == 2 || pathComponents.count == 3 { } else if pathComponents.count == 2 || pathComponents.count == 3 {
@ -350,6 +356,16 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) -> Signal<ResolvedUrl?, NoError> { private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) -> Signal<ResolvedUrl?, NoError> {
switch url { switch url {
case let .phone(phone):
return context.engine.peers.resolvePeerByPhone(phone: phone)
|> take(1)
|> map { peer -> ResolvedUrl? in
if let peer = peer?._asPeer() {
return .peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil))
} else {
return .peer(nil, .info)
}
}
case let .peerName(name, parameter): case let .peerName(name, parameter):
return context.engine.peers.resolvePeerByName(name: name) return context.engine.peers.resolvePeerByName(name: name)
|> take(1) |> take(1)
@ -383,11 +399,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
return .single(.joinVoiceChat(peer.id, invite)) return .single(.joinVoiceChat(peer.id, invite))
} }
} else { } else {
if let peer = peer as? TelegramUser, peer.botInfo == nil {
return .single(.peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil))) return .single(.peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil)))
} else {
return .single(.peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil)))
}
} }
} else { } else {
return .single(.peer(nil, .info)) return .single(.peer(nil, .info))