mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 11:20:18 +00:00
Added new call P2P settings
This commit is contained in:
parent
3cb29347d1
commit
ef533b02a6
@ -682,6 +682,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
if let continueActionButtonLayout = continueActionButtonLayout {
|
if let continueActionButtonLayout = continueActionButtonLayout {
|
||||||
let (size, apply) = continueActionButtonLayout(boundingWidth - 13.0 - insets.right)
|
let (size, apply) = continueActionButtonLayout(boundingWidth - 13.0 - insets.right)
|
||||||
actionButtonSizeAndApply = (size, apply)
|
actionButtonSizeAndApply = (size, apply)
|
||||||
|
adjustedBoundingSize.width = max(adjustedBoundingSize.width, insets.left + size.width + insets.right)
|
||||||
adjustedBoundingSize.height += 7.0 + size.height
|
adjustedBoundingSize.height += 7.0 + size.height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ final class InstantPageAnchorItem: InstantPageItem {
|
|||||||
func drawInTile(context: CGContext) {
|
func drawInTile(context: CGContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,7 @@ final class InstantPageArticleItem: InstantPageItem {
|
|||||||
self.webpageId = webpageId
|
self.webpageId = webpageId
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return InstantPageArticleNode(account: account, webPage: self.webPage, strings: strings, theme: theme, title: self.title, description: self.description, cover: self.cover, url: self.url, webpageId: self.webpageId, openUrl: openUrl)
|
return InstantPageArticleNode(account: account, webPage: self.webPage, strings: strings, theme: theme, title: self.title, description: self.description, cover: self.cover, url: self.url, webpageId: self.webpageId, openUrl: openUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ final class InstantPageAudioItem: InstantPageItem {
|
|||||||
self.medias = [media]
|
self.medias = [media]
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return InstantPageAudioNode(account: account, strings: strings, theme: theme, webPage: self.webpage, media: self.media, openMedia: openMedia)
|
return InstantPageAudioNode(account: account, strings: strings, theme: theme, webPage: self.webpage, media: self.media, openMedia: openMedia)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -43,8 +43,9 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
var visibleTiles: [Int: InstantPageTileNode] = [:]
|
var visibleTiles: [Int: InstantPageTileNode] = [:]
|
||||||
var visibleItemsWithNodes: [Int: InstantPageNode] = [:]
|
var visibleItemsWithNodes: [Int: InstantPageNode] = [:]
|
||||||
|
|
||||||
var currentWebEmbedHeights: [Int : Int] = [:]
|
var currentWebEmbedHeights: [Int : CGFloat] = [:]
|
||||||
var currentOpenedDetails: [Int : Bool]? = [:]
|
var currentExpandedDetails: [Int : Bool]?
|
||||||
|
var currentDetailsItems: [InstantPageDetailsItem] = []
|
||||||
|
|
||||||
var previousContentOffset: CGPoint?
|
var previousContentOffset: CGPoint?
|
||||||
var isDeceleratingBecauseOfDragging = false
|
var isDeceleratingBecauseOfDragging = false
|
||||||
@ -196,7 +197,8 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let currentLayout = strongSelf.currentLayout {
|
if let currentLayout = strongSelf.currentLayout {
|
||||||
for item in currentLayout.items {
|
for item in currentLayout.items {
|
||||||
if item.frame.contains(point) {
|
let frame = strongSelf.effectiveFrameForItem(item)
|
||||||
|
if frame.contains(point) {
|
||||||
if item is InstantPagePeerReferenceItem {
|
if item is InstantPagePeerReferenceItem {
|
||||||
return .fail
|
return .fail
|
||||||
} else if item is InstantPageAudioItem {
|
} else if item is InstantPageAudioItem {
|
||||||
@ -319,10 +321,11 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
let currentLayoutTiles = instantPageTilesFromLayout(currentLayout, boundingWidth: containerLayout.size.width)
|
let currentLayoutTiles = instantPageTilesFromLayout(currentLayout, boundingWidth: containerLayout.size.width)
|
||||||
|
|
||||||
|
var currentDetailsItems: [InstantPageDetailsItem] = []
|
||||||
var currentLayoutItemsWithNodes: [InstantPageItem] = []
|
var currentLayoutItemsWithNodes: [InstantPageItem] = []
|
||||||
var distanceThresholdGroupCount: [Int : Int] = [:]
|
var distanceThresholdGroupCount: [Int : Int] = [:]
|
||||||
|
|
||||||
var openedDetails: [Int : Bool] = [:]
|
var expandedDetails: [Int : Bool] = [:]
|
||||||
|
|
||||||
var itemIndex = -1
|
var itemIndex = -1
|
||||||
for item in currentLayout.items {
|
for item in currentLayout.items {
|
||||||
@ -340,26 +343,29 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let detailsItem = item as? InstantPageDetailsItem {
|
if let detailsItem = item as? InstantPageDetailsItem {
|
||||||
openedDetails[itemIndex] = detailsItem.open
|
expandedDetails[itemIndex] = detailsItem.initiallyExpanded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let item = item as? InstantPageDetailsItem {
|
||||||
|
currentDetailsItems.append(item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.currentOpenedDetails == nil {
|
if self.currentExpandedDetails == nil {
|
||||||
self.currentOpenedDetails = openedDetails
|
self.currentExpandedDetails = expandedDetails
|
||||||
}
|
}
|
||||||
|
|
||||||
self.currentLayout = currentLayout
|
self.currentLayout = currentLayout
|
||||||
self.currentLayoutTiles = currentLayoutTiles
|
self.currentLayoutTiles = currentLayoutTiles
|
||||||
self.currentLayoutItemsWithNodes = currentLayoutItemsWithNodes
|
self.currentLayoutItemsWithNodes = currentLayoutItemsWithNodes
|
||||||
|
self.currentDetailsItems = currentDetailsItems
|
||||||
self.distanceThresholdGroupCount = distanceThresholdGroupCount
|
self.distanceThresholdGroupCount = distanceThresholdGroupCount
|
||||||
|
|
||||||
self.scrollNode.view.contentSize = currentLayout.contentSize
|
self.scrollNode.view.contentSize = currentLayout.contentSize
|
||||||
|
|
||||||
self.scrollNodeFooter.frame = CGRect(origin: CGPoint(x: 0.0, y: currentLayout.contentSize.height), size: CGSize(width: containerLayout.size.width, height: 2000.0))
|
self.scrollNodeFooter.frame = CGRect(origin: CGPoint(x: 0.0, y: currentLayout.contentSize.height), size: CGSize(width: containerLayout.size.width, height: 2000.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateVisibleItems() {
|
func updateVisibleItems(animated: Bool = false) {
|
||||||
guard let theme = self.theme else {
|
guard let theme = self.theme else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -370,6 +376,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
let visibleBounds = self.scrollNode.view.bounds
|
let visibleBounds = self.scrollNode.view.bounds
|
||||||
|
|
||||||
var topNode: ASDisplayNode?
|
var topNode: ASDisplayNode?
|
||||||
|
let topTileNode = topNode
|
||||||
if let scrollSubnodes = self.scrollNode.subnodes {
|
if let scrollSubnodes = self.scrollNode.subnodes {
|
||||||
for node in scrollSubnodes.reversed() {
|
for node in scrollSubnodes.reversed() {
|
||||||
if let node = node as? InstantPageTileNode {
|
if let node = node as? InstantPageTileNode {
|
||||||
@ -379,34 +386,27 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tileIndex = -1
|
var collapseOffset: CGFloat = 0.0
|
||||||
for tile in self.currentLayoutTiles {
|
let transition: ContainedViewLayoutTransition
|
||||||
tileIndex += 1
|
if animated {
|
||||||
var tileVisibleFrame = tile.frame
|
transition = .animated(duration: 0.3, curve: .spring)
|
||||||
tileVisibleFrame.origin.y -= 400.0
|
} else {
|
||||||
tileVisibleFrame.size.height += 400.0 * 2.0
|
transition = .immediate
|
||||||
if tileVisibleFrame.intersects(visibleBounds) {
|
|
||||||
visibleTileIndices.insert(tileIndex)
|
|
||||||
|
|
||||||
if visibleTiles[tileIndex] == nil {
|
|
||||||
let tileNode = InstantPageTileNode(tile: tile, backgroundColor: theme.pageBackgroundColor)
|
|
||||||
tileNode.frame = tile.frame
|
|
||||||
if let topNode = topNode {
|
|
||||||
self.scrollNode.insertSubnode(tileNode, aboveSubnode: topNode)
|
|
||||||
} else {
|
|
||||||
self.scrollNode.insertSubnode(tileNode, at: 0)
|
|
||||||
}
|
|
||||||
topNode = tileNode
|
|
||||||
self.visibleTiles[tileIndex] = tileNode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var collapseOffset: CGFloat = 0.0
|
|
||||||
|
|
||||||
var itemIndex = -1
|
var itemIndex = -1
|
||||||
|
var embedIndex = -1
|
||||||
|
var detailsIndex = -1
|
||||||
|
|
||||||
for item in self.currentLayoutItemsWithNodes {
|
for item in self.currentLayoutItemsWithNodes {
|
||||||
itemIndex += 1
|
itemIndex += 1
|
||||||
|
if item is InstantPageWebEmbedItem {
|
||||||
|
embedIndex += 1
|
||||||
|
}
|
||||||
|
if item is InstantPageDetailsItem {
|
||||||
|
detailsIndex += 1
|
||||||
|
}
|
||||||
|
|
||||||
var itemThreshold: CGFloat = 0.0
|
var itemThreshold: CGFloat = 0.0
|
||||||
if let group = item.distanceThresholdGroup() {
|
if let group = item.distanceThresholdGroup() {
|
||||||
var count: Int = 0
|
var count: Int = 0
|
||||||
@ -421,8 +421,8 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
thresholdedItemFrame.origin.y -= itemThreshold
|
thresholdedItemFrame.origin.y -= itemThreshold
|
||||||
thresholdedItemFrame.size.height += itemThreshold * 2.0
|
thresholdedItemFrame.size.height += itemThreshold * 2.0
|
||||||
|
|
||||||
if let opened = self.currentOpenedDetails?[itemIndex], !opened {
|
if let expanded = self.currentExpandedDetails?[detailsIndex], !expanded {
|
||||||
collapseOffset = itemFrame.height - 44.0
|
collapseOffset += itemFrame.height - 44.0
|
||||||
itemFrame = CGRect(origin: itemFrame.origin, size: CGSize(width: itemFrame.width, height: 44.0))
|
itemFrame = CGRect(origin: itemFrame.origin, size: CGSize(width: itemFrame.width, height: 44.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,16 +439,19 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if itemNode == nil {
|
if itemNode == nil {
|
||||||
|
let itemIndex = itemIndex
|
||||||
|
let embedIndex = embedIndex
|
||||||
|
let detailsIndex = detailsIndex
|
||||||
if let itemNode = item.node(account: self.account, strings: self.strings, theme: theme, openMedia: { [weak self] media in
|
if let itemNode = item.node(account: self.account, strings: self.strings, theme: theme, openMedia: { [weak self] media in
|
||||||
self?.openMedia(media)
|
self?.openMedia(media)
|
||||||
}, openPeer: { [weak self] peerId in
|
}, openPeer: { [weak self] peerId in
|
||||||
self?.openPeer(peerId)
|
self?.openPeer(peerId)
|
||||||
}, openUrl: { [weak self] url in
|
}, openUrl: { [weak self] url in
|
||||||
self?.openUrl(url)
|
self?.openUrl(url)
|
||||||
}, updateWebEmbedHeight: { [weak self] key, height in
|
}, updateWebEmbedHeight: { [weak self] height in
|
||||||
self?.updateWebEmbedHeight(key, height)
|
self?.updateWebEmbedHeight(embedIndex, height)
|
||||||
}, updateDetailsOpened: { [weak self] key, opened in
|
}, updateDetailsExpanded: { [weak self] expanded in
|
||||||
self?.updateDetailsOpened(key, opened)
|
self?.updateDetailsExpanded(detailsIndex, expanded)
|
||||||
}) {
|
}) {
|
||||||
itemNode.frame = itemFrame
|
itemNode.frame = itemFrame
|
||||||
if let topNode = topNode {
|
if let topNode = topNode {
|
||||||
@ -461,12 +464,62 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (itemNode as! ASDisplayNode).frame != itemFrame {
|
if (itemNode as! ASDisplayNode).frame != itemFrame {
|
||||||
|
let previousFrame = (itemNode as! ASDisplayNode).frame
|
||||||
(itemNode as! ASDisplayNode).frame = itemFrame
|
(itemNode as! ASDisplayNode).frame = itemFrame
|
||||||
|
transition.animateFrame(node: (itemNode as! ASDisplayNode), from: previousFrame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
topNode = topTileNode
|
||||||
|
|
||||||
|
var tileIndex = -1
|
||||||
|
for tile in self.currentLayoutTiles {
|
||||||
|
tileIndex += 1
|
||||||
|
|
||||||
|
var tileFrame = tile.frame
|
||||||
|
if tileIndex > 0 {
|
||||||
|
tileFrame = tileFrame.offsetBy(dx: 0.0, dy: -collapseOffset)
|
||||||
|
}
|
||||||
|
var tileVisibleFrame = tileFrame
|
||||||
|
tileVisibleFrame.origin.y -= 400.0
|
||||||
|
tileVisibleFrame.size.height += 400.0 * 2.0
|
||||||
|
if tileVisibleFrame.intersects(visibleBounds) || animated {
|
||||||
|
visibleTileIndices.insert(tileIndex)
|
||||||
|
|
||||||
|
if visibleTiles[tileIndex] == nil {
|
||||||
|
let tileNode = InstantPageTileNode(tile: tile, backgroundColor: theme.pageBackgroundColor)
|
||||||
|
tileNode.frame = tile.frame
|
||||||
|
if let topNode = topNode {
|
||||||
|
self.scrollNode.insertSubnode(tileNode, aboveSubnode: topNode)
|
||||||
|
} else {
|
||||||
|
self.scrollNode.insertSubnode(tileNode, at: 0)
|
||||||
|
}
|
||||||
|
topNode = tileNode
|
||||||
|
self.visibleTiles[tileIndex] = tileNode
|
||||||
|
} else {
|
||||||
|
if visibleTiles[tileIndex]!.frame != tileFrame {
|
||||||
|
let previousFrame = visibleTiles[tileIndex]!.frame
|
||||||
|
visibleTiles[tileIndex]!.frame = tileFrame
|
||||||
|
transition.animateFrame(node: visibleTiles[tileIndex]!, from: previousFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let currentLayout = self.currentLayout, collapseOffset > 0.0 {
|
||||||
|
let effectiveContentHeight = currentLayout.contentSize.height - collapseOffset
|
||||||
|
if effectiveContentHeight != self.scrollNode.view.contentSize.height {
|
||||||
|
transition.animateView {
|
||||||
|
self.scrollNode.view.contentSize = CGSize(width: currentLayout.contentSize.width, height: effectiveContentHeight)
|
||||||
|
}
|
||||||
|
let previousFrame = self.scrollNodeFooter.frame
|
||||||
|
self.scrollNodeFooter.frame = CGRect(origin: CGPoint(x: 0.0, y: effectiveContentHeight), size: CGSize(width: previousFrame.width, height: 2000.0))
|
||||||
|
transition.animateFrame(node: self.scrollNodeFooter, from: previousFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var removeTileIndices: [Int] = []
|
var removeTileIndices: [Int] = []
|
||||||
for (index, tileNode) in self.visibleTiles {
|
for (index, tileNode) in self.visibleTiles {
|
||||||
if !visibleTileIndices.contains(index) {
|
if !visibleTileIndices.contains(index) {
|
||||||
@ -644,15 +697,40 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
return contentOffset
|
return contentOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func effectiveFrameForItem(_ item: InstantPageItem) -> CGRect {
|
||||||
|
let layoutOrigin = item.frame.origin
|
||||||
|
var origin = layoutOrigin
|
||||||
|
|
||||||
|
for item in self.currentDetailsItems {
|
||||||
|
let expanded = self.currentExpandedDetails?[item.index] ?? item.initiallyExpanded
|
||||||
|
if !expanded && layoutOrigin.y >= item.frame.maxY {
|
||||||
|
let offset = 44.0 - item.frame.height
|
||||||
|
origin.y += offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let item = item as? InstantPageDetailsItem {
|
||||||
|
let expanded = self.currentExpandedDetails?[item.index] ?? item.initiallyExpanded
|
||||||
|
return CGRect(origin: origin, size: CGSize(width: item.frame.width, height: expanded ? item.frame.height : 44.0))
|
||||||
|
} else {
|
||||||
|
return CGRect(origin: origin, size: item.frame.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func textItemAtLocation(_ location: CGPoint) -> (InstantPageTextItem, CGPoint)? {
|
private func textItemAtLocation(_ location: CGPoint) -> (InstantPageTextItem, CGPoint)? {
|
||||||
if let currentLayout = self.currentLayout {
|
if let currentLayout = self.currentLayout {
|
||||||
for item in currentLayout.items {
|
for item in currentLayout.items {
|
||||||
if let item = item as? InstantPageTextItem, item.selectable, item.frame.contains(location) {
|
let frame = self.effectiveFrameForItem(item)
|
||||||
return (item, CGPoint())
|
if frame.contains(location) {
|
||||||
} else if let item = item as? InstantPageTableItem, item.frame.contains(location) {
|
if let item = item as? InstantPageTextItem, item.selectable {
|
||||||
let contentOffset = tableContentOffset(item: item)
|
return (item, CGPoint())
|
||||||
if let (textItem, parentOffset) = item.textItemAtLocation(location.offsetBy(dx: -item.frame.minX + contentOffset.x, dy: -item.frame.minY)) {
|
} else if let item = item as? InstantPageTableItem {
|
||||||
return (textItem, item.frame.origin.offsetBy(dx: parentOffset.x - contentOffset.x, dy: parentOffset.y))
|
let contentOffset = tableContentOffset(item: item)
|
||||||
|
if let (textItem, parentOffset) = item.textItemAtLocation(location.offsetBy(dx: -item.frame.minX + contentOffset.x, dy: -item.frame.minY)) {
|
||||||
|
return (textItem, item.frame.origin.offsetBy(dx: parentOffset.x - contentOffset.x, dy: parentOffset.y))
|
||||||
|
}
|
||||||
|
} else if let item = item as? InstantPageDetailsItem {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -706,7 +784,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
])])
|
])])
|
||||||
self.present(actionSheet, nil)
|
self.present(actionSheet, nil)
|
||||||
} else if let (item, parentOffset) = self.textItemAtLocation(location) {
|
} else if let (item, parentOffset) = self.textItemAtLocation(location) {
|
||||||
let textNodeFrame = item.frame
|
let textNodeFrame = effectiveFrameForItem(item)
|
||||||
var itemRects = item.lineRects()
|
var itemRects = item.lineRects()
|
||||||
for i in 0 ..< itemRects.count {
|
for i in 0 ..< itemRects.count {
|
||||||
itemRects[i] = itemRects[i].offsetBy(dx: parentOffset.x + textNodeFrame.minX, dy: parentOffset.y + textNodeFrame.minY).insetBy(dx: -2.0, dy: -2.0)
|
itemRects[i] = itemRects[i].offsetBy(dx: parentOffset.x + textNodeFrame.minX, dy: parentOffset.y + textNodeFrame.minY).insetBy(dx: -2.0, dy: -2.0)
|
||||||
@ -812,7 +890,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
case let .withBotStartPayload(botStart):
|
case let .withBotStartPayload(botStart):
|
||||||
if let navigationController = strongSelf.getNavigationController() {
|
if let navigationController = strongSelf.getNavigationController() {
|
||||||
navigateToChatController(navigationController: navigationController, account: strongSelf.account, chatLocation: .peer(peerId), botStart: botStart)
|
navigateToChatController(navigationController: navigationController, account: strongSelf.account, chatLocation: .peer(peerId), botStart: botStart, keepStack: .always)
|
||||||
}
|
}
|
||||||
case .info:
|
case .info:
|
||||||
let _ = (strongSelf.account.postbox.loadedPeerWithId(peerId)
|
let _ = (strongSelf.account.postbox.loadedPeerWithId(peerId)
|
||||||
@ -910,13 +988,13 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateWebEmbedHeight(_ key: Int, _ height: Int) {
|
private func updateWebEmbedHeight(_ index: Int, _ height: CGFloat) {
|
||||||
let currentHeight = self.currentWebEmbedHeights[key]
|
let currentHeight = self.currentWebEmbedHeights[index]
|
||||||
if height != currentHeight {
|
if height != currentHeight {
|
||||||
if let currentHeight = currentHeight, currentHeight > height {
|
if let currentHeight = currentHeight, currentHeight > height {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.currentWebEmbedHeights[key] = height
|
self.currentWebEmbedHeights[index] = height
|
||||||
|
|
||||||
let signal: Signal<Void, NoError> = (.complete() |> delay(0.08, queue: Queue.mainQueue()))
|
let signal: Signal<Void, NoError> = (.complete() |> delay(0.08, queue: Queue.mainQueue()))
|
||||||
self.updateLayoutDisposable.set(signal.start(completed: { [weak self] in
|
self.updateLayoutDisposable.set(signal.start(completed: { [weak self] in
|
||||||
@ -928,13 +1006,12 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateDetailsOpened(_ index: Int, _ opened: Bool) {
|
private func updateDetailsExpanded(_ index: Int, _ expanded: Bool) {
|
||||||
if var currentOpenedDetails = self.currentOpenedDetails {
|
if var currentExpandedDetails = self.currentExpandedDetails {
|
||||||
currentOpenedDetails[index] = opened
|
currentExpandedDetails[index] = expanded
|
||||||
self.currentOpenedDetails = currentOpenedDetails
|
self.currentExpandedDetails = currentExpandedDetails
|
||||||
}
|
}
|
||||||
//self.updateLayout()
|
self.updateVisibleItems(animated: true)
|
||||||
self.updateVisibleItems()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func presentSettings() {
|
private func presentSettings() {
|
||||||
|
|||||||
@ -10,20 +10,23 @@ final class InstantPageDetailsItem: InstantPageItem {
|
|||||||
|
|
||||||
let title: NSAttributedString
|
let title: NSAttributedString
|
||||||
let items: [InstantPageItem]
|
let items: [InstantPageItem]
|
||||||
|
let safeInset: CGFloat
|
||||||
let rtl: Bool
|
let rtl: Bool
|
||||||
|
var initiallyExpanded: Bool
|
||||||
|
let index: Int
|
||||||
|
|
||||||
var open: Bool
|
init(frame: CGRect, title: NSAttributedString, items: [InstantPageItem], safeInset: CGFloat, rtl: Bool, initiallyExpanded: Bool, index: Int) {
|
||||||
|
|
||||||
init(frame: CGRect, title: NSAttributedString, items: [InstantPageItem], rtl: Bool, open: Bool) {
|
|
||||||
self.frame = frame
|
self.frame = frame
|
||||||
self.title = title
|
self.title = title
|
||||||
self.items = items
|
self.items = items
|
||||||
|
self.safeInset = safeInset
|
||||||
self.rtl = rtl
|
self.rtl = rtl
|
||||||
self.open = open
|
self.initiallyExpanded = initiallyExpanded
|
||||||
|
self.index = index
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return InstantPageDetailsNode(account: account, strings: strings, theme: theme, item: self, updateDetailsOpened: updateDetailsOpened)
|
return InstantPageDetailsNode(account: account, strings: strings, theme: theme, item: self, updateDetailsExpanded: updateDetailsExpanded)
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchesAnchor(_ anchor: String) -> Bool {
|
func matchesAnchor(_ anchor: String) -> Bool {
|
||||||
@ -58,6 +61,6 @@ final class InstantPageDetailsItem: InstantPageItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func layoutDetailsItem(theme: InstantPageTheme, title: NSAttributedString, boundingWidth: CGFloat, items: [InstantPageItem], contentSize: CGSize, rtl: Bool, open: Bool) -> InstantPageDetailsItem {
|
func layoutDetailsItem(theme: InstantPageTheme, title: NSAttributedString, boundingWidth: CGFloat, items: [InstantPageItem], contentSize: CGSize, safeInset: CGFloat, rtl: Bool, initiallyExpanded: Bool, index: Int) -> InstantPageDetailsItem {
|
||||||
return InstantPageDetailsItem(frame: CGRect(x: 0.0, y: 0.0, width: boundingWidth, height: contentSize.height + 44.0), title: title, items: items, rtl: rtl, open: open)
|
return InstantPageDetailsItem(frame: CGRect(x: 0.0, y: 0.0, width: boundingWidth, height: contentSize.height + 44.0), title: title, items: items, safeInset: safeInset, rtl: rtl, initiallyExpanded: initiallyExpanded, index: index)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -140,9 +140,9 @@ final class InstantPageDetailsContentNode : ASDisplayNode {
|
|||||||
//self?.openPeer(peerId)
|
//self?.openPeer(peerId)
|
||||||
}, openUrl: { [weak self] url in
|
}, openUrl: { [weak self] url in
|
||||||
//self?.openUrl(url)
|
//self?.openUrl(url)
|
||||||
}, updateWebEmbedHeight: { [weak self] key, height in
|
}, updateWebEmbedHeight: { [weak self] height in
|
||||||
//self?.updateWebEmbedHeight(key, height)
|
//self?.updateWebEmbedHeight(key, height)
|
||||||
}, updateDetailsOpened: { _, _ in
|
}, updateDetailsExpanded: { _ in
|
||||||
}) {
|
}) {
|
||||||
itemNode.frame = item.frame
|
itemNode.frame = item.frame
|
||||||
if let topNode = topNode {
|
if let topNode = topNode {
|
||||||
@ -206,16 +206,16 @@ final class InstantPageDetailsNode: ASDisplayNode, InstantPageNode {
|
|||||||
private let separatorNode: ASDisplayNode
|
private let separatorNode: ASDisplayNode
|
||||||
private let contentNode: InstantPageDetailsContentNode
|
private let contentNode: InstantPageDetailsContentNode
|
||||||
|
|
||||||
let updateOpened: (Int, Bool) -> Void
|
private let updateExpanded: (Bool) -> Void
|
||||||
var opened: Bool
|
var expanded: Bool
|
||||||
|
|
||||||
init(account: Account, strings: PresentationStrings, theme: InstantPageTheme, item: InstantPageDetailsItem, updateDetailsOpened: @escaping (Int, Bool) -> Void) {
|
init(account: Account, strings: PresentationStrings, theme: InstantPageTheme, item: InstantPageDetailsItem, updateDetailsExpanded: @escaping (Bool) -> Void) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.item = item
|
self.item = item
|
||||||
|
|
||||||
self.updateOpened = updateDetailsOpened
|
self.updateExpanded = updateDetailsExpanded
|
||||||
|
|
||||||
let frame = item.frame
|
let frame = item.frame
|
||||||
|
|
||||||
@ -241,12 +241,12 @@ final class InstantPageDetailsNode: ASDisplayNode, InstantPageNode {
|
|||||||
}
|
}
|
||||||
self.titleTile.items.append(contentsOf: titleItems)
|
self.titleTile.items.append(contentsOf: titleItems)
|
||||||
|
|
||||||
self.arrowNode = InstantPageDetailsArrowNode(color: theme.controlColor, open: item.open)
|
self.arrowNode = InstantPageDetailsArrowNode(color: theme.controlColor, open: item.initiallyExpanded)
|
||||||
self.separatorNode = ASDisplayNode()
|
self.separatorNode = ASDisplayNode()
|
||||||
|
|
||||||
self.contentNode = InstantPageDetailsContentNode(account: account, strings: strings, theme: theme, items: item.items, contentSize: CGSize(width: item.frame.width, height: item.frame.height))
|
self.contentNode = InstantPageDetailsContentNode(account: account, strings: strings, theme: theme, items: item.items, contentSize: CGSize(width: item.frame.width, height: item.frame.height))
|
||||||
|
|
||||||
self.opened = item.open
|
self.expanded = item.initiallyExpanded
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -259,9 +259,6 @@ final class InstantPageDetailsNode: ASDisplayNode, InstantPageNode {
|
|||||||
self.addSubnode(self.separatorNode)
|
self.addSubnode(self.separatorNode)
|
||||||
self.addSubnode(self.contentNode)
|
self.addSubnode(self.contentNode)
|
||||||
|
|
||||||
let lineSize = CGSize(width: frame.width - detailsInset, height: UIScreenPixel)
|
|
||||||
self.separatorNode.frame = CGRect(origin: CGPoint(x: item.rtl ? 0.0 : detailsInset, y: detailsHeaderHeight - lineSize.height), size: lineSize)
|
|
||||||
|
|
||||||
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||||
|
|
||||||
self.buttonNode.highligthedChanged = { [weak self] highlighted in
|
self.buttonNode.highligthedChanged = { [weak self] highlighted in
|
||||||
@ -287,26 +284,38 @@ final class InstantPageDetailsNode: ASDisplayNode, InstantPageNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func buttonPressed() {
|
@objc func buttonPressed() {
|
||||||
self.setOpened(!self.opened, animated: true)
|
self.setExpanded(!self.expanded, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setOpened(_ opened: Bool, animated: Bool) {
|
func setExpanded(_ expanded: Bool, animated: Bool) {
|
||||||
self.opened = opened
|
self.expanded = expanded
|
||||||
self.arrowNode.setOpen(opened, animated: animated)
|
self.arrowNode.setOpen(expanded, animated: animated)
|
||||||
self.updateOpened(0, opened)
|
self.updateExpanded(expanded)
|
||||||
|
}
|
||||||
|
|
||||||
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
|
let size = layout.size
|
||||||
|
let inset = detailsInset + self.item.safeInset
|
||||||
|
|
||||||
|
let lineSize = CGSize(width: frame.width - inset, height: UIScreenPixel)
|
||||||
|
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: item.rtl ? 0.0 : inset, y: size.height - lineSize.height), size: lineSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
override func layout() {
|
override func layout() {
|
||||||
super.layout()
|
super.layout()
|
||||||
|
|
||||||
let size = self.bounds.size
|
let size = self.bounds.size
|
||||||
|
let inset = detailsInset + self.item.safeInset
|
||||||
|
|
||||||
self.titleTileNode.frame = self.titleTile.frame
|
self.titleTileNode.frame = self.titleTile.frame
|
||||||
self.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: detailsHeaderHeight + UIScreenPixel))
|
self.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: detailsHeaderHeight + UIScreenPixel))
|
||||||
self.buttonNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: detailsHeaderHeight))
|
self.buttonNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: detailsHeaderHeight))
|
||||||
self.arrowNode.frame = CGRect(x: detailsInset, y: floorToScreenPixels((detailsHeaderHeight - 8.0) / 2.0) + 1.0, width: 13.0, height: 8.0)
|
self.arrowNode.frame = CGRect(x: inset, y: floorToScreenPixels((detailsHeaderHeight - 8.0) / 2.0) + 1.0, width: 13.0, height: 8.0)
|
||||||
self.contentNode.frame = CGRect(x: 0.0, y: detailsHeaderHeight, width: size.width, height: self.item.frame.height - detailsHeaderHeight)
|
self.contentNode.frame = CGRect(x: 0.0, y: detailsHeaderHeight, width: size.width, height: self.item.frame.height - detailsHeaderHeight)
|
||||||
|
|
||||||
|
let lineSize = CGSize(width: frame.width - inset, height: UIScreenPixel)
|
||||||
|
self.separatorNode.frame = CGRect(origin: CGPoint(x: item.rtl ? 0.0 : inset, y: size.height - lineSize.height), size: lineSize)
|
||||||
|
|
||||||
self.contentNode.updateVisibleItems()
|
self.contentNode.updateVisibleItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,9 +446,9 @@ final class InstantPageDetailsArrowNode : ASDisplayNode {
|
|||||||
context.setLineCap(.round)
|
context.setLineCap(.round)
|
||||||
context.setLineWidth(2.0)
|
context.setLineWidth(2.0)
|
||||||
|
|
||||||
context.move(to: CGPoint(x: 1.0, y: 6.0 - 5.0 * parameters.progress))
|
context.move(to: CGPoint(x: 1.0, y: 1.0 + 5.0 * parameters.progress))
|
||||||
context.addLine(to: CGPoint(x: 6.0, y: 1.0 + 5.0 * parameters.progress))
|
context.addLine(to: CGPoint(x: 6.0, y: 6.0 - 5.0 * parameters.progress))
|
||||||
context.addLine(to: CGPoint(x: 11.0, y: 6.0 - 5.0 * parameters.progress))
|
context.addLine(to: CGPoint(x: 11.0, y: 1.0 + 5.0 * parameters.progress))
|
||||||
context.strokePath()
|
context.strokePath()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ final class InstantPageFeedbackItem: InstantPageItem {
|
|||||||
self.webPage = webPage
|
self.webPage = webPage
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return InstantPageFeedbackNode(account: account, strings: strings, theme: theme, webPage: self.webPage, openUrl: openUrl)
|
return InstantPageFeedbackNode(account: account, strings: strings, theme: theme, webPage: self.webPage, openUrl: openUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ final class InstantPageImageItem: InstantPageItem {
|
|||||||
self.fit = fit
|
self.fit = fit
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return InstantPageImageNode(account: account, theme: theme, webPage: self.webPage, media: self.media, attributes: self.attributes, url: self.url, interactive: self.interactive, roundCorners: self.roundCorners, fit: self.fit, openMedia: openMedia, openUrl: openUrl)
|
return InstantPageImageNode(account: account, theme: theme, webPage: self.webPage, media: self.media, attributes: self.attributes, url: self.url, interactive: self.interactive, roundCorners: self.roundCorners, fit: self.fit, openMedia: openMedia, openUrl: openUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,8 @@ import SwiftSignalKit
|
|||||||
|
|
||||||
final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
|
final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
|
||||||
private let account: Account
|
private let account: Account
|
||||||
private let theme: InstantPageTheme
|
private let webPage: TelegramMediaWebpage
|
||||||
|
private var theme: InstantPageTheme
|
||||||
let media: InstantPageMedia
|
let media: InstantPageMedia
|
||||||
let attributes: [InstantPageImageAttribute]
|
let attributes: [InstantPageImageAttribute]
|
||||||
let url: InstantPageUrlItem?
|
let url: InstantPageUrlItem?
|
||||||
@ -24,9 +25,12 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
|
|||||||
|
|
||||||
private var fetchedDisposable = MetaDisposable()
|
private var fetchedDisposable = MetaDisposable()
|
||||||
|
|
||||||
|
private var themeUpdated: Bool = false
|
||||||
|
|
||||||
init(account: Account, theme: InstantPageTheme, webPage: TelegramMediaWebpage, media: InstantPageMedia, attributes: [InstantPageImageAttribute], url: InstantPageUrlItem? = nil, interactive: Bool, roundCorners: Bool, fit: Bool, openMedia: @escaping (InstantPageMedia) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void = { _ in }) {
|
init(account: Account, theme: InstantPageTheme, webPage: TelegramMediaWebpage, media: InstantPageMedia, attributes: [InstantPageImageAttribute], url: InstantPageUrlItem? = nil, interactive: Bool, roundCorners: Bool, fit: Bool, openMedia: @escaping (InstantPageMedia) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void = { _ in }) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
|
self.webPage = webPage
|
||||||
self.media = media
|
self.media = media
|
||||||
self.attributes = attributes
|
self.attributes = attributes
|
||||||
self.url = url
|
self.url = url
|
||||||
@ -88,6 +92,19 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func update(strings: PresentationStrings, theme: InstantPageTheme) {
|
func update(strings: PresentationStrings, theme: InstantPageTheme) {
|
||||||
|
if self.theme.imageEmptyColor != theme.imageEmptyColor {
|
||||||
|
self.theme = theme
|
||||||
|
self.themeUpdated = true
|
||||||
|
self.setNeedsLayout()
|
||||||
|
|
||||||
|
if let file = self.media.media as? TelegramMediaFile {
|
||||||
|
let fileReference = FileMediaReference.webPage(webPage: WebpageReference(webPage), media: file)
|
||||||
|
if file.mimeType.hasPrefix("image/") {
|
||||||
|
_ = freeMediaFileInteractiveFetched(account: self.account, fileReference: fileReference).start()
|
||||||
|
self.imageNode.setSignal(chatMessageImageFile(account: self.account, fileReference: fileReference, thumbnail: false, fetched: true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func layout() {
|
override func layout() {
|
||||||
@ -95,8 +112,9 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
|
|||||||
|
|
||||||
let size = self.bounds.size
|
let size = self.bounds.size
|
||||||
|
|
||||||
if self.currentSize != size {
|
if self.currentSize != size || self.themeUpdated {
|
||||||
self.currentSize = size
|
self.currentSize = size
|
||||||
|
self.themeUpdated = false
|
||||||
|
|
||||||
self.imageNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.imageNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ protocol InstantPageItem {
|
|||||||
|
|
||||||
func matchesAnchor(_ anchor: String) -> Bool
|
func matchesAnchor(_ anchor: String) -> Bool
|
||||||
func drawInTile(context: CGContext)
|
func drawInTile(context: CGContext)
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)?
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)?
|
||||||
func matchesNode(_ node: InstantPageNode) -> Bool
|
func matchesNode(_ node: InstantPageNode) -> Bool
|
||||||
func linkSelectionRects(at point: CGPoint) -> [CGRect]
|
func linkSelectionRects(at point: CGPoint) -> [CGRect]
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ private func setupStyleStack(_ stack: InstantPageTextStyleStack, theme: InstantP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: InstantPageBlock, boundingWidth: CGFloat, horizontalInset: CGFloat, safeInset: CGFloat, isCover: Bool, previousItems: [InstantPageItem], fillToWidthAndHeight: Bool, media: [MediaId: Media], mediaIndexCounter: inout Int, embedIndexCounter: inout Int, theme: InstantPageTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, webEmbedHeights: [Int : Int] = [:]) -> InstantPageLayout {
|
func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: InstantPageBlock, boundingWidth: CGFloat, horizontalInset: CGFloat, safeInset: CGFloat, isCover: Bool, previousItems: [InstantPageItem], fillToWidthAndHeight: Bool, media: [MediaId: Media], mediaIndexCounter: inout Int, embedIndexCounter: inout Int, detailsIndexCounter: inout Int, theme: InstantPageTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, webEmbedHeights: [Int : CGFloat] = [:]) -> InstantPageLayout {
|
||||||
|
|
||||||
let layoutCaption: (InstantPageCaption, CGSize) -> ([InstantPageItem], CGSize) = { caption, contentSize in
|
let layoutCaption: (InstantPageCaption, CGSize) -> ([InstantPageItem], CGSize) = { caption, contentSize in
|
||||||
var items: [InstantPageItem] = []
|
var items: [InstantPageItem] = []
|
||||||
@ -80,7 +80,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
|
|||||||
|
|
||||||
switch block {
|
switch block {
|
||||||
case let .cover(block):
|
case let .cover(block):
|
||||||
return layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: block, boundingWidth: boundingWidth, horizontalInset: horizontalInset, safeInset: safeInset, isCover: true, previousItems:previousItems, fillToWidthAndHeight: fillToWidthAndHeight, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
|
return layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: block, boundingWidth: boundingWidth, horizontalInset: horizontalInset, safeInset: safeInset, isCover: true, previousItems:previousItems, fillToWidthAndHeight: fillToWidthAndHeight, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
|
||||||
case let .title(text):
|
case let .title(text):
|
||||||
let styleStack = InstantPageTextStyleStack()
|
let styleStack = InstantPageTextStyleStack()
|
||||||
setupStyleStack(styleStack, theme: theme, category: .header, link: false)
|
setupStyleStack(styleStack, theme: theme, category: .header, link: false)
|
||||||
@ -265,7 +265,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
|
|||||||
var previousBlock: InstantPageBlock?
|
var previousBlock: InstantPageBlock?
|
||||||
var originY: CGFloat = 0.0
|
var originY: CGFloat = 0.0
|
||||||
for subBlock in blocks {
|
for subBlock in blocks {
|
||||||
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - indexSpacing - maxIndexWidth, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: listItems, fillToWidthAndHeight: false, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
|
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - indexSpacing - maxIndexWidth, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: listItems, fillToWidthAndHeight: false, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
|
||||||
|
|
||||||
let spacing: CGFloat = previousBlock != nil ? spacingBetweenBlocks(upper: previousBlock, lower: subBlock) : 0.0
|
let spacing: CGFloat = previousBlock != nil ? spacingBetweenBlocks(upper: previousBlock, lower: subBlock) : 0.0
|
||||||
let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset + indexSpacing + maxIndexWidth, y: contentSize.height + spacing))
|
let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset + indexSpacing + maxIndexWidth, y: contentSize.height + spacing))
|
||||||
@ -454,7 +454,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
|
|||||||
nextItemOrigin.x = 0.0
|
nextItemOrigin.x = 0.0
|
||||||
nextItemOrigin.y += itemSize + spacing
|
nextItemOrigin.y += itemSize + spacing
|
||||||
}
|
}
|
||||||
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subItem, boundingWidth: itemSize, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToWidthAndHeight: true, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
|
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subItem, boundingWidth: itemSize, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToWidthAndHeight: true, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
|
||||||
items.append(contentsOf: subLayout.flattenedItemsWithOrigin(nextItemOrigin))
|
items.append(contentsOf: subLayout.flattenedItemsWithOrigin(nextItemOrigin))
|
||||||
nextItemOrigin.x += itemSize + spacing
|
nextItemOrigin.x += itemSize + spacing
|
||||||
}
|
}
|
||||||
@ -522,7 +522,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
|
|||||||
|
|
||||||
var previousBlock: InstantPageBlock?
|
var previousBlock: InstantPageBlock?
|
||||||
for subBlock in blocks {
|
for subBlock in blocks {
|
||||||
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - lineInset, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToWidthAndHeight: false, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
|
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0 - lineInset, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: items, fillToWidthAndHeight: false, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
|
||||||
|
|
||||||
let spacing = spacingBetweenBlocks(upper: previousBlock, lower: subBlock)
|
let spacing = spacingBetweenBlocks(upper: previousBlock, lower: subBlock)
|
||||||
let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset + lineInset, y: contentSize.height + spacing))
|
let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset + lineInset, y: contentSize.height + spacing))
|
||||||
@ -576,6 +576,10 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
|
|||||||
if stretchToWidth {
|
if stretchToWidth {
|
||||||
embedBoundingWidth = boundingWidth
|
embedBoundingWidth = boundingWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let embedIndex = embedIndexCounter
|
||||||
|
embedIndexCounter += 1
|
||||||
|
|
||||||
let size: CGSize
|
let size: CGSize
|
||||||
if let dimensions = dimensions {
|
if let dimensions = dimensions {
|
||||||
if dimensions.width.isLessThanOrEqualTo(0.0) {
|
if dimensions.width.isLessThanOrEqualTo(0.0) {
|
||||||
@ -584,14 +588,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
|
|||||||
size = dimensions.aspectFitted(CGSize(width: embedBoundingWidth, height: embedBoundingWidth))
|
size = dimensions.aspectFitted(CGSize(width: embedBoundingWidth, height: embedBoundingWidth))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var hash: Int?
|
if let height = webEmbedHeights[embedIndex] {
|
||||||
if let url = url {
|
|
||||||
hash = url.hashValue
|
|
||||||
} else if let html = html {
|
|
||||||
hash = html.hashValue
|
|
||||||
}
|
|
||||||
|
|
||||||
if let hash = hash, let height = webEmbedHeights[hash] {
|
|
||||||
size = CGSize(width: embedBoundingWidth, height: CGFloat(height))
|
size = CGSize(width: embedBoundingWidth, height: CGFloat(height))
|
||||||
} else {
|
} else {
|
||||||
size = CGSize(width: embedBoundingWidth, height: 44.0)
|
size = CGSize(width: embedBoundingWidth, height: 44.0)
|
||||||
@ -619,7 +616,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
let item = InstantPagePeerReferenceItem(frame: CGRect(origin: CGPoint(), size: CGSize(width: boundingWidth, height: 40.0)), initialPeer: peer, rtl: rtl || previousItemHasRTL)
|
let item = InstantPagePeerReferenceItem(frame: CGRect(origin: CGPoint(), size: CGSize(width: boundingWidth, height: 40.0)), initialPeer: peer, safeInset: safeInset, rtl: rtl || previousItemHasRTL)
|
||||||
items.append(item)
|
items.append(item)
|
||||||
contentSize.height += 40.0
|
contentSize.height += 40.0
|
||||||
}
|
}
|
||||||
@ -670,13 +667,16 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
|
|||||||
items.append(tableItem)
|
items.append(tableItem)
|
||||||
|
|
||||||
return InstantPageLayout(origin: CGPoint(), contentSize: contentSize, items: items)
|
return InstantPageLayout(origin: CGPoint(), contentSize: contentSize, items: items)
|
||||||
case let .details(title, blocks, open):
|
case let .details(title, blocks, expanded):
|
||||||
var contentSize = CGSize(width: boundingWidth, height: 0.0)
|
var contentSize = CGSize(width: boundingWidth, height: 0.0)
|
||||||
var subitems: [InstantPageItem] = []
|
var subitems: [InstantPageItem] = []
|
||||||
|
|
||||||
|
let detailsIndex = detailsIndexCounter
|
||||||
|
detailsIndexCounter += 1
|
||||||
|
|
||||||
var previousBlock: InstantPageBlock?
|
var previousBlock: InstantPageBlock?
|
||||||
for subBlock in blocks {
|
for subBlock in blocks {
|
||||||
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: subitems, fillToWidthAndHeight: false, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
|
let subLayout = layoutInstantPageBlock(webpage: webpage, rtl: rtl, block: subBlock, boundingWidth: boundingWidth - horizontalInset * 2.0, horizontalInset: 0.0, safeInset: 0.0, isCover: false, previousItems: subitems, fillToWidthAndHeight: false, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
|
||||||
|
|
||||||
let spacing = spacingBetweenBlocks(upper: previousBlock, lower: subBlock)
|
let spacing = spacingBetweenBlocks(upper: previousBlock, lower: subBlock)
|
||||||
let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset, y: contentSize.height + spacing))
|
let blockItems = subLayout.flattenedItemsWithOrigin(CGPoint(x: horizontalInset, y: contentSize.height + spacing))
|
||||||
@ -690,7 +690,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
|
|||||||
|
|
||||||
let styleStack = InstantPageTextStyleStack()
|
let styleStack = InstantPageTextStyleStack()
|
||||||
setupStyleStack(styleStack, theme: theme, category: .paragraph, link: false)
|
setupStyleStack(styleStack, theme: theme, category: .paragraph, link: false)
|
||||||
let detailsItem = layoutDetailsItem(theme: theme, title: attributedStringForRichText(title, styleStack: styleStack), boundingWidth: boundingWidth, items: subitems, contentSize: contentSize, rtl: rtl, open: open)
|
let detailsItem = layoutDetailsItem(theme: theme, title: attributedStringForRichText(title, styleStack: styleStack), boundingWidth: boundingWidth, items: subitems, contentSize: contentSize, safeInset: safeInset, rtl: rtl, initiallyExpanded: expanded, index: detailsIndex)
|
||||||
|
|
||||||
return InstantPageLayout(origin: CGPoint(), contentSize: detailsItem.frame.size, items: [detailsItem])
|
return InstantPageLayout(origin: CGPoint(), contentSize: detailsItem.frame.size, items: [detailsItem])
|
||||||
case let .relatedArticles(title, articles):
|
case let .relatedArticles(title, articles):
|
||||||
@ -756,7 +756,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, rtl: Bool, block: Ins
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func instantPageLayoutForWebPage(_ webPage: TelegramMediaWebpage, boundingWidth: CGFloat, safeInset: CGFloat, strings: PresentationStrings, theme: InstantPageTheme, dateTimeFormat: PresentationDateTimeFormat, webEmbedHeights: [Int : Int] = [:]) -> InstantPageLayout {
|
func instantPageLayoutForWebPage(_ webPage: TelegramMediaWebpage, boundingWidth: CGFloat, safeInset: CGFloat, strings: PresentationStrings, theme: InstantPageTheme, dateTimeFormat: PresentationDateTimeFormat, webEmbedHeights: [Int : CGFloat] = [:]) -> InstantPageLayout {
|
||||||
var maybeLoadedContent: TelegramMediaWebpageLoadedContent?
|
var maybeLoadedContent: TelegramMediaWebpageLoadedContent?
|
||||||
if case let .Loaded(content) = webPage.content {
|
if case let .Loaded(content) = webPage.content {
|
||||||
maybeLoadedContent = content
|
maybeLoadedContent = content
|
||||||
@ -778,10 +778,11 @@ func instantPageLayoutForWebPage(_ webPage: TelegramMediaWebpage, boundingWidth:
|
|||||||
|
|
||||||
var mediaIndexCounter: Int = 0
|
var mediaIndexCounter: Int = 0
|
||||||
var embedIndexCounter: Int = 0
|
var embedIndexCounter: Int = 0
|
||||||
|
var detailsIndexCounter: Int = 0
|
||||||
|
|
||||||
var previousBlock: InstantPageBlock?
|
var previousBlock: InstantPageBlock?
|
||||||
for block in pageBlocks {
|
for block in pageBlocks {
|
||||||
let blockLayout = layoutInstantPageBlock(webpage: webPage, rtl: rtl, block: block, boundingWidth: boundingWidth, horizontalInset: 17.0 + safeInset, safeInset: safeInset, isCover: false, previousItems: items, fillToWidthAndHeight: false, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
|
let blockLayout = layoutInstantPageBlock(webpage: webPage, rtl: rtl, block: block, boundingWidth: boundingWidth, horizontalInset: 17.0 + safeInset, safeInset: safeInset, isCover: false, previousItems: items, fillToWidthAndHeight: false, media: media, mediaIndexCounter: &mediaIndexCounter, embedIndexCounter: &embedIndexCounter, detailsIndexCounter: &detailsIndexCounter, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, webEmbedHeights: webEmbedHeights)
|
||||||
let spacing = spacingBetweenBlocks(upper: previousBlock, lower: block)
|
let spacing = spacingBetweenBlocks(upper: previousBlock, lower: block)
|
||||||
let blockItems = blockLayout.flattenedItemsWithOrigin(CGPoint(x: 0.0, y: contentSize.height + spacing))
|
let blockItems = blockLayout.flattenedItemsWithOrigin(CGPoint(x: 0.0, y: contentSize.height + spacing))
|
||||||
items.append(contentsOf: blockItems)
|
items.append(contentsOf: blockItems)
|
||||||
|
|||||||
@ -9,16 +9,18 @@ final class InstantPagePeerReferenceItem: InstantPageItem {
|
|||||||
let medias: [InstantPageMedia] = []
|
let medias: [InstantPageMedia] = []
|
||||||
|
|
||||||
let initialPeer: Peer
|
let initialPeer: Peer
|
||||||
|
let safeInset: CGFloat
|
||||||
let rtl: Bool
|
let rtl: Bool
|
||||||
|
|
||||||
init(frame: CGRect, initialPeer: Peer, rtl: Bool) {
|
init(frame: CGRect, initialPeer: Peer, safeInset: CGFloat, rtl: Bool) {
|
||||||
self.frame = frame
|
self.frame = frame
|
||||||
self.initialPeer = initialPeer
|
self.initialPeer = initialPeer
|
||||||
|
self.safeInset = safeInset
|
||||||
self.rtl = rtl
|
self.rtl = rtl
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return InstantPagePeerReferenceNode(account: account, strings: strings, theme: theme, initialPeer: self.initialPeer, rtl: self.rtl, openPeer: openPeer)
|
return InstantPagePeerReferenceNode(account: account, strings: strings, theme: theme, initialPeer: self.initialPeer, safeInset: self.safeInset, rtl: self.rtl, openPeer: openPeer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchesAnchor(_ anchor: String) -> Bool {
|
func matchesAnchor(_ anchor: String) -> Bool {
|
||||||
@ -27,7 +29,7 @@ final class InstantPagePeerReferenceItem: InstantPageItem {
|
|||||||
|
|
||||||
func matchesNode(_ node: InstantPageNode) -> Bool {
|
func matchesNode(_ node: InstantPageNode) -> Bool {
|
||||||
if let node = node as? InstantPagePeerReferenceNode {
|
if let node = node as? InstantPagePeerReferenceNode {
|
||||||
return self.initialPeer.id == node.initialPeer.id
|
return self.initialPeer.id == node.initialPeer.id && self.safeInset == node.safeInset
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,6 +44,7 @@ private enum JoinState: Equatable {
|
|||||||
final class InstantPagePeerReferenceNode: ASDisplayNode, InstantPageNode {
|
final class InstantPagePeerReferenceNode: ASDisplayNode, InstantPageNode {
|
||||||
private let account: Account
|
private let account: Account
|
||||||
let initialPeer: Peer
|
let initialPeer: Peer
|
||||||
|
let safeInset: CGFloat
|
||||||
private let rtl: Bool
|
private let rtl: Bool
|
||||||
private var strings: PresentationStrings
|
private var strings: PresentationStrings
|
||||||
private var theme: InstantPageTheme
|
private var theme: InstantPageTheme
|
||||||
@ -63,11 +64,12 @@ final class InstantPagePeerReferenceNode: ASDisplayNode, InstantPageNode {
|
|||||||
|
|
||||||
private var joinState: JoinState = .none
|
private var joinState: JoinState = .none
|
||||||
|
|
||||||
init(account: Account, strings: PresentationStrings, theme: InstantPageTheme, initialPeer: Peer, rtl: Bool, openPeer: @escaping (PeerId) -> Void) {
|
init(account: Account, strings: PresentationStrings, theme: InstantPageTheme, initialPeer: Peer, safeInset: CGFloat, rtl: Bool, openPeer: @escaping (PeerId) -> Void) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.initialPeer = initialPeer
|
self.initialPeer = initialPeer
|
||||||
|
self.safeInset = safeInset
|
||||||
self.rtl = rtl
|
self.rtl = rtl
|
||||||
self.openPeer = openPeer
|
self.openPeer = openPeer
|
||||||
|
|
||||||
@ -219,7 +221,7 @@ final class InstantPagePeerReferenceNode: ASDisplayNode, InstantPageNode {
|
|||||||
super.layout()
|
super.layout()
|
||||||
|
|
||||||
let size = self.bounds.size
|
let size = self.bounds.size
|
||||||
let inset: CGFloat = 17.0
|
let inset: CGFloat = 17.0 + safeInset
|
||||||
|
|
||||||
self.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
self.buttonNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.buttonNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
@ -230,15 +232,15 @@ final class InstantPagePeerReferenceNode: ASDisplayNode, InstantPageNode {
|
|||||||
let indicatorSize = self.activityIndicator.measure(size)
|
let indicatorSize = self.activityIndicator.measure(size)
|
||||||
|
|
||||||
if self.rtl {
|
if self.rtl {
|
||||||
self.nameNode.frame = CGRect(origin: CGPoint(x: size.width - 17.0 - nameSize.width, y: floor((size.height - nameSize.height) / 2.0)), size: nameSize)
|
self.nameNode.frame = CGRect(origin: CGPoint(x: size.width - inset - nameSize.width, y: floor((size.height - nameSize.height) / 2.0)), size: nameSize)
|
||||||
self.joinNode.frame = CGRect(origin: CGPoint(x: 17.0, y: floor((size.height - joinSize.height) / 2.0)), size: joinSize)
|
self.joinNode.frame = CGRect(origin: CGPoint(x: inset, y: floor((size.height - joinSize.height) / 2.0)), size: joinSize)
|
||||||
self.checkNode.frame = CGRect(origin: CGPoint(x: 17.0, y: floor((size.height - checkSize.height) / 2.0)), size: checkSize)
|
self.checkNode.frame = CGRect(origin: CGPoint(x: inset, y: floor((size.height - checkSize.height) / 2.0)), size: checkSize)
|
||||||
self.activityIndicator.frame = CGRect(origin: CGPoint(x: 17.0, y: floor((size.height - indicatorSize.height) / 2.0)), size: indicatorSize)
|
self.activityIndicator.frame = CGRect(origin: CGPoint(x: inset, y: floor((size.height - indicatorSize.height) / 2.0)), size: indicatorSize)
|
||||||
} else {
|
} else {
|
||||||
self.nameNode.frame = CGRect(origin: CGPoint(x: 17.0, y: floor((size.height - nameSize.height) / 2.0)), size: nameSize)
|
self.nameNode.frame = CGRect(origin: CGPoint(x: inset, y: floor((size.height - nameSize.height) / 2.0)), size: nameSize)
|
||||||
self.joinNode.frame = CGRect(origin: CGPoint(x: size.width - 17.0 - joinSize.width, y: floor((size.height - joinSize.height) / 2.0)), size: joinSize)
|
self.joinNode.frame = CGRect(origin: CGPoint(x: size.width - inset - joinSize.width, y: floor((size.height - joinSize.height) / 2.0)), size: joinSize)
|
||||||
self.checkNode.frame = CGRect(origin: CGPoint(x: size.width - 17.0 - checkSize.width, y: floor((size.height - checkSize.height) / 2.0)), size: checkSize)
|
self.checkNode.frame = CGRect(origin: CGPoint(x: size.width - inset - checkSize.width, y: floor((size.height - checkSize.height) / 2.0)), size: checkSize)
|
||||||
self.activityIndicator.frame = CGRect(origin: CGPoint(x: size.width - 17.0 - indicatorSize.width, y: floor((size.height - indicatorSize.height) / 2.0)), size: indicatorSize)
|
self.activityIndicator.frame = CGRect(origin: CGPoint(x: size.width - inset - indicatorSize.width, y: floor((size.height - indicatorSize.height) / 2.0)), size: indicatorSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ final class InstantPagePlayableVideoItem: InstantPageItem {
|
|||||||
self.interactive = interactive
|
self.interactive = interactive
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return InstantPagePlayableVideoNode(account: account, webPage: self.webPage, media: self.media, interactive: self.interactive, openMedia: openMedia)
|
return InstantPagePlayableVideoNode(account: account, webPage: self.webPage, media: self.media, interactive: self.interactive, openMedia: openMedia)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -56,7 +56,7 @@ final class InstantPageShapeItem: InstantPageItem {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ final class InstantPageSlideshowItem: InstantPageItem {
|
|||||||
self.medias = medias
|
self.medias = medias
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return InstantPageSlideshowNode(account: account, theme: theme, webPage: webPage, medias: self.medias, openMedia: openMedia)
|
return InstantPageSlideshowNode(account: account, theme: theme, webPage: webPage, medias: self.medias, openMedia: openMedia)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -166,7 +166,7 @@ final class InstantPageTableItem: InstantPageItem {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return InstantPageTableNode(item: self, account: account, strings: strings, theme: theme)
|
return InstantPageTableNode(item: self, account: account, strings: strings, theme: theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +227,7 @@ final class InstantPageTableContentNode: ASDisplayNode {
|
|||||||
for cell in self.item.cells {
|
for cell in self.item.cells {
|
||||||
for item in cell.additionalItems {
|
for item in cell.additionalItems {
|
||||||
if item.wantsNode {
|
if item.wantsNode {
|
||||||
if let node = item.node(account: account, strings: strings, theme: theme, openMedia: { _ in }, openPeer: { _ in }, openUrl: { _ in}, updateWebEmbedHeight: { _, _ in }, updateDetailsOpened: { _, _ in }) {
|
if let node = item.node(account: account, strings: strings, theme: theme, openMedia: { _ in }, openPeer: { _ in }, openUrl: { _ in}, updateWebEmbedHeight: { _ in }, updateDetailsExpanded: { _ in }) {
|
||||||
node.frame = item.frame.offsetBy(dx: cell.frame.minX, dy: cell.frame.minY)
|
node.frame = item.frame.offsetBy(dx: cell.frame.minX, dy: cell.frame.minY)
|
||||||
self.addSubnode(node)
|
self.addSubnode(node)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -309,7 +309,7 @@ final class InstantPageTextItem: InstantPageItem {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ final class InstantPageWebEmbedItem: InstantPageItem {
|
|||||||
self.enableScrolling = enableScrolling
|
self.enableScrolling = enableScrolling
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (Int, Int) -> Void, updateDetailsOpened: @escaping (Int, Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
func node(account: Account, strings: PresentationStrings, theme: InstantPageTheme, openMedia: @escaping (InstantPageMedia) -> Void, openPeer: @escaping (PeerId) -> Void, openUrl: @escaping (InstantPageUrlItem) -> Void, updateWebEmbedHeight: @escaping (CGFloat) -> Void, updateDetailsExpanded: @escaping (Bool) -> Void) -> (InstantPageNode & ASDisplayNode)? {
|
||||||
return InstantPageWebEmbedNode(frame: self.frame, url: self.url, html: self.html, enableScrolling: self.enableScrolling, updateWebEmbedHeight: updateWebEmbedHeight)
|
return InstantPageWebEmbedNode(frame: self.frame, url: self.url, html: self.html, enableScrolling: self.enableScrolling, updateWebEmbedHeight: updateWebEmbedHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,11 +20,11 @@ private class WeakInstantPageWebEmbedNodeMessageHandler: NSObject, WKScriptMessa
|
|||||||
final class InstantPageWebEmbedNode: ASDisplayNode, InstantPageNode {
|
final class InstantPageWebEmbedNode: ASDisplayNode, InstantPageNode {
|
||||||
let url: String?
|
let url: String?
|
||||||
let html: String?
|
let html: String?
|
||||||
let updateWebEmbedHeight: (Int, Int) -> Void
|
let updateWebEmbedHeight: (CGFloat) -> Void
|
||||||
|
|
||||||
private var webView: WKWebView?
|
private var webView: WKWebView?
|
||||||
|
|
||||||
init(frame: CGRect, url: String?, html: String?, enableScrolling: Bool, updateWebEmbedHeight: @escaping (Int, Int) -> Void) {
|
init(frame: CGRect, url: String?, html: String?, enableScrolling: Bool, updateWebEmbedHeight: @escaping (CGFloat) -> Void) {
|
||||||
self.url = url
|
self.url = url
|
||||||
self.html = html
|
self.html = html
|
||||||
self.updateWebEmbedHeight = updateWebEmbedHeight
|
self.updateWebEmbedHeight = updateWebEmbedHeight
|
||||||
@ -91,15 +91,7 @@ final class InstantPageWebEmbedNode: ASDisplayNode, InstantPageNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if eventName == "resize_frame", let height = dict["height"] as? Int {
|
if eventName == "resize_frame", let height = dict["height"] as? Int {
|
||||||
var hash: Int?
|
self.updateWebEmbedHeight(CGFloat(height))
|
||||||
if let url = self.url {
|
|
||||||
hash = url.hashValue
|
|
||||||
} else if let html = self.html {
|
|
||||||
hash = html.hashValue
|
|
||||||
}
|
|
||||||
if let hash = hash {
|
|
||||||
self.updateWebEmbedHeight(hash, height)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -125,7 +125,7 @@ final class OngoingCallContext {
|
|||||||
private let audioSessionDisposable = MetaDisposable()
|
private let audioSessionDisposable = MetaDisposable()
|
||||||
private var networkTypeDisposable: Disposable?
|
private var networkTypeDisposable: Disposable?
|
||||||
|
|
||||||
init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, allowP2P: Bool, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>) {
|
init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>) {
|
||||||
let _ = setupLogs
|
let _ = setupLogs
|
||||||
|
|
||||||
self.internalId = internalId
|
self.internalId = internalId
|
||||||
@ -142,7 +142,7 @@ final class OngoingCallContext {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), allowP2P: allowP2P, proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType))
|
let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType))
|
||||||
self.contextRef = Unmanaged.passRetained(context)
|
self.contextRef = Unmanaged.passRetained(context)
|
||||||
context.stateChanged = { [weak self] state in
|
context.stateChanged = { [weak self] state in
|
||||||
self?.contextState.set(.single(state))
|
self?.contextState.set(.single(state))
|
||||||
@ -186,13 +186,13 @@ final class OngoingCallContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func start(key: Data, isOutgoing: Bool, connections: CallSessionConnectionSet, maxLayer: Int32, audioSessionActive: Signal<Bool, NoError>) {
|
func start(key: Data, isOutgoing: Bool, connections: CallSessionConnectionSet, maxLayer: Int32, allowP2P: Bool, audioSessionActive: Signal<Bool, NoError>) {
|
||||||
self.audioSessionDisposable.set((audioSessionActive
|
self.audioSessionDisposable.set((audioSessionActive
|
||||||
|> filter { $0 }
|
|> filter { $0 }
|
||||||
|> take(1)).start(next: { [weak self] _ in
|
|> take(1)).start(next: { [weak self] _ in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.withContext { context in
|
strongSelf.withContext { context in
|
||||||
context.start(withKey: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescription(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescription), maxLayer: maxLayer)
|
context.start(withKey: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescription(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescription), maxLayer: maxLayer, allowP2P: allowP2P)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|||||||
@ -54,8 +54,8 @@ typedef NS_ENUM(int32_t, OngoingCallNetworkType) {
|
|||||||
@property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallState);
|
@property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallState);
|
||||||
@property (nonatomic, copy) void (^ _Nullable callEnded)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile);
|
@property (nonatomic, copy) void (^ _Nullable callEnded)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile);
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue allowP2P:(BOOL)allowP2P proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType;
|
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType;
|
||||||
- (void)startWithKey:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer;
|
- (void)startWithKey:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P;
|
||||||
- (void)stop;
|
- (void)stop;
|
||||||
|
|
||||||
- (NSString * _Nullable)debugInfo;
|
- (NSString * _Nullable)debugInfo;
|
||||||
|
|||||||
@ -127,7 +127,6 @@ static void withContext(int32_t contextId, void (^f)(OngoingCallThreadLocalConte
|
|||||||
NSTimeInterval _callConnectTimeout;
|
NSTimeInterval _callConnectTimeout;
|
||||||
NSTimeInterval _callPacketTimeout;
|
NSTimeInterval _callPacketTimeout;
|
||||||
int32_t _dataSavingMode;
|
int32_t _dataSavingMode;
|
||||||
bool _allowP2P;
|
|
||||||
|
|
||||||
tgvoip::VoIPController *_controller;
|
tgvoip::VoIPController *_controller;
|
||||||
|
|
||||||
@ -181,7 +180,7 @@ static int callControllerNetworkTypeForType(OngoingCallNetworkType type) {
|
|||||||
TGVoipLoggingFunction = loggingFunction;
|
TGVoipLoggingFunction = loggingFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue allowP2P:(BOOL)allowP2P proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType {
|
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
_queue = queue;
|
_queue = queue;
|
||||||
@ -193,7 +192,6 @@ static int callControllerNetworkTypeForType(OngoingCallNetworkType type) {
|
|||||||
_callConnectTimeout = 30.0;
|
_callConnectTimeout = 30.0;
|
||||||
_callPacketTimeout = 10.0;
|
_callPacketTimeout = 10.0;
|
||||||
_dataSavingMode = 0;
|
_dataSavingMode = 0;
|
||||||
_allowP2P = allowP2P;
|
|
||||||
_networkType = networkType;
|
_networkType = networkType;
|
||||||
|
|
||||||
_controller = new tgvoip::VoIPController();
|
_controller = new tgvoip::VoIPController();
|
||||||
@ -232,7 +230,7 @@ static int callControllerNetworkTypeForType(OngoingCallNetworkType type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)startWithKey:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer {
|
- (void)startWithKey:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P {
|
||||||
std::vector<tgvoip::Endpoint> endpoints;
|
std::vector<tgvoip::Endpoint> endpoints;
|
||||||
NSArray<OngoingCallConnectionDescription *> *connections = [@[primaryConnection] arrayByAddingObjectsFromArray:alternativeConnections];
|
NSArray<OngoingCallConnectionDescription *> *connections = [@[primaryConnection] arrayByAddingObjectsFromArray:alternativeConnections];
|
||||||
for (OngoingCallConnectionDescription *connection in connections) {
|
for (OngoingCallConnectionDescription *connection in connections) {
|
||||||
@ -261,7 +259,7 @@ static int callControllerNetworkTypeForType(OngoingCallNetworkType type) {
|
|||||||
_controller->SetConfig(config);
|
_controller->SetConfig(config);
|
||||||
|
|
||||||
_controller->SetEncryptionKey((char *)key.bytes, isOutgoing);
|
_controller->SetEncryptionKey((char *)key.bytes, isOutgoing);
|
||||||
_controller->SetRemoteEndpoints(endpoints, _allowP2P, maxLayer);
|
_controller->SetRemoteEndpoints(endpoints, allowP2P, maxLayer);
|
||||||
_controller->Start();
|
_controller->Start();
|
||||||
|
|
||||||
_controller->Connect();
|
_controller->Connect();
|
||||||
|
|||||||
@ -188,6 +188,7 @@ public class PeerMediaCollectionController: TelegramController {
|
|||||||
}, presentGlobalOverlayController: { _, _ in }, callPeer: { _ in
|
}, presentGlobalOverlayController: { _, _ in }, callPeer: { _ in
|
||||||
}, longTap: { [weak self] content in
|
}, longTap: { [weak self] content in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
strongSelf.view.endEditing(true)
|
||||||
switch content {
|
switch content {
|
||||||
case let .url(url):
|
case let .url(url):
|
||||||
let canOpenIn = availableOpenInOptions(applicationContext: strongSelf.account.telegramApplicationContext, item: .url(url: url)).count > 1
|
let canOpenIn = availableOpenInOptions(applicationContext: strongSelf.account.telegramApplicationContext, item: .url(url: url)).count > 1
|
||||||
|
|||||||
@ -230,7 +230,7 @@ public final class PresentationCall {
|
|||||||
self.isOutgoing = isOutgoing
|
self.isOutgoing = isOutgoing
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
|
|
||||||
self.ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, allowP2P: allowP2P, proxyServer: proxyServer, initialNetworkType: currentNetworkType, updatedNetworkType: updatedNetworkType)
|
self.ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: currentNetworkType, updatedNetworkType: updatedNetworkType)
|
||||||
|
|
||||||
var didReceiveAudioOutputs = false
|
var didReceiveAudioOutputs = false
|
||||||
self.sessionStateDisposable = (callSessionManager.callState(internalId: internalId)
|
self.sessionStateDisposable = (callSessionManager.callState(internalId: internalId)
|
||||||
@ -413,7 +413,7 @@ public final class PresentationCall {
|
|||||||
presentationState = .terminated(reason)
|
presentationState = .terminated(reason)
|
||||||
case let .requesting(ringing):
|
case let .requesting(ringing):
|
||||||
presentationState = .requesting(ringing)
|
presentationState = .requesting(ringing)
|
||||||
case let .active(_, keyVisualHash, _, _):
|
case let .active(_, keyVisualHash, _, _, _):
|
||||||
if let callContextState = callContextState {
|
if let callContextState = callContextState {
|
||||||
switch callContextState {
|
switch callContextState {
|
||||||
case .initializing:
|
case .initializing:
|
||||||
@ -441,10 +441,10 @@ public final class PresentationCall {
|
|||||||
if let _ = audioSessionControl {
|
if let _ = audioSessionControl {
|
||||||
self.audioSessionShouldBeActive.set(true)
|
self.audioSessionShouldBeActive.set(true)
|
||||||
}
|
}
|
||||||
case let .active(key, _, connections, maxLayer):
|
case let .active(key, _, connections, maxLayer, allowsP2P):
|
||||||
self.audioSessionShouldBeActive.set(true)
|
self.audioSessionShouldBeActive.set(true)
|
||||||
if let _ = audioSessionControl, !wasActive || previousControl == nil {
|
if let _ = audioSessionControl, !wasActive || previousControl == nil {
|
||||||
self.ongoingContext.start(key: key, isOutgoing: sessionState.isOutgoing, connections: connections, maxLayer: maxLayer, audioSessionActive: self.audioSessionActive.get())
|
self.ongoingContext.start(key: key, isOutgoing: sessionState.isOutgoing, connections: connections, maxLayer: maxLayer, allowP2P: allowsP2P, audioSessionActive: self.audioSessionActive.get())
|
||||||
if sessionState.isOutgoing {
|
if sessionState.isOutgoing {
|
||||||
self.callKitIntegration?.reportOutgoingCallConnected(uuid: sessionState.id, at: Date())
|
self.callKitIntegration?.reportOutgoingCallConnected(uuid: sessionState.id, at: Date())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -376,7 +376,7 @@ public func privacyAndSecurityController(account: Account, initialSettings: Sign
|
|||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> mapToSignal { value -> Signal<Void, NoError> in
|
|> mapToSignal { value -> Signal<Void, NoError> in
|
||||||
if let value = value {
|
if let value = value {
|
||||||
privacySettingsPromise.set(.single(AccountPrivacySettings(presence: updated, groupInvitations: value.groupInvitations, voiceCalls: value.voiceCalls, accountRemovalTimeout: value.accountRemovalTimeout)))
|
privacySettingsPromise.set(.single(AccountPrivacySettings(presence: updated, groupInvitations: value.groupInvitations, voiceCalls: value.voiceCalls, voiceCallsP2P: value.voiceCallsP2P, accountRemovalTimeout: value.accountRemovalTimeout)))
|
||||||
}
|
}
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
@ -399,7 +399,7 @@ public func privacyAndSecurityController(account: Account, initialSettings: Sign
|
|||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> mapToSignal { value -> Signal<Void, NoError> in
|
|> mapToSignal { value -> Signal<Void, NoError> in
|
||||||
if let value = value {
|
if let value = value {
|
||||||
privacySettingsPromise.set(.single(AccountPrivacySettings(presence: value.presence, groupInvitations: updated, voiceCalls: value.voiceCalls, accountRemovalTimeout: value.accountRemovalTimeout)))
|
privacySettingsPromise.set(.single(AccountPrivacySettings(presence: value.presence, groupInvitations: updated, voiceCalls: value.voiceCalls, voiceCallsP2P: value.voiceCallsP2P, accountRemovalTimeout: value.accountRemovalTimeout)))
|
||||||
}
|
}
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
@ -424,8 +424,8 @@ public func privacyAndSecurityController(account: Account, initialSettings: Sign
|
|||||||
currentInfoDisposable.set((combineLatest(privacySignal, callsSignal)
|
currentInfoDisposable.set((combineLatest(privacySignal, callsSignal)
|
||||||
|> deliverOnMainQueue).start(next: { [weak currentInfoDisposable] info, callSettings in
|
|> deliverOnMainQueue).start(next: { [weak currentInfoDisposable] info, callSettings in
|
||||||
if let info = info {
|
if let info = info {
|
||||||
pushControllerImpl?(selectivePrivacySettingsController(account: account, kind: .voiceCalls, current: info.voiceCalls, callSettings: callSettings.0, voipConfiguration: callSettings.1, callIntegrationAvailable: CallKitIntegration.isAvailable, updated: { updated, updatedCallSettings in
|
pushControllerImpl?(selectivePrivacySettingsController(account: account, kind: .voiceCalls, current: info.voiceCalls, callSettings: (info.voiceCallsP2P, callSettings.0), voipConfiguration: callSettings.1, callIntegrationAvailable: CallKitIntegration.isAvailable, updated: { updated, updatedCallSettings in
|
||||||
if let currentInfoDisposable = currentInfoDisposable, let updatedCallSettings = updatedCallSettings {
|
if let currentInfoDisposable = currentInfoDisposable, let (updatedCallsPrivacy, updatedCallSettings) = updatedCallSettings {
|
||||||
let _ = updateVoiceCallSettingsSettingsInteractively(postbox: account.postbox, { _ in
|
let _ = updateVoiceCallSettingsSettingsInteractively(postbox: account.postbox, { _ in
|
||||||
return updatedCallSettings
|
return updatedCallSettings
|
||||||
}).start()
|
}).start()
|
||||||
@ -436,7 +436,7 @@ public func privacyAndSecurityController(account: Account, initialSettings: Sign
|
|||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> mapToSignal { value -> Signal<Void, NoError> in
|
|> mapToSignal { value -> Signal<Void, NoError> in
|
||||||
if let value = value {
|
if let value = value {
|
||||||
privacySettingsPromise.set(.single(AccountPrivacySettings(presence: value.presence, groupInvitations: value.groupInvitations, voiceCalls: updated, accountRemovalTimeout: value.accountRemovalTimeout)))
|
privacySettingsPromise.set(.single(AccountPrivacySettings(presence: value.presence, groupInvitations: value.groupInvitations, voiceCalls: updated, voiceCallsP2P: updatedCallsPrivacy, accountRemovalTimeout: value.accountRemovalTimeout)))
|
||||||
}
|
}
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
@ -485,7 +485,7 @@ public func privacyAndSecurityController(account: Account, initialSettings: Sign
|
|||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> mapToSignal { value -> Signal<Void, NoError> in
|
|> mapToSignal { value -> Signal<Void, NoError> in
|
||||||
if let value = value {
|
if let value = value {
|
||||||
privacySettingsPromise.set(.single(AccountPrivacySettings(presence: value.presence, groupInvitations: value.groupInvitations, voiceCalls: value.voiceCalls, accountRemovalTimeout: timeout)))
|
privacySettingsPromise.set(.single(AccountPrivacySettings(presence: value.presence, groupInvitations: value.groupInvitations, voiceCalls: value.voiceCalls, voiceCallsP2P: value.voiceCallsP2P, accountRemovalTimeout: timeout)))
|
||||||
}
|
}
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,24 +27,29 @@ private enum SelectivePrivacySettingType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum SelectivePrivacySettingsPeerTarget {
|
||||||
|
case main
|
||||||
|
case callP2P
|
||||||
|
}
|
||||||
|
|
||||||
private final class SelectivePrivacySettingsControllerArguments {
|
private final class SelectivePrivacySettingsControllerArguments {
|
||||||
let account: Account
|
let account: Account
|
||||||
|
|
||||||
let updateType: (SelectivePrivacySettingType) -> Void
|
let updateType: (SelectivePrivacySettingType) -> Void
|
||||||
let openEnableFor: () -> Void
|
let openEnableFor: (SelectivePrivacySettingsPeerTarget) -> Void
|
||||||
let openDisableFor: () -> Void
|
let openDisableFor: (SelectivePrivacySettingsPeerTarget) -> Void
|
||||||
|
|
||||||
let updateCallsP2PMode: ((VoiceCallP2PMode) -> Void)?
|
let updateCallP2PMode: ((SelectivePrivacySettingType) -> Void)?
|
||||||
let updateCallsIntegrationEnabled: ((Bool) -> Void)?
|
let updateCallIntegrationEnabled: ((Bool) -> Void)?
|
||||||
|
|
||||||
init(account: Account, updateType: @escaping (SelectivePrivacySettingType) -> Void, openEnableFor: @escaping () -> Void, openDisableFor: @escaping () -> Void, updateCallsP2PMode: ((VoiceCallP2PMode) -> Void)?, updateCallsIntegrationEnabled: ((Bool) -> Void)?) {
|
init(account: Account, updateType: @escaping (SelectivePrivacySettingType) -> Void, openEnableFor: @escaping (SelectivePrivacySettingsPeerTarget) -> Void, openDisableFor: @escaping (SelectivePrivacySettingsPeerTarget) -> Void, updateCallP2PMode: ((SelectivePrivacySettingType) -> Void)?, updateCallIntegrationEnabled: ((Bool) -> Void)?) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.updateType = updateType
|
self.updateType = updateType
|
||||||
self.openEnableFor = openEnableFor
|
self.openEnableFor = openEnableFor
|
||||||
self.openDisableFor = openDisableFor
|
self.openDisableFor = openDisableFor
|
||||||
|
|
||||||
self.updateCallsP2PMode = updateCallsP2PMode
|
self.updateCallP2PMode = updateCallP2PMode
|
||||||
self.updateCallsIntegrationEnabled = updateCallsIntegrationEnabled
|
self.updateCallIntegrationEnabled = updateCallIntegrationEnabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +57,7 @@ private enum SelectivePrivacySettingsSection: Int32 {
|
|||||||
case setting
|
case setting
|
||||||
case peers
|
case peers
|
||||||
case callsP2P
|
case callsP2P
|
||||||
|
case callsP2PPeers
|
||||||
case callsIntegrationEnabled
|
case callsIntegrationEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +83,9 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
|||||||
case callsP2PContacts(PresentationTheme, String, Bool)
|
case callsP2PContacts(PresentationTheme, String, Bool)
|
||||||
case callsP2PNever(PresentationTheme, String, Bool)
|
case callsP2PNever(PresentationTheme, String, Bool)
|
||||||
case callsP2PInfo(PresentationTheme, String)
|
case callsP2PInfo(PresentationTheme, String)
|
||||||
|
case callsP2PDisableFor(PresentationTheme, String, String)
|
||||||
|
case callsP2PEnableFor(PresentationTheme, String, String)
|
||||||
|
case callsP2PPeersInfo(PresentationTheme, String)
|
||||||
case callsIntegrationEnabled(PresentationTheme, String, Bool)
|
case callsIntegrationEnabled(PresentationTheme, String, Bool)
|
||||||
case callsIntegrationInfo(PresentationTheme, String)
|
case callsIntegrationInfo(PresentationTheme, String)
|
||||||
|
|
||||||
@ -88,6 +97,8 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
|||||||
return SelectivePrivacySettingsSection.peers.rawValue
|
return SelectivePrivacySettingsSection.peers.rawValue
|
||||||
case .callsP2PHeader, .callsP2PAlways, .callsP2PContacts, .callsP2PNever, .callsP2PInfo:
|
case .callsP2PHeader, .callsP2PAlways, .callsP2PContacts, .callsP2PNever, .callsP2PInfo:
|
||||||
return SelectivePrivacySettingsSection.callsP2P.rawValue
|
return SelectivePrivacySettingsSection.callsP2P.rawValue
|
||||||
|
case .callsP2PDisableFor, .callsP2PEnableFor, .callsP2PPeersInfo:
|
||||||
|
return SelectivePrivacySettingsSection.callsP2PPeers.rawValue
|
||||||
case .callsIntegrationEnabled, .callsIntegrationInfo:
|
case .callsIntegrationEnabled, .callsIntegrationInfo:
|
||||||
return SelectivePrivacySettingsSection.callsIntegrationEnabled.rawValue
|
return SelectivePrivacySettingsSection.callsIntegrationEnabled.rawValue
|
||||||
}
|
}
|
||||||
@ -121,10 +132,16 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
|||||||
return 11
|
return 11
|
||||||
case .callsP2PInfo:
|
case .callsP2PInfo:
|
||||||
return 12
|
return 12
|
||||||
case .callsIntegrationEnabled:
|
case .callsP2PDisableFor:
|
||||||
return 13
|
return 13
|
||||||
case .callsIntegrationInfo:
|
case .callsP2PEnableFor:
|
||||||
return 14
|
return 14
|
||||||
|
case .callsP2PPeersInfo:
|
||||||
|
return 15
|
||||||
|
case .callsIntegrationEnabled:
|
||||||
|
return 16
|
||||||
|
case .callsIntegrationInfo:
|
||||||
|
return 17
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,6 +225,24 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case let .callsP2PDisableFor(lhsTheme, lhsText, lhsValue):
|
||||||
|
if case let .callsP2PDisableFor(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .callsP2PEnableFor(lhsTheme, lhsText, lhsValue):
|
||||||
|
if case let .callsP2PEnableFor(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .callsP2PPeersInfo(lhsTheme, lhsText):
|
||||||
|
if case let .callsP2PPeersInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
case let .callsIntegrationEnabled(lhsTheme, lhsText, lhsValue):
|
case let .callsIntegrationEnabled(lhsTheme, lhsText, lhsValue):
|
||||||
if case let .callsIntegrationEnabled(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
if case let .callsIntegrationEnabled(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||||
return true
|
return true
|
||||||
@ -247,11 +282,11 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
|||||||
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
|
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
|
||||||
case let .disableFor(theme, title, value):
|
case let .disableFor(theme, title, value):
|
||||||
return ItemListDisclosureItem(theme: theme, title: title, label: value, sectionId: self.section, style: .blocks, action: {
|
return ItemListDisclosureItem(theme: theme, title: title, label: value, sectionId: self.section, style: .blocks, action: {
|
||||||
arguments.openDisableFor()
|
arguments.openDisableFor(.main)
|
||||||
})
|
})
|
||||||
case let .enableFor(theme, title, value):
|
case let .enableFor(theme, title, value):
|
||||||
return ItemListDisclosureItem(theme: theme, title: title, label: value, sectionId: self.section, style: .blocks, action: {
|
return ItemListDisclosureItem(theme: theme, title: title, label: value, sectionId: self.section, style: .blocks, action: {
|
||||||
arguments.openEnableFor()
|
arguments.openEnableFor(.main)
|
||||||
})
|
})
|
||||||
case let .peersInfo(theme, text):
|
case let .peersInfo(theme, text):
|
||||||
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
|
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
|
||||||
@ -259,21 +294,31 @@ private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
|
|||||||
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
|
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
|
||||||
case let .callsP2PAlways(theme, text, value):
|
case let .callsP2PAlways(theme, text, value):
|
||||||
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||||
arguments.updateCallsP2PMode?(.always)
|
arguments.updateCallP2PMode?(.everybody)
|
||||||
})
|
})
|
||||||
case let .callsP2PContacts(theme, text, value):
|
case let .callsP2PContacts(theme, text, value):
|
||||||
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||||
arguments.updateCallsP2PMode?(.contacts)
|
arguments.updateCallP2PMode?(.contacts)
|
||||||
})
|
})
|
||||||
case let .callsP2PNever(theme, text, value):
|
case let .callsP2PNever(theme, text, value):
|
||||||
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||||
arguments.updateCallsP2PMode?(.never)
|
arguments.updateCallP2PMode?(.nobody)
|
||||||
})
|
})
|
||||||
case let .callsP2PInfo(theme, text):
|
case let .callsP2PInfo(theme, text):
|
||||||
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
|
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
|
||||||
|
case let .callsP2PDisableFor(theme, title, value):
|
||||||
|
return ItemListDisclosureItem(theme: theme, title: title, label: value, sectionId: self.section, style: .blocks, action: {
|
||||||
|
arguments.openDisableFor(.callP2P)
|
||||||
|
})
|
||||||
|
case let .callsP2PEnableFor(theme, title, value):
|
||||||
|
return ItemListDisclosureItem(theme: theme, title: title, label: value, sectionId: self.section, style: .blocks, action: {
|
||||||
|
arguments.openEnableFor(.callP2P)
|
||||||
|
})
|
||||||
|
case let .callsP2PPeersInfo(theme, text):
|
||||||
|
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
|
||||||
case let .callsIntegrationEnabled(theme, text, value):
|
case let .callsIntegrationEnabled(theme, text, value):
|
||||||
return ItemListSwitchItem(theme: theme, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
return ItemListSwitchItem(theme: theme, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||||
arguments.updateCallsIntegrationEnabled?(value)
|
arguments.updateCallIntegrationEnabled?(value)
|
||||||
})
|
})
|
||||||
case let .callsIntegrationInfo(theme, text):
|
case let .callsIntegrationInfo(theme, text):
|
||||||
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
|
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
|
||||||
@ -289,17 +334,21 @@ private struct SelectivePrivacySettingsControllerState: Equatable {
|
|||||||
let saving: Bool
|
let saving: Bool
|
||||||
|
|
||||||
let callDataSaving: VoiceCallDataSaving?
|
let callDataSaving: VoiceCallDataSaving?
|
||||||
let callP2PMode: VoiceCallP2PMode?
|
let callP2PMode: SelectivePrivacySettingType?
|
||||||
|
let callP2PEnableFor: Set<PeerId>?
|
||||||
|
let callP2PDisableFor: Set<PeerId>?
|
||||||
let callIntegrationAvailable: Bool?
|
let callIntegrationAvailable: Bool?
|
||||||
let callIntegrationEnabled: Bool?
|
let callIntegrationEnabled: Bool?
|
||||||
|
|
||||||
init(setting: SelectivePrivacySettingType, enableFor: Set<PeerId>, disableFor: Set<PeerId>, saving: Bool, callDataSaving: VoiceCallDataSaving?, callP2PMode: VoiceCallP2PMode?, callIntegrationAvailable: Bool?, callIntegrationEnabled: Bool?) {
|
init(setting: SelectivePrivacySettingType, enableFor: Set<PeerId>, disableFor: Set<PeerId>, saving: Bool, callDataSaving: VoiceCallDataSaving?, callP2PMode: SelectivePrivacySettingType?, callP2PEnableFor: Set<PeerId>?, callP2PDisableFor: Set<PeerId>?, callIntegrationAvailable: Bool?, callIntegrationEnabled: Bool?) {
|
||||||
self.setting = setting
|
self.setting = setting
|
||||||
self.enableFor = enableFor
|
self.enableFor = enableFor
|
||||||
self.disableFor = disableFor
|
self.disableFor = disableFor
|
||||||
self.saving = saving
|
self.saving = saving
|
||||||
self.callDataSaving = callDataSaving
|
self.callDataSaving = callDataSaving
|
||||||
self.callP2PMode = callP2PMode
|
self.callP2PMode = callP2PMode
|
||||||
|
self.callP2PEnableFor = callP2PEnableFor
|
||||||
|
self.callP2PDisableFor = callP2PDisableFor
|
||||||
self.callIntegrationAvailable = callIntegrationAvailable
|
self.callIntegrationAvailable = callIntegrationAvailable
|
||||||
self.callIntegrationEnabled = callIntegrationEnabled
|
self.callIntegrationEnabled = callIntegrationEnabled
|
||||||
}
|
}
|
||||||
@ -323,6 +372,12 @@ private struct SelectivePrivacySettingsControllerState: Equatable {
|
|||||||
if lhs.callP2PMode != rhs.callP2PMode {
|
if lhs.callP2PMode != rhs.callP2PMode {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.callP2PEnableFor != rhs.callP2PEnableFor {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.callP2PDisableFor != rhs.callP2PDisableFor {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.callIntegrationAvailable != rhs.callIntegrationAvailable {
|
if lhs.callIntegrationAvailable != rhs.callIntegrationAvailable {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -334,27 +389,35 @@ private struct SelectivePrivacySettingsControllerState: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedSetting(_ setting: SelectivePrivacySettingType) -> SelectivePrivacySettingsControllerState {
|
func withUpdatedSetting(_ setting: SelectivePrivacySettingType) -> SelectivePrivacySettingsControllerState {
|
||||||
return SelectivePrivacySettingsControllerState(setting: setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled)
|
return SelectivePrivacySettingsControllerState(setting: setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedEnableFor(_ enableFor: Set<PeerId>) -> SelectivePrivacySettingsControllerState {
|
func withUpdatedEnableFor(_ enableFor: Set<PeerId>) -> SelectivePrivacySettingsControllerState {
|
||||||
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled)
|
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedDisableFor(_ disableFor: Set<PeerId>) -> SelectivePrivacySettingsControllerState {
|
func withUpdatedDisableFor(_ disableFor: Set<PeerId>) -> SelectivePrivacySettingsControllerState {
|
||||||
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled)
|
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedSaving(_ saving: Bool) -> SelectivePrivacySettingsControllerState {
|
func withUpdatedSaving(_ saving: Bool) -> SelectivePrivacySettingsControllerState {
|
||||||
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled)
|
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedCallsP2PMode(_ mode: VoiceCallP2PMode) -> SelectivePrivacySettingsControllerState {
|
func withUpdatedCallP2PMode(_ mode: SelectivePrivacySettingType) -> SelectivePrivacySettingsControllerState {
|
||||||
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: mode, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled)
|
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: mode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withUpdatedCallP2PEnableFor(_ enableFor: Set<PeerId>) -> SelectivePrivacySettingsControllerState {
|
||||||
|
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: enableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withUpdatedCallP2PDisableFor(_ disableFor: Set<PeerId>) -> SelectivePrivacySettingsControllerState {
|
||||||
|
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: disableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedCallsIntegrationEnabled(_ enabled: Bool) -> SelectivePrivacySettingsControllerState {
|
func withUpdatedCallsIntegrationEnabled(_ enabled: Bool) -> SelectivePrivacySettingsControllerState {
|
||||||
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: enabled)
|
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: enabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,12 +472,24 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
|
|||||||
if case .voiceCalls = kind, let p2pMode = state.callP2PMode, let integrationAvailable = state.callIntegrationAvailable, let integrationEnabled = state.callIntegrationEnabled {
|
if case .voiceCalls = kind, let p2pMode = state.callP2PMode, let integrationAvailable = state.callIntegrationAvailable, let integrationEnabled = state.callIntegrationEnabled {
|
||||||
entries.append(.callsP2PHeader(presentationData.theme, presentationData.strings.Privacy_Calls_P2P.uppercased()))
|
entries.append(.callsP2PHeader(presentationData.theme, presentationData.strings.Privacy_Calls_P2P.uppercased()))
|
||||||
|
|
||||||
entries.append(.callsP2PAlways(presentationData.theme, presentationData.strings.Privacy_Calls_P2PAlways, p2pMode == .always))
|
entries.append(.callsP2PAlways(presentationData.theme, presentationData.strings.Privacy_Calls_P2PAlways, p2pMode == .everybody))
|
||||||
entries.append(.callsP2PContacts(presentationData.theme, presentationData.strings.Privacy_Calls_P2PContacts, p2pMode == .contacts))
|
entries.append(.callsP2PContacts(presentationData.theme, presentationData.strings.Privacy_Calls_P2PContacts, p2pMode == .contacts))
|
||||||
entries.append(.callsP2PNever(presentationData.theme, presentationData.strings.Privacy_Calls_P2PNever, p2pMode == .never))
|
entries.append(.callsP2PNever(presentationData.theme, presentationData.strings.Privacy_Calls_P2PNever, p2pMode == .nobody))
|
||||||
|
|
||||||
entries.append(.callsP2PInfo(presentationData.theme, presentationData.strings.Privacy_Calls_P2PHelp))
|
entries.append(.callsP2PInfo(presentationData.theme, presentationData.strings.Privacy_Calls_P2PHelp))
|
||||||
|
|
||||||
|
if let callP2PMode = state.callP2PMode, let disableFor = state.callP2PDisableFor, let enableFor = state.callP2PEnableFor {
|
||||||
|
switch callP2PMode {
|
||||||
|
case .everybody:
|
||||||
|
entries.append(.callsP2PDisableFor(presentationData.theme, disableForText, stringForUserCount(disableFor.count, strings: presentationData.strings)))
|
||||||
|
case .contacts:
|
||||||
|
entries.append(.callsP2PDisableFor(presentationData.theme, disableForText, stringForUserCount(disableFor.count, strings: presentationData.strings)))
|
||||||
|
entries.append(.callsP2PEnableFor(presentationData.theme, enableForText, stringForUserCount(enableFor.count, strings: presentationData.strings)))
|
||||||
|
case .nobody:
|
||||||
|
entries.append(.callsP2PEnableFor(presentationData.theme, enableForText, stringForUserCount(enableFor.count, strings: presentationData.strings)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entries.append(.callsP2PPeersInfo(presentationData.theme, presentationData.strings.PrivacyLastSeenSettings_CustomShareSettingsHelp))
|
||||||
|
|
||||||
if integrationAvailable {
|
if integrationAvailable {
|
||||||
entries.append(.callsIntegrationEnabled(presentationData.theme, presentationData.strings.Privacy_Calls_Integration, integrationEnabled))
|
entries.append(.callsIntegrationEnabled(presentationData.theme, presentationData.strings.Privacy_Calls_Integration, integrationEnabled))
|
||||||
entries.append(.callsIntegrationInfo(presentationData.theme, presentationData.strings.Privacy_Calls_IntegrationHelp))
|
entries.append(.callsIntegrationInfo(presentationData.theme, presentationData.strings.Privacy_Calls_IntegrationHelp))
|
||||||
@ -424,7 +499,7 @@ private func selectivePrivacySettingsControllerEntries(presentationData: Present
|
|||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectivePrivacySettingsController(account: Account, kind: SelectivePrivacySettingsKind, current: SelectivePrivacySettings, callSettings: VoiceCallSettings? = nil, voipConfiguration: VoipConfiguration? = nil, callIntegrationAvailable: Bool? = nil, updated: @escaping (SelectivePrivacySettings, VoiceCallSettings?) -> Void) -> ViewController {
|
func selectivePrivacySettingsController(account: Account, kind: SelectivePrivacySettingsKind, current: SelectivePrivacySettings, callSettings: (SelectivePrivacySettings, VoiceCallSettings)? = nil, voipConfiguration: VoipConfiguration? = nil, callIntegrationAvailable: Bool? = nil, updated: @escaping (SelectivePrivacySettings, (SelectivePrivacySettings, VoiceCallSettings)?) -> Void) -> ViewController {
|
||||||
let strings = account.telegramApplicationContext.currentPresentationData.with { $0 }.strings
|
let strings = account.telegramApplicationContext.currentPresentationData.with { $0 }.strings
|
||||||
|
|
||||||
var initialEnableFor = Set<PeerId>()
|
var initialEnableFor = Set<PeerId>()
|
||||||
@ -438,7 +513,23 @@ func selectivePrivacySettingsController(account: Account, kind: SelectivePrivacy
|
|||||||
case let .enableEveryone(disableFor):
|
case let .enableEveryone(disableFor):
|
||||||
initialDisableFor = disableFor
|
initialDisableFor = disableFor
|
||||||
}
|
}
|
||||||
let initialState = SelectivePrivacySettingsControllerState(setting: SelectivePrivacySettingType(current), enableFor: initialEnableFor, disableFor: initialDisableFor, saving: false, callDataSaving: callSettings?.dataSaving, callP2PMode: callSettings?.p2pMode ?? voipConfiguration?.defaultP2PMode, callIntegrationAvailable: callIntegrationAvailable, callIntegrationEnabled: callSettings?.enableSystemIntegration)
|
var initialCallP2PEnableFor: Set<PeerId>?
|
||||||
|
var initialCallP2PDisableFor: Set<PeerId>?
|
||||||
|
if let callCurrent = callSettings?.0 {
|
||||||
|
switch callCurrent {
|
||||||
|
case let .disableEveryone(enableFor):
|
||||||
|
initialCallP2PEnableFor = enableFor
|
||||||
|
initialCallP2PDisableFor = Set<PeerId>()
|
||||||
|
case let .enableContacts(enableFor, disableFor):
|
||||||
|
initialCallP2PEnableFor = enableFor
|
||||||
|
initialCallP2PDisableFor = disableFor
|
||||||
|
case let .enableEveryone(disableFor):
|
||||||
|
initialCallP2PEnableFor = Set<PeerId>()
|
||||||
|
initialCallP2PDisableFor = disableFor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let initialState = SelectivePrivacySettingsControllerState(setting: SelectivePrivacySettingType(current), enableFor: initialEnableFor, disableFor: initialDisableFor, saving: false, callDataSaving: callSettings?.1.dataSaving, callP2PMode: callSettings != nil ? SelectivePrivacySettingType(callSettings!.0) : nil, callP2PEnableFor: initialCallP2PEnableFor, callP2PDisableFor: initialCallP2PDisableFor, callIntegrationAvailable: callIntegrationAvailable, callIntegrationEnabled: callSettings?.1.enableSystemIntegration)
|
||||||
|
|
||||||
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
||||||
let stateValue = Atomic(value: initialState)
|
let stateValue = Atomic(value: initialState)
|
||||||
@ -458,7 +549,7 @@ func selectivePrivacySettingsController(account: Account, kind: SelectivePrivacy
|
|||||||
updateState {
|
updateState {
|
||||||
$0.withUpdatedSetting(type)
|
$0.withUpdatedSetting(type)
|
||||||
}
|
}
|
||||||
}, openEnableFor: {
|
}, openEnableFor: { target in
|
||||||
let title: String
|
let title: String
|
||||||
switch kind {
|
switch kind {
|
||||||
case .presence:
|
case .presence:
|
||||||
@ -475,10 +566,15 @@ func selectivePrivacySettingsController(account: Account, kind: SelectivePrivacy
|
|||||||
}
|
}
|
||||||
pushControllerImpl?(selectivePrivacyPeersController(account: account, title: title, initialPeerIds: Array(peerIds), updated: { updatedPeerIds in
|
pushControllerImpl?(selectivePrivacyPeersController(account: account, title: title, initialPeerIds: Array(peerIds), updated: { updatedPeerIds in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
return state.withUpdatedEnableFor(Set(updatedPeerIds)).withUpdatedDisableFor(state.disableFor.subtracting(Set(updatedPeerIds)))
|
switch target {
|
||||||
|
case .main:
|
||||||
|
return state.withUpdatedEnableFor(Set(updatedPeerIds)).withUpdatedDisableFor(state.disableFor.subtracting(Set(updatedPeerIds)))
|
||||||
|
case .callP2P:
|
||||||
|
return state.withUpdatedCallP2PEnableFor(Set(updatedPeerIds)).withUpdatedCallP2PDisableFor(state.disableFor.subtracting(Set(updatedPeerIds)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}, openDisableFor: {
|
}, openDisableFor: { target in
|
||||||
let title: String
|
let title: String
|
||||||
switch kind {
|
switch kind {
|
||||||
case .presence:
|
case .presence:
|
||||||
@ -495,19 +591,19 @@ func selectivePrivacySettingsController(account: Account, kind: SelectivePrivacy
|
|||||||
}
|
}
|
||||||
pushControllerImpl?(selectivePrivacyPeersController(account: account, title: title, initialPeerIds: Array(peerIds), updated: { updatedPeerIds in
|
pushControllerImpl?(selectivePrivacyPeersController(account: account, title: title, initialPeerIds: Array(peerIds), updated: { updatedPeerIds in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
return state.withUpdatedDisableFor(Set(updatedPeerIds)).withUpdatedEnableFor(state.enableFor.subtracting(Set(updatedPeerIds)))
|
switch target {
|
||||||
|
case .main:
|
||||||
|
return state.withUpdatedDisableFor(Set(updatedPeerIds)).withUpdatedEnableFor(state.enableFor.subtracting(Set(updatedPeerIds)))
|
||||||
|
case .callP2P:
|
||||||
|
return state.withUpdatedCallP2PDisableFor(Set(updatedPeerIds)).withUpdatedCallP2PEnableFor(state.enableFor.subtracting(Set(updatedPeerIds)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}, updateCallsP2PMode: { mode in
|
}, updateCallP2PMode: { mode in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
return state.withUpdatedCallsP2PMode(mode)
|
return state.withUpdatedCallP2PMode(mode)
|
||||||
}
|
}
|
||||||
let _ = updateVoiceCallSettingsSettingsInteractively(postbox: account.postbox, { settings in
|
}, updateCallIntegrationEnabled: { enabled in
|
||||||
var settings = settings
|
|
||||||
settings.p2pMode = mode
|
|
||||||
return settings
|
|
||||||
}).start()
|
|
||||||
}, updateCallsIntegrationEnabled: { enabled in
|
|
||||||
updateState { state in
|
updateState { state in
|
||||||
return state.withUpdatedCallsIntegrationEnabled(enabled)
|
return state.withUpdatedCallsIntegrationEnabled(enabled)
|
||||||
}
|
}
|
||||||
@ -532,6 +628,7 @@ func selectivePrivacySettingsController(account: Account, kind: SelectivePrivacy
|
|||||||
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
|
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
|
||||||
var wasSaving = false
|
var wasSaving = false
|
||||||
var settings: SelectivePrivacySettings?
|
var settings: SelectivePrivacySettings?
|
||||||
|
var callP2PSettings: SelectivePrivacySettings?
|
||||||
updateState { state in
|
updateState { state in
|
||||||
wasSaving = state.saving
|
wasSaving = state.saving
|
||||||
switch state.setting {
|
switch state.setting {
|
||||||
@ -542,6 +639,18 @@ func selectivePrivacySettingsController(account: Account, kind: SelectivePrivacy
|
|||||||
case .nobody:
|
case .nobody:
|
||||||
settings = SelectivePrivacySettings.disableEveryone(enableFor: state.enableFor)
|
settings = SelectivePrivacySettings.disableEveryone(enableFor: state.enableFor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if case .voiceCalls = kind, let callP2PMode = state.callP2PMode, let disableFor = state.callP2PDisableFor, let enableFor = state.callP2PEnableFor {
|
||||||
|
switch callP2PMode {
|
||||||
|
case .everybody:
|
||||||
|
callP2PSettings = SelectivePrivacySettings.enableEveryone(disableFor: disableFor)
|
||||||
|
case .contacts:
|
||||||
|
callP2PSettings = SelectivePrivacySettings.enableContacts(enableFor: enableFor, disableFor: disableFor)
|
||||||
|
case .nobody:
|
||||||
|
callP2PSettings = SelectivePrivacySettings.disableEveryone(enableFor: enableFor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return state.withUpdatedSaving(true)
|
return state.withUpdatedSaving(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,12 +665,18 @@ func selectivePrivacySettingsController(account: Account, kind: SelectivePrivacy
|
|||||||
type = .voiceCalls
|
type = .voiceCalls
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSettingsDisposable.set((updateSelectiveAccountPrivacySettings(account: account, type: type, settings: settings) |> deliverOnMainQueue).start(completed: {
|
let updateSettingsSignal = updateSelectiveAccountPrivacySettings(account: account, type: type, settings: settings)
|
||||||
|
var updateCallP2PSettingsSignal: Signal<Void, NoError> = Signal.complete()
|
||||||
|
if let callP2PSettings = callP2PSettings {
|
||||||
|
updateCallP2PSettingsSignal = updateSelectiveAccountPrivacySettings(account: account, type: .voiceCallsP2P, settings: callP2PSettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSettingsDisposable.set((combineLatest(updateSettingsSignal, updateCallP2PSettingsSignal) |> deliverOnMainQueue).start(completed: {
|
||||||
updateState { state in
|
updateState { state in
|
||||||
return state.withUpdatedSaving(false)
|
return state.withUpdatedSaving(false)
|
||||||
}
|
}
|
||||||
if case .voiceCalls = kind, let dataSaving = state.callDataSaving, let p2pMode = state.callP2PMode, let systemIntegrationEnabled = state.callIntegrationEnabled {
|
if case .voiceCalls = kind, let dataSaving = state.callDataSaving, let callP2PSettings = callP2PSettings, let systemIntegrationEnabled = state.callIntegrationEnabled {
|
||||||
updated(settings, VoiceCallSettings(dataSaving: dataSaving, p2pMode: p2pMode, enableSystemIntegration: systemIntegrationEnabled))
|
updated(settings, (callP2PSettings, VoiceCallSettings(dataSaving: dataSaving, p2pMode: nil, enableSystemIntegration: systemIntegrationEnabled)))
|
||||||
} else {
|
} else {
|
||||||
updated(settings, nil)
|
updated(settings, nil)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user