mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
iOS 13 style segmented control
iPad UI improvements
This commit is contained in:
parent
e99a9e8d99
commit
c8837e04f8
@ -274,6 +274,9 @@
|
|||||||
<FileRef
|
<FileRef
|
||||||
location = "group:submodules/RadialStatusNode/RadialStatusNode_Xcode.xcodeproj">
|
location = "group:submodules/RadialStatusNode/RadialStatusNode_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:submodules/SegmentedControlNode/SegmentedControlNode_Xcode.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:submodules/LiveLocationTimerNode/LiveLocationTimerNode_Xcode.xcodeproj">
|
location = "group:submodules/LiveLocationTimerNode/LiveLocationTimerNode_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
@ -45,7 +45,7 @@ public final class CallListController: ViewController {
|
|||||||
self.mode = mode
|
self.mode = mode
|
||||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
self.segmentedTitleView = ItemListControllerSegmentedTitleView(segments: [self.presentationData.strings.Calls_All, self.presentationData.strings.Calls_Missed], index: 0, color: self.presentationData.theme.rootController.navigationBar.accentTextColor)
|
self.segmentedTitleView = ItemListControllerSegmentedTitleView(theme: self.presentationData.theme, segments: [self.presentationData.strings.Calls_All, self.presentationData.strings.Calls_Missed], selectedIndex: 0)
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ public final class CallListController: ViewController {
|
|||||||
private func updateThemeAndStrings() {
|
private func updateThemeAndStrings() {
|
||||||
let index = self.segmentedTitleView.index
|
let index = self.segmentedTitleView.index
|
||||||
self.segmentedTitleView.segments = [self.presentationData.strings.Calls_All, self.presentationData.strings.Calls_Missed]
|
self.segmentedTitleView.segments = [self.presentationData.strings.Calls_All, self.presentationData.strings.Calls_Missed]
|
||||||
self.segmentedTitleView.color = self.presentationData.theme.rootController.navigationBar.accentTextColor
|
self.segmentedTitleView.theme = self.presentationData.theme
|
||||||
self.segmentedTitleView.index = index
|
self.segmentedTitleView.index = index
|
||||||
|
|
||||||
self.tabBarItem.title = self.presentationData.strings.Calls_TabTitle
|
self.tabBarItem.title = self.presentationData.strings.Calls_TabTitle
|
||||||
|
@ -151,8 +151,7 @@ public func generateImage(_ size: CGSize, opaque: Bool = false, scale: CGFloat?
|
|||||||
|
|
||||||
guard let provider = CGDataProvider(dataInfo: bytes, data: bytes, size: length, releaseData: { bytes, _, _ in
|
guard let provider = CGDataProvider(dataInfo: bytes, data: bytes, size: length, releaseData: { bytes, _, _ in
|
||||||
free(bytes)
|
free(bytes)
|
||||||
})
|
}) else {
|
||||||
else {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,11 +6,12 @@ import TelegramCore
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import AccountContext
|
import AccountContext
|
||||||
import ChatListUI
|
import ChatListUI
|
||||||
|
import SegmentedControlNode
|
||||||
|
|
||||||
final class HashtagSearchControllerNode: ASDisplayNode {
|
final class HashtagSearchControllerNode: ASDisplayNode {
|
||||||
private let toolbarBackgroundNode: ASDisplayNode
|
private let toolbarBackgroundNode: ASDisplayNode
|
||||||
private let toolbarSeparatorNode: ASDisplayNode
|
private let toolbarSeparatorNode: ASDisplayNode
|
||||||
private let segmentedControl: UISegmentedControl
|
private let segmentedControlNode: SegmentedControlNode
|
||||||
let listNode: ListView
|
let listNode: ListView
|
||||||
|
|
||||||
var chatController: ChatController?
|
var chatController: ChatController?
|
||||||
@ -35,9 +36,11 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
|||||||
self.toolbarSeparatorNode = ASDisplayNode()
|
self.toolbarSeparatorNode = ASDisplayNode()
|
||||||
self.toolbarSeparatorNode.backgroundColor = theme.rootController.navigationBar.separatorColor
|
self.toolbarSeparatorNode.backgroundColor = theme.rootController.navigationBar.separatorColor
|
||||||
|
|
||||||
self.segmentedControl = UISegmentedControl(items: [peer?.displayTitle ?? "", strings.HashtagSearch_AllChats])
|
let items = [
|
||||||
self.segmentedControl.tintColor = theme.rootController.navigationBar.accentTextColor
|
peer?.displayTitle ?? "",
|
||||||
self.segmentedControl.selectedSegmentIndex = 0
|
strings.HashtagSearch_AllChats
|
||||||
|
]
|
||||||
|
self.segmentedControlNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: theme), items: items.map { SegmentedControlItem(title: $0) }, selectedIndex: 0)
|
||||||
|
|
||||||
if let peer = peer {
|
if let peer = peer {
|
||||||
self.chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(peer.id), subject: nil, botStart: nil, mode: .inline)
|
self.chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(peer.id), subject: nil, botStart: nil, mode: .inline)
|
||||||
@ -56,7 +59,17 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
|||||||
self.addSubnode(self.listNode)
|
self.addSubnode(self.listNode)
|
||||||
self.listNode.isHidden = true
|
self.listNode.isHidden = true
|
||||||
|
|
||||||
self.segmentedControl.addTarget(self, action: #selector(self.indexChanged), for: .valueChanged)
|
self.segmentedControlNode.selectedIndexChanged = { [weak self] index in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if index == 0 {
|
||||||
|
strongSelf.chatController?.displayNode.isHidden = false
|
||||||
|
strongSelf.listNode.isHidden = true
|
||||||
|
} else {
|
||||||
|
strongSelf.chatController?.displayNode.isHidden = true
|
||||||
|
strongSelf.listNode.isHidden = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func enqueueTransition(_ transition: ChatListSearchContainerTransition, firstTime: Bool) {
|
func enqueueTransition(_ transition: ChatListSearchContainerTransition, firstTime: Bool) {
|
||||||
@ -84,8 +97,7 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
|||||||
if self.chatController != nil && self.toolbarBackgroundNode.supernode == nil {
|
if self.chatController != nil && self.toolbarBackgroundNode.supernode == nil {
|
||||||
self.addSubnode(self.toolbarBackgroundNode)
|
self.addSubnode(self.toolbarBackgroundNode)
|
||||||
self.addSubnode(self.toolbarSeparatorNode)
|
self.addSubnode(self.toolbarSeparatorNode)
|
||||||
|
self.addSubnode(self.segmentedControlNode)
|
||||||
self.view.addSubview(self.segmentedControl)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var insets = layout.insets(options: [.input])
|
var insets = layout.insets(options: [.input])
|
||||||
@ -97,10 +109,8 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
|||||||
transition.updateFrame(node: self.toolbarBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY), size: CGSize(width: layout.size.width, height: toolbarHeight)))
|
transition.updateFrame(node: self.toolbarBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY), size: CGSize(width: layout.size.width, height: toolbarHeight)))
|
||||||
transition.updateFrame(node: self.toolbarSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY + toolbarHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
transition.updateFrame(node: self.toolbarSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY + toolbarHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
||||||
|
|
||||||
var controlSize = self.segmentedControl.sizeThatFits(layout.size)
|
let controlSize = self.segmentedControlNode.updateLayout(.stretchToFill(width: layout.size.width - 14.0 * 2.0), transition: transition)
|
||||||
controlSize.width = layout.size.width - 14.0 * 2.0
|
transition.updateFrame(node: self.segmentedControlNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - controlSize.width) / 2.0), y: panelY + floor((toolbarHeight - controlSize.height) / 2.0)), size: controlSize))
|
||||||
|
|
||||||
transition.updateFrame(view: self.segmentedControl, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - controlSize.width) / 2.0), y: panelY + floor((toolbarHeight - controlSize.height) / 2.0)), size: controlSize))
|
|
||||||
|
|
||||||
if let chatController = self.chatController {
|
if let chatController = self.chatController {
|
||||||
insets.top += toolbarHeight - 4.0
|
insets.top += toolbarHeight - 4.0
|
||||||
@ -146,21 +156,11 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
|
||||||
if !hasValidLayout {
|
if !self.hasValidLayout {
|
||||||
hasValidLayout = true
|
self.hasValidLayout = true
|
||||||
while !self.enqueuedTransitions.isEmpty {
|
while !self.enqueuedTransitions.isEmpty {
|
||||||
self.dequeueTransition()
|
self.dequeueTransition()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func indexChanged() {
|
|
||||||
if self.segmentedControl.selectedSegmentIndex == 0 {
|
|
||||||
self.chatController?.displayNode.isHidden = false
|
|
||||||
self.listNode.isHidden = true
|
|
||||||
} else {
|
|
||||||
self.chatController?.displayNode.isHidden = true
|
|
||||||
self.listNode.isHidden = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
09CE5B922322985500743FF4 /* ItemListMaskAccessory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09CE5B912322985500743FF4 /* ItemListMaskAccessory.swift */; };
|
||||||
D060182122F35C2300796784 /* ProgressNavigationButtonNode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D060182022F35C2300796784 /* ProgressNavigationButtonNode.framework */; };
|
D060182122F35C2300796784 /* ProgressNavigationButtonNode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D060182022F35C2300796784 /* ProgressNavigationButtonNode.framework */; };
|
||||||
D060185322F35E1F00796784 /* ItemListMultilineInputItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060184922F35E1E00796784 /* ItemListMultilineInputItem.swift */; };
|
D060185322F35E1F00796784 /* ItemListMultilineInputItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060184922F35E1E00796784 /* ItemListMultilineInputItem.swift */; };
|
||||||
D060185422F35E1F00796784 /* ItemListTextWithLabelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060184A22F35E1E00796784 /* ItemListTextWithLabelItem.swift */; };
|
D060185422F35E1F00796784 /* ItemListTextWithLabelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060184A22F35E1E00796784 /* ItemListTextWithLabelItem.swift */; };
|
||||||
@ -50,6 +51,7 @@
|
|||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
09CE5B912322985500743FF4 /* ItemListMaskAccessory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemListMaskAccessory.swift; sourceTree = "<group>"; };
|
||||||
D060182022F35C2300796784 /* ProgressNavigationButtonNode.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ProgressNavigationButtonNode.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
D060182022F35C2300796784 /* ProgressNavigationButtonNode.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ProgressNavigationButtonNode.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D060184922F35E1E00796784 /* ItemListMultilineInputItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListMultilineInputItem.swift; sourceTree = "<group>"; };
|
D060184922F35E1E00796784 /* ItemListMultilineInputItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListMultilineInputItem.swift; sourceTree = "<group>"; };
|
||||||
D060184A22F35E1E00796784 /* ItemListTextWithLabelItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListTextWithLabelItem.swift; sourceTree = "<group>"; };
|
D060184A22F35E1E00796784 /* ItemListTextWithLabelItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListTextWithLabelItem.swift; sourceTree = "<group>"; };
|
||||||
@ -168,6 +170,7 @@
|
|||||||
D0D3286322F3366500D07EE2 /* ItemListControllerSearch.swift */,
|
D0D3286322F3366500D07EE2 /* ItemListControllerSearch.swift */,
|
||||||
D0D3286122F3366500D07EE2 /* ItemListControllerSegmentedTitleView.swift */,
|
D0D3286122F3366500D07EE2 /* ItemListControllerSegmentedTitleView.swift */,
|
||||||
D0D3289922F345C500D07EE2 /* ItemListItem.swift */,
|
D0D3289922F345C500D07EE2 /* ItemListItem.swift */,
|
||||||
|
09CE5B912322985500743FF4 /* ItemListMaskAccessory.swift */,
|
||||||
D060186022F35F6B00796784 /* ItemListRevealOptionsNode.swift */,
|
D060186022F35F6B00796784 /* ItemListRevealOptionsNode.swift */,
|
||||||
D06018BA22F3663900796784 /* ItemListEditableDeleteControlNode.swift */,
|
D06018BA22F3663900796784 /* ItemListEditableDeleteControlNode.swift */,
|
||||||
D06018B822F3663800796784 /* ItemListEditableReorderControlNode.swift */,
|
D06018B822F3663800796784 /* ItemListEditableReorderControlNode.swift */,
|
||||||
@ -294,6 +297,7 @@
|
|||||||
D060185422F35E1F00796784 /* ItemListTextWithLabelItem.swift in Sources */,
|
D060185422F35E1F00796784 /* ItemListTextWithLabelItem.swift in Sources */,
|
||||||
D0C9BFB222FE327700FAB518 /* ItemListPlaceholderItem.swift in Sources */,
|
D0C9BFB222FE327700FAB518 /* ItemListPlaceholderItem.swift in Sources */,
|
||||||
D0D3286722F3366600D07EE2 /* ItemListController.swift in Sources */,
|
D0D3286722F3366600D07EE2 /* ItemListController.swift in Sources */,
|
||||||
|
09CE5B922322985500743FF4 /* ItemListMaskAccessory.swift in Sources */,
|
||||||
D0D3286822F3366600D07EE2 /* ItemListControllerSearch.swift in Sources */,
|
D0D3286822F3366600D07EE2 /* ItemListControllerSearch.swift in Sources */,
|
||||||
D060185722F35E1F00796784 /* ItemListSwitchItem.swift in Sources */,
|
D060185722F35E1F00796784 /* ItemListSwitchItem.swift in Sources */,
|
||||||
D0D3286622F3366600D07EE2 /* ItemListControllerSegmentedTitleView.swift in Sources */,
|
D0D3286622F3366600D07EE2 /* ItemListControllerSegmentedTitleView.swift in Sources */,
|
||||||
|
@ -283,7 +283,7 @@ open class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShor
|
|||||||
if let segmentedTitleView = strongSelf.segmentedTitleView, segmentedTitleView.segments == sections {
|
if let segmentedTitleView = strongSelf.segmentedTitleView, segmentedTitleView.segments == sections {
|
||||||
segmentedTitleView.index = index
|
segmentedTitleView.index = index
|
||||||
} else {
|
} else {
|
||||||
let segmentedTitleView = ItemListControllerSegmentedTitleView(segments: sections, index: index, color: controllerState.theme.rootController.navigationBar.accentTextColor)
|
let segmentedTitleView = ItemListControllerSegmentedTitleView(theme: controllerState.theme, segments: sections, selectedIndex: index)
|
||||||
strongSelf.segmentedTitleView = segmentedTitleView
|
strongSelf.segmentedTitleView = segmentedTitleView
|
||||||
strongSelf.navigationItem.titleView = strongSelf.segmentedTitleView
|
strongSelf.navigationItem.titleView = strongSelf.segmentedTitleView
|
||||||
segmentedTitleView.indexUpdated = { index in
|
segmentedTitleView.indexUpdated = { index in
|
||||||
@ -406,7 +406,7 @@ open class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShor
|
|||||||
strongSelf.navigationBar?.updatePresentationData(NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: strongSelf.theme), strings: NavigationBarStrings(presentationStrings: strongSelf.strings)))
|
strongSelf.navigationBar?.updatePresentationData(NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: strongSelf.theme), strings: NavigationBarStrings(presentationStrings: strongSelf.strings)))
|
||||||
strongSelf.statusBar.statusBarStyle = strongSelf.theme.rootController.statusBarStyle.style
|
strongSelf.statusBar.statusBarStyle = strongSelf.theme.rootController.statusBarStyle.style
|
||||||
|
|
||||||
strongSelf.segmentedTitleView?.color = controllerState.theme.rootController.navigationBar.accentTextColor
|
strongSelf.segmentedTitleView?.theme = controllerState.theme
|
||||||
|
|
||||||
var items = strongSelf.navigationItem.rightBarButtonItems ?? []
|
var items = strongSelf.navigationItem.rightBarButtonItems ?? []
|
||||||
for i in 0 ..< strongSelf.rightNavigationButtonTitleAndStyle.count {
|
for i in 0 ..< strongSelf.rightNavigationButtonTitleAndStyle.count {
|
||||||
|
@ -162,6 +162,8 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
|||||||
private let navigationBar: NavigationBar
|
private let navigationBar: NavigationBar
|
||||||
|
|
||||||
public let listNode: ListView
|
public let listNode: ListView
|
||||||
|
private let leftOverlayNode: ASDisplayNode
|
||||||
|
private let rightOverlayNode: ASDisplayNode
|
||||||
private var emptyStateItem: ItemListControllerEmptyStateItem?
|
private var emptyStateItem: ItemListControllerEmptyStateItem?
|
||||||
private var emptyStateNode: ItemListControllerEmptyStateItemNode?
|
private var emptyStateNode: ItemListControllerEmptyStateItemNode?
|
||||||
|
|
||||||
@ -204,6 +206,8 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
|||||||
self.updateNavigationOffset = updateNavigationOffset
|
self.updateNavigationOffset = updateNavigationOffset
|
||||||
|
|
||||||
self.listNode = ListView()
|
self.listNode = ListView()
|
||||||
|
self.leftOverlayNode = ASDisplayNode()
|
||||||
|
self.rightOverlayNode = ASDisplayNode()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -351,15 +355,45 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
|||||||
|
|
||||||
var insets = layout.insets(options: [.input])
|
var insets = layout.insets(options: [.input])
|
||||||
insets.top += navigationBarHeight
|
insets.top += navigationBarHeight
|
||||||
|
|
||||||
|
var addedInsets: UIEdgeInsets?
|
||||||
|
if case .tablet = layout.deviceMetrics.type, layout.size.width > 460.0 {
|
||||||
|
let inset = max(20.0, floor((layout.size.width - 674.0) / 2.0))
|
||||||
|
insets.left += inset
|
||||||
|
insets.right += inset
|
||||||
|
addedInsets = UIEdgeInsets(top: 0.0, left: inset, bottom: 0.0, right: inset)
|
||||||
|
|
||||||
|
if self.leftOverlayNode.supernode == nil {
|
||||||
|
self.addSubnode(self.leftOverlayNode)
|
||||||
|
}
|
||||||
|
if self.rightOverlayNode.supernode == nil {
|
||||||
|
self.addSubnode(self.rightOverlayNode)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
insets.left += layout.safeInsets.left
|
insets.left += layout.safeInsets.left
|
||||||
insets.right += layout.safeInsets.right
|
insets.right += layout.safeInsets.right
|
||||||
|
|
||||||
|
if self.leftOverlayNode.supernode != nil {
|
||||||
|
self.leftOverlayNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
if self.rightOverlayNode.supernode != nil {
|
||||||
|
self.rightOverlayNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.listNode.bounds = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
|
self.listNode.bounds = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
|
||||||
self.listNode.position = CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0)
|
self.listNode.position = CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0)
|
||||||
|
|
||||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: insets, duration: duration, curve: listViewCurve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: insets, duration: duration, curve: listViewCurve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
|
||||||
|
self.leftOverlayNode.frame = CGRect(x: 0.0, y: insets.top + 1.0, width: insets.left, height: layout.size.height - insets.top)
|
||||||
|
self.rightOverlayNode.frame = CGRect(x: layout.size.width - insets.right, y: insets.top + 1.0, width: insets.right, height: layout.size.height - insets.top)
|
||||||
|
|
||||||
if let emptyStateNode = self.emptyStateNode {
|
if let emptyStateNode = self.emptyStateNode {
|
||||||
|
var layout = layout
|
||||||
|
if let addedInsets = addedInsets {
|
||||||
|
layout = layout.addedInsets(insets: addedInsets)
|
||||||
|
}
|
||||||
emptyStateNode.updateLayout(layout: layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
emptyStateNode.updateLayout(layout: layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,9 +435,13 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
|||||||
case .plain:
|
case .plain:
|
||||||
self.backgroundColor = transition.theme.list.plainBackgroundColor
|
self.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||||
self.listNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
self.listNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||||
|
self.leftOverlayNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||||
|
self.rightOverlayNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||||
case .blocks:
|
case .blocks:
|
||||||
self.backgroundColor = transition.theme.list.blocksBackgroundColor
|
self.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||||
self.listNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
self.listNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||||
|
self.leftOverlayNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||||
|
self.rightOverlayNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -416,9 +454,13 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
|||||||
case .plain:
|
case .plain:
|
||||||
self.backgroundColor = transition.theme.list.plainBackgroundColor
|
self.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||||
self.listNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
self.listNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||||
|
self.leftOverlayNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||||
|
self.rightOverlayNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||||
case .blocks:
|
case .blocks:
|
||||||
self.backgroundColor = transition.theme.list.blocksBackgroundColor
|
self.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||||
self.listNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
self.listNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||||
|
self.leftOverlayNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||||
|
self.rightOverlayNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -553,10 +595,6 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
|||||||
if itemTag.isEqual(to: ensureVisibleItemTag) {
|
if itemTag.isEqual(to: ensureVisibleItemTag) {
|
||||||
if let itemNode = itemNode as? ListViewItemNode {
|
if let itemNode = itemNode as? ListViewItemNode {
|
||||||
strongSelf.listNode.ensureItemNodeVisible(itemNode)
|
strongSelf.listNode.ensureItemNodeVisible(itemNode)
|
||||||
/*itemNode.setHighlighted(true, at: CGPoint(), animated: false)
|
|
||||||
Queue.mainQueue().after(1.0, {
|
|
||||||
itemNode.setHighlighted(false, at: CGPoint(), animated: true)
|
|
||||||
})*/
|
|
||||||
applied = true
|
applied = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -613,21 +651,13 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
|||||||
|
|
||||||
open func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
open func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
let distanceFromEquilibrium = scrollView.contentOffset.y - scrollView.contentSize.height / 3.0
|
let distanceFromEquilibrium = scrollView.contentOffset.y - scrollView.contentSize.height / 3.0
|
||||||
|
|
||||||
//let transition = 1.0 - min(1.0, max(0.0, abs(distanceFromEquilibrium) / 50.0))
|
|
||||||
|
|
||||||
self.updateNavigationOffset(-distanceFromEquilibrium)
|
self.updateNavigationOffset(-distanceFromEquilibrium)
|
||||||
|
|
||||||
/*if let toolbarNode = toolbarNode {
|
|
||||||
toolbarNode.layer.position = CGPoint(x: toolbarNode.layer.position.x, y: self.bounds.size.height - toolbarNode.bounds.size.height / 2.0 + (1.0 - transition) * toolbarNode.bounds.size.height)
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
open func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
||||||
targetContentOffset.pointee = scrollView.contentOffset
|
targetContentOffset.pointee = scrollView.contentOffset
|
||||||
|
|
||||||
let scrollVelocity = scrollView.panGestureRecognizer.velocity(in: scrollView)
|
let scrollVelocity = scrollView.panGestureRecognizer.velocity(in: scrollView)
|
||||||
|
|
||||||
if abs(scrollVelocity.y) > 200.0 {
|
if abs(scrollVelocity.y) > 200.0 {
|
||||||
self.animateOut()
|
self.animateOut()
|
||||||
}
|
}
|
||||||
|
@ -1,50 +1,49 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import SegmentedControlNode
|
||||||
|
import TelegramPresentationData
|
||||||
|
|
||||||
public final class ItemListControllerSegmentedTitleView: UIView {
|
public final class ItemListControllerSegmentedTitleView: UIView {
|
||||||
|
private let segmentedControlNode: SegmentedControlNode
|
||||||
|
|
||||||
|
public var theme: PresentationTheme {
|
||||||
|
didSet {
|
||||||
|
self.segmentedControlNode.updateTheme(SegmentedControlTheme(theme: self.theme))
|
||||||
|
}
|
||||||
|
}
|
||||||
public var segments: [String] {
|
public var segments: [String] {
|
||||||
didSet {
|
didSet {
|
||||||
if self.segments != oldValue {
|
if self.segments != oldValue {
|
||||||
self.control.removeAllSegments()
|
self.segmentedControlNode.items = self.segments.map { SegmentedControlItem(title: $0) }
|
||||||
var index = 0
|
|
||||||
for segment in self.segments {
|
|
||||||
self.control.insertSegment(withTitle: segment, at: index, animated: false)
|
|
||||||
index += 1
|
|
||||||
}
|
|
||||||
self.setNeedsLayout()
|
self.setNeedsLayout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var index: Int {
|
public var index: Int {
|
||||||
didSet {
|
get {
|
||||||
self.control.selectedSegmentIndex = self.index
|
return self.segmentedControlNode.selectedIndex
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
self.segmentedControlNode.selectedIndex = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let control: UISegmentedControl
|
|
||||||
|
|
||||||
public var indexUpdated: ((Int) -> Void)?
|
public var indexUpdated: ((Int) -> Void)?
|
||||||
|
|
||||||
public var color: UIColor {
|
public init(theme: PresentationTheme, segments: [String], selectedIndex: Int) {
|
||||||
didSet {
|
self.theme = theme
|
||||||
self.control.tintColor = self.color
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(segments: [String], index: Int, color: UIColor) {
|
|
||||||
self.segments = segments
|
self.segments = segments
|
||||||
self.index = index
|
|
||||||
self.color = color
|
|
||||||
|
|
||||||
self.control = UISegmentedControl(items: segments)
|
self.segmentedControlNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: theme), items: segments.map { SegmentedControlItem(title: $0) }, selectedIndex: selectedIndex)
|
||||||
self.control.selectedSegmentIndex = index
|
|
||||||
self.control.tintColor = color
|
|
||||||
|
|
||||||
super.init(frame: CGRect())
|
super.init(frame: CGRect())
|
||||||
|
|
||||||
self.addSubview(self.control)
|
self.segmentedControlNode.selectedIndexChanged = { [weak self] index in
|
||||||
self.control.addTarget(self, action: #selector(indexChanged), for: .valueChanged)
|
self?.indexUpdated?(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.addSubnode(self.segmentedControlNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init?(coder aDecoder: NSCoder) {
|
required public init?(coder aDecoder: NSCoder) {
|
||||||
@ -55,13 +54,7 @@ public final class ItemListControllerSegmentedTitleView: UIView {
|
|||||||
super.layoutSubviews()
|
super.layoutSubviews()
|
||||||
|
|
||||||
let size = self.bounds.size
|
let size = self.bounds.size
|
||||||
|
let controlSize = self.segmentedControlNode.updateLayout(.sizeToFit(maximumWidth: size.width, minimumWidth: 160.0), transition: .immediate)
|
||||||
var controlSize = self.control.sizeThatFits(size)
|
self.segmentedControlNode.frame = CGRect(origin: CGPoint(x: floor((size.width - controlSize.width) / 2.0), y: floor((size.height - controlSize.height) / 2.0)), size: controlSize)
|
||||||
controlSize.width = min(size.width, max(160.0, controlSize.width))
|
|
||||||
self.control.frame = CGRect(origin: CGPoint(x: floor((size.width - controlSize.width) / 2.0), y: floor((size.height - controlSize.height) / 2.0)), size: controlSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func indexChanged() {
|
|
||||||
self.indexUpdated?(self.control.selectedSegmentIndex)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ public protocol ItemListItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public extension ItemListItem {
|
public extension ItemListItem {
|
||||||
|
//let accessoryItem: ListViewAccessoryItem?
|
||||||
|
|
||||||
var isAlwaysPlain: Bool {
|
var isAlwaysPlain: Bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
38
submodules/ItemListUI/Sources/ItemListMaskAccessory.swift
Normal file
38
submodules/ItemListUI/Sources/ItemListMaskAccessory.swift
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
|
||||||
|
final class ItemListMaskAccessoryItem: ListViewAccessoryItem {
|
||||||
|
private let sectionId: Int32
|
||||||
|
|
||||||
|
init(sectionId: Int32) {
|
||||||
|
self.sectionId = sectionId
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEqualToItem(_ other: ListViewAccessoryItem) -> Bool {
|
||||||
|
if case let other as ItemListMaskAccessoryItem = other {
|
||||||
|
return self.sectionId == other.sectionId
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func node(synchronous: Bool) -> ListViewAccessoryItemNode {
|
||||||
|
let node = ItemListMaskAccessoryItemItemNode()
|
||||||
|
node.frame = CGRect(origin: CGPoint(), size: CGSize(width: 38.0, height: 38.0))
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ItemListMaskAccessoryItemItemNode: ListViewAccessoryItemNode {
|
||||||
|
let node: ASDisplayNode
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
self.node = ASDisplayNode()
|
||||||
|
self.node.backgroundColor = .red
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.addSubnode(self.node)
|
||||||
|
}
|
||||||
|
}
|
@ -92,6 +92,7 @@ public class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
private let highlightedBackgroundNode: ASDisplayNode
|
private let highlightedBackgroundNode: ASDisplayNode
|
||||||
|
private let maskNode: ASImageNode
|
||||||
|
|
||||||
private let titleNode: TextNode
|
private let titleNode: TextNode
|
||||||
|
|
||||||
@ -107,7 +108,7 @@ public class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
self.backgroundNode = ASDisplayNode()
|
self.backgroundNode = ASDisplayNode()
|
||||||
self.backgroundNode.isLayerBacked = true
|
self.backgroundNode.isLayerBacked = true
|
||||||
self.backgroundNode.backgroundColor = .white
|
self.backgroundNode.backgroundColor = .white
|
||||||
|
self.maskNode = ASImageNode()
|
||||||
self.topStripeNode = ASDisplayNode()
|
self.topStripeNode = ASDisplayNode()
|
||||||
self.topStripeNode.isLayerBacked = true
|
self.topStripeNode.isLayerBacked = true
|
||||||
|
|
||||||
@ -216,7 +217,9 @@ public class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
if strongSelf.bottomStripeNode.supernode == nil {
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
||||||
}
|
}
|
||||||
|
if strongSelf.maskNode.supernode != nil {
|
||||||
|
strongSelf.maskNode.removeFromSupernode()
|
||||||
|
}
|
||||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
||||||
case .blocks:
|
case .blocks:
|
||||||
if strongSelf.backgroundNode.supernode == nil {
|
if strongSelf.backgroundNode.supernode == nil {
|
||||||
@ -228,11 +231,19 @@ public class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
if strongSelf.bottomStripeNode.supernode == nil {
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||||
}
|
}
|
||||||
|
if strongSelf.maskNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasCorners = params.width > 480
|
||||||
|
var hasTopCorners = false
|
||||||
|
var hasBottomCorners = false
|
||||||
switch neighbors.top {
|
switch neighbors.top {
|
||||||
case .sameSection(false):
|
case .sameSection(false):
|
||||||
strongSelf.topStripeNode.isHidden = true
|
strongSelf.topStripeNode.isHidden = true
|
||||||
default:
|
default:
|
||||||
strongSelf.topStripeNode.isHidden = false
|
hasTopCorners = true
|
||||||
|
strongSelf.topStripeNode.isHidden = hasCorners
|
||||||
}
|
}
|
||||||
let bottomStripeInset: CGFloat
|
let bottomStripeInset: CGFloat
|
||||||
let bottomStripeOffset: CGFloat
|
let bottomStripeOffset: CGFloat
|
||||||
@ -243,8 +254,14 @@ public class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
default:
|
default:
|
||||||
bottomStripeInset = 0.0
|
bottomStripeInset = 0.0
|
||||||
bottomStripeOffset = 0.0
|
bottomStripeOffset = 0.0
|
||||||
|
hasBottomCorners = true
|
||||||
|
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||||
|
|
||||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||||
|
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
|
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
|
||||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,7 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
private let highlightedBackgroundNode: ASDisplayNode
|
private let highlightedBackgroundNode: ASDisplayNode
|
||||||
|
private let maskNode: ASImageNode
|
||||||
|
|
||||||
let iconNode: ASImageNode
|
let iconNode: ASImageNode
|
||||||
let titleNode: TextNode
|
let titleNode: TextNode
|
||||||
@ -137,6 +138,8 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
self.backgroundNode.isLayerBacked = true
|
self.backgroundNode.isLayerBacked = true
|
||||||
self.backgroundNode.backgroundColor = .white
|
self.backgroundNode.backgroundColor = .white
|
||||||
|
|
||||||
|
self.maskNode = ASImageNode()
|
||||||
|
|
||||||
self.topStripeNode = ASDisplayNode()
|
self.topStripeNode = ASDisplayNode()
|
||||||
self.topStripeNode.isLayerBacked = true
|
self.topStripeNode.isLayerBacked = true
|
||||||
|
|
||||||
@ -357,7 +360,9 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
if strongSelf.bottomStripeNode.supernode == nil {
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
||||||
}
|
}
|
||||||
|
if strongSelf.maskNode.supernode != nil {
|
||||||
|
strongSelf.maskNode.removeFromSupernode()
|
||||||
|
}
|
||||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
||||||
case .blocks:
|
case .blocks:
|
||||||
if strongSelf.backgroundNode.supernode == nil {
|
if strongSelf.backgroundNode.supernode == nil {
|
||||||
@ -369,11 +374,19 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
if strongSelf.bottomStripeNode.supernode == nil {
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||||
}
|
}
|
||||||
|
if strongSelf.maskNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasCorners = params.width > 480
|
||||||
|
var hasTopCorners = false
|
||||||
|
var hasBottomCorners = false
|
||||||
switch neighbors.top {
|
switch neighbors.top {
|
||||||
case .sameSection(false):
|
case .sameSection(false):
|
||||||
strongSelf.topStripeNode.isHidden = true
|
strongSelf.topStripeNode.isHidden = true
|
||||||
default:
|
default:
|
||||||
strongSelf.topStripeNode.isHidden = false
|
hasTopCorners = true
|
||||||
|
strongSelf.topStripeNode.isHidden = hasCorners
|
||||||
}
|
}
|
||||||
let bottomStripeInset: CGFloat
|
let bottomStripeInset: CGFloat
|
||||||
switch neighbors.bottom {
|
switch neighbors.bottom {
|
||||||
@ -381,10 +394,15 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
bottomStripeInset = leftInset
|
bottomStripeInset = leftInset
|
||||||
default:
|
default:
|
||||||
bottomStripeInset = 0.0
|
bottomStripeInset = 0.0
|
||||||
|
hasBottomCorners = true
|
||||||
|
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||||
|
|
||||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
|
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||||
|
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
|
||||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +114,7 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
private let highlightedBackgroundNode: ASDisplayNode
|
private let highlightedBackgroundNode: ASDisplayNode
|
||||||
|
private let maskNode: ASImageNode
|
||||||
|
|
||||||
private let titleNode: TextNode
|
private let titleNode: TextNode
|
||||||
private var switchNode: ASDisplayNode & ItemListSwitchNodeImpl
|
private var switchNode: ASDisplayNode & ItemListSwitchNodeImpl
|
||||||
@ -133,6 +134,8 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
self.backgroundNode.isLayerBacked = true
|
self.backgroundNode.isLayerBacked = true
|
||||||
self.backgroundNode.backgroundColor = .white
|
self.backgroundNode.backgroundColor = .white
|
||||||
|
|
||||||
|
self.maskNode = ASImageNode()
|
||||||
|
|
||||||
self.topStripeNode = ASDisplayNode()
|
self.topStripeNode = ASDisplayNode()
|
||||||
self.topStripeNode.isLayerBacked = true
|
self.topStripeNode.isLayerBacked = true
|
||||||
|
|
||||||
@ -299,7 +302,9 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
if strongSelf.bottomStripeNode.supernode == nil {
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
||||||
}
|
}
|
||||||
|
if strongSelf.maskNode.supernode != nil {
|
||||||
|
strongSelf.maskNode.removeFromSupernode()
|
||||||
|
}
|
||||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
||||||
case .blocks:
|
case .blocks:
|
||||||
if strongSelf.backgroundNode.supernode == nil {
|
if strongSelf.backgroundNode.supernode == nil {
|
||||||
@ -311,11 +316,19 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
if strongSelf.bottomStripeNode.supernode == nil {
|
if strongSelf.bottomStripeNode.supernode == nil {
|
||||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||||
}
|
}
|
||||||
|
if strongSelf.maskNode.supernode == nil {
|
||||||
|
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasCorners = params.width > 480
|
||||||
|
var hasTopCorners = false
|
||||||
|
var hasBottomCorners = false
|
||||||
switch neighbors.top {
|
switch neighbors.top {
|
||||||
case .sameSection(false):
|
case .sameSection(false):
|
||||||
strongSelf.topStripeNode.isHidden = true
|
strongSelf.topStripeNode.isHidden = true
|
||||||
default:
|
default:
|
||||||
strongSelf.topStripeNode.isHidden = false
|
hasTopCorners = true
|
||||||
|
strongSelf.topStripeNode.isHidden = hasCorners
|
||||||
}
|
}
|
||||||
let bottomStripeInset: CGFloat
|
let bottomStripeInset: CGFloat
|
||||||
switch neighbors.bottom {
|
switch neighbors.bottom {
|
||||||
@ -323,9 +336,14 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
bottomStripeInset = 16.0 + params.leftInset
|
bottomStripeInset = 16.0 + params.leftInset
|
||||||
default:
|
default:
|
||||||
bottomStripeInset = 0.0
|
bottomStripeInset = 0.0
|
||||||
|
hasBottomCorners = true
|
||||||
|
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||||
|
|
||||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||||
|
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))
|
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))
|
||||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ public final class ItemListTextEmptyStateItemNode: ItemListControllerEmptyStateI
|
|||||||
self.validLayout = (layout, navigationBarHeight)
|
self.validLayout = (layout, navigationBarHeight)
|
||||||
var insets = layout.insets(options: [.statusBar])
|
var insets = layout.insets(options: [.statusBar])
|
||||||
insets.top += navigationBarHeight
|
insets.top += navigationBarHeight
|
||||||
let textSize = self.textNode.measure(CGSize(width: layout.size.width - 40.0 - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
let textSize = self.textNode.measure(CGSize(width: layout.size.width - 40.0 - layout.safeInsets.left - layout.safeInsets.right - layout.intrinsicInsets.left - layout.intrinsicInsets.right, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||||
self.textNode.frame = CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - textSize.width) / 2.0), y: insets.top + floor((layout.size.height - insets.top - insets.bottom - textSize.height) / 2.0)), size: textSize)
|
self.textNode.frame = CGRect(origin: CGPoint(x: layout.safeInsets.left + layout.intrinsicInsets.left + floor((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - layout.intrinsicInsets.left - layout.intrinsicInsets.right - textSize.width) / 2.0), y: insets.top + floor((layout.size.height - insets.top - insets.bottom - textSize.height) / 2.0)), size: textSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
@implementation OggOpusReader
|
@implementation OggOpusReader
|
||||||
|
|
||||||
- (instancetype _Nullable)init:(NSString *)path {
|
- (instancetype _Nullable)initWithPath:(NSString *)path {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
int error = OPUS_OK;
|
int error = OPUS_OK;
|
||||||
|
22
submodules/SegmentedControlNode/Info.plist
Normal file
22
submodules/SegmentedControlNode/Info.plist
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@ -0,0 +1,563 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 50;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
09CE5B9023225AC200743FF4 /* TelegramPresentationData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09CE5B8F23225AC200743FF4 /* TelegramPresentationData.framework */; };
|
||||||
|
D060188A22F3604000796784 /* SegmentedControlNode.h in Headers */ = {isa = PBXBuildFile; fileRef = D060188822F3604000796784 /* SegmentedControlNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
|
D060189522F3615800796784 /* SegmentedControlNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060189422F3615800796784 /* SegmentedControlNode.swift */; };
|
||||||
|
D060189822F3616300796784 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D060189722F3616300796784 /* Foundation.framework */; };
|
||||||
|
D060189A22F3616600796784 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D060189922F3616600796784 /* UIKit.framework */; };
|
||||||
|
D060189C22F3616A00796784 /* AsyncDisplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D060189B22F3616A00796784 /* AsyncDisplayKit.framework */; };
|
||||||
|
D060189E22F3616E00796784 /* LegacyComponents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D060189D22F3616E00796784 /* LegacyComponents.framework */; };
|
||||||
|
D0A0B53922F370DF00628AF3 /* Display.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0A0B53822F370DF00628AF3 /* Display.framework */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
09CE5B8F23225AC200743FF4 /* TelegramPresentationData.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TelegramPresentationData.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D060188522F3604000796784 /* SegmentedControlNode.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SegmentedControlNode.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D060188822F3604000796784 /* SegmentedControlNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SegmentedControlNode.h; sourceTree = "<group>"; };
|
||||||
|
D060188922F3604000796784 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
D060189422F3615800796784 /* SegmentedControlNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegmentedControlNode.swift; sourceTree = "<group>"; };
|
||||||
|
D060189722F3616300796784 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||||
|
D060189922F3616600796784 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||||
|
D060189B22F3616A00796784 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D060189D22F3616E00796784 /* LegacyComponents.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LegacyComponents.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D0A0B53822F370DF00628AF3 /* Display.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Display.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
D060188222F3604000796784 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
09CE5B9023225AC200743FF4 /* TelegramPresentationData.framework in Frameworks */,
|
||||||
|
D0A0B53922F370DF00628AF3 /* Display.framework in Frameworks */,
|
||||||
|
D060189E22F3616E00796784 /* LegacyComponents.framework in Frameworks */,
|
||||||
|
D060189C22F3616A00796784 /* AsyncDisplayKit.framework in Frameworks */,
|
||||||
|
D060189A22F3616600796784 /* UIKit.framework in Frameworks */,
|
||||||
|
D060189822F3616300796784 /* Foundation.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
D060187B22F3604000796784 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D060188922F3604000796784 /* Info.plist */,
|
||||||
|
D060188722F3604000796784 /* Sources */,
|
||||||
|
D060188622F3604000796784 /* Products */,
|
||||||
|
D060189622F3616300796784 /* Frameworks */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
D060188622F3604000796784 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D060188522F3604000796784 /* SegmentedControlNode.framework */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
D060188722F3604000796784 /* Sources */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D060189422F3615800796784 /* SegmentedControlNode.swift */,
|
||||||
|
D060188822F3604000796784 /* SegmentedControlNode.h */,
|
||||||
|
);
|
||||||
|
path = Sources;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
D060189622F3616300796784 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
09CE5B8F23225AC200743FF4 /* TelegramPresentationData.framework */,
|
||||||
|
D0A0B53822F370DF00628AF3 /* Display.framework */,
|
||||||
|
D060189D22F3616E00796784 /* LegacyComponents.framework */,
|
||||||
|
D060189B22F3616A00796784 /* AsyncDisplayKit.framework */,
|
||||||
|
D060189922F3616600796784 /* UIKit.framework */,
|
||||||
|
D060189722F3616300796784 /* Foundation.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXHeadersBuildPhase section */
|
||||||
|
D060188022F3604000796784 /* Headers */ = {
|
||||||
|
isa = PBXHeadersBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
D060188A22F3604000796784 /* SegmentedControlNode.h in Headers */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXHeadersBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
D060188422F3604000796784 /* SegmentedControlNode */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = D060188D22F3604000796784 /* Build configuration list for PBXNativeTarget "SegmentedControlNode" */;
|
||||||
|
buildPhases = (
|
||||||
|
D060188022F3604000796784 /* Headers */,
|
||||||
|
D060188122F3604000796784 /* Sources */,
|
||||||
|
D060188222F3604000796784 /* Frameworks */,
|
||||||
|
D060188322F3604000796784 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = SegmentedControlNode;
|
||||||
|
productName = SegmentedControlNode;
|
||||||
|
productReference = D060188522F3604000796784 /* SegmentedControlNode.framework */;
|
||||||
|
productType = "com.apple.product-type.framework";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
D060187C22F3604000796784 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
DefaultBuildSystemTypeForWorkspace = Latest;
|
||||||
|
LastUpgradeCheck = 1010;
|
||||||
|
ORGANIZATIONNAME = "Telegram Messenger LLP";
|
||||||
|
TargetAttributes = {
|
||||||
|
D060188422F3604000796784 = {
|
||||||
|
CreatedOnToolsVersion = 10.1;
|
||||||
|
LastSwiftMigration = 1010;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = D060187F22F3604000796784 /* Build configuration list for PBXProject "SegmentedControlNode_Xcode" */;
|
||||||
|
compatibilityVersion = "Xcode 9.3";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
);
|
||||||
|
mainGroup = D060187B22F3604000796784;
|
||||||
|
productRefGroup = D060188622F3604000796784 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
D060188422F3604000796784 /* SegmentedControlNode */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
D060188322F3604000796784 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
D060188122F3604000796784 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
D060189522F3615800796784 /* SegmentedControlNode.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
D060188B22F3604000796784 /* DebugAppStoreLLC */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
VERSION_INFO_PREFIX = "";
|
||||||
|
};
|
||||||
|
name = DebugAppStoreLLC;
|
||||||
|
};
|
||||||
|
D060188C22F3604000796784 /* ReleaseAppStoreLLC */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
VERSION_INFO_PREFIX = "";
|
||||||
|
};
|
||||||
|
name = ReleaseAppStoreLLC;
|
||||||
|
};
|
||||||
|
D060188E22F3604000796784 /* DebugAppStoreLLC */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEFINES_MODULE = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
|
INFOPLIST_FILE = Info.plist;
|
||||||
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
);
|
||||||
|
MACH_O_TYPE = staticlib;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.SegmentedControlNode;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = DebugAppStoreLLC;
|
||||||
|
};
|
||||||
|
D060188F22F3604000796784 /* ReleaseAppStoreLLC */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEFINES_MODULE = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
|
INFOPLIST_FILE = Info.plist;
|
||||||
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
);
|
||||||
|
MACH_O_TYPE = staticlib;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.SegmentedControlNode;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = ReleaseAppStoreLLC;
|
||||||
|
};
|
||||||
|
D060189022F360BF00796784 /* DebugHockeyapp */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
VERSION_INFO_PREFIX = "";
|
||||||
|
};
|
||||||
|
name = DebugHockeyapp;
|
||||||
|
};
|
||||||
|
D060189122F360BF00796784 /* DebugHockeyapp */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEFINES_MODULE = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
|
INFOPLIST_FILE = Info.plist;
|
||||||
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
);
|
||||||
|
MACH_O_TYPE = staticlib;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.SegmentedControlNode;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = DebugHockeyapp;
|
||||||
|
};
|
||||||
|
D060189222F360CA00796784 /* ReleaseHockeyappInternal */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
VERSION_INFO_PREFIX = "";
|
||||||
|
};
|
||||||
|
name = ReleaseHockeyappInternal;
|
||||||
|
};
|
||||||
|
D060189322F360CA00796784 /* ReleaseHockeyappInternal */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEFINES_MODULE = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
|
INFOPLIST_FILE = Info.plist;
|
||||||
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
);
|
||||||
|
MACH_O_TYPE = staticlib;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.SegmentedControlNode;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = ReleaseHockeyappInternal;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
D060187F22F3604000796784 /* Build configuration list for PBXProject "SegmentedControlNode_Xcode" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
D060188B22F3604000796784 /* DebugAppStoreLLC */,
|
||||||
|
D060189022F360BF00796784 /* DebugHockeyapp */,
|
||||||
|
D060188C22F3604000796784 /* ReleaseAppStoreLLC */,
|
||||||
|
D060189222F360CA00796784 /* ReleaseHockeyappInternal */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = ReleaseAppStoreLLC;
|
||||||
|
};
|
||||||
|
D060188D22F3604000796784 /* Build configuration list for PBXNativeTarget "SegmentedControlNode" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
D060188E22F3604000796784 /* DebugAppStoreLLC */,
|
||||||
|
D060189122F360BF00796784 /* DebugHockeyapp */,
|
||||||
|
D060188F22F3604000796784 /* ReleaseAppStoreLLC */,
|
||||||
|
D060189322F360CA00796784 /* ReleaseHockeyappInternal */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = ReleaseAppStoreLLC;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = D060187C22F3604000796784 /* Project object */;
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@ -0,0 +1,11 @@
|
|||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
//! Project version number for SegmentedControlNode.
|
||||||
|
FOUNDATION_EXPORT double SegmentedControlNodeVersionNumber;
|
||||||
|
|
||||||
|
//! Project version string for SegmentedControlNode.
|
||||||
|
FOUNDATION_EXPORT const unsigned char SegmentedControlNodeVersionString[];
|
||||||
|
|
||||||
|
// In this header, you should import all the public headers of your framework using statements like #import <SegmentedControlNode/PublicHeader.h>
|
||||||
|
|
||||||
|
|
@ -0,0 +1,381 @@
|
|||||||
|
import Foundation
|
||||||
|
import Display
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import TelegramPresentationData
|
||||||
|
|
||||||
|
private let textFont = Font.regular(13.0)
|
||||||
|
private let selectedTextFont = Font.bold(13.0)
|
||||||
|
|
||||||
|
public enum SegmentedControlLayout {
|
||||||
|
case stretchToFill(width: CGFloat)
|
||||||
|
case sizeToFit(maximumWidth: CGFloat, minimumWidth: CGFloat)
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class SegmentedControlTheme: Equatable {
|
||||||
|
public let backgroundColor: UIColor
|
||||||
|
public let foregroundColor: UIColor
|
||||||
|
public let shadowColor: UIColor
|
||||||
|
public let textColor: UIColor
|
||||||
|
public let dividerColor: UIColor
|
||||||
|
|
||||||
|
public init(backgroundColor: UIColor, foregroundColor: UIColor, shadowColor: UIColor, textColor: UIColor, dividerColor: UIColor) {
|
||||||
|
self.backgroundColor = backgroundColor
|
||||||
|
self.foregroundColor = foregroundColor
|
||||||
|
self.shadowColor = shadowColor
|
||||||
|
self.textColor = textColor
|
||||||
|
self.dividerColor = dividerColor
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: SegmentedControlTheme, rhs: SegmentedControlTheme) -> Bool {
|
||||||
|
if lhs.backgroundColor != rhs.backgroundColor {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.foregroundColor != rhs.foregroundColor {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.shadowColor != rhs.shadowColor {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.textColor != rhs.textColor {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.dividerColor != rhs.dividerColor {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension SegmentedControlTheme {
|
||||||
|
convenience init(theme: PresentationTheme) {
|
||||||
|
self.init(backgroundColor: theme.rootController.navigationSearchBar.inputFillColor, foregroundColor: theme.rootController.navigationBar.backgroundColor, shadowColor: .black, textColor: theme.rootController.navigationBar.primaryTextColor, dividerColor: theme.list.freeInputField.strokeColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func generateSelectionImage(theme: SegmentedControlTheme) -> UIImage? {
|
||||||
|
return generateImage(CGSize(width: 20.0, height: 20.0), rotatedContext: { size, context in
|
||||||
|
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||||
|
context.clear(bounds)
|
||||||
|
|
||||||
|
if theme.shadowColor != .clear {
|
||||||
|
context.setShadow(offset: CGSize(width: 0.0, height: -3.0), blur: 6.0, color: theme.shadowColor.withAlphaComponent(0.12).cgColor)
|
||||||
|
}
|
||||||
|
context.setFillColor(theme.foregroundColor.cgColor)
|
||||||
|
context.fillEllipse(in: CGRect(x: 2.0, y: 2.0, width: 16.0, height: 16.0))
|
||||||
|
})?.stretchableImage(withLeftCapWidth: 10, topCapHeight: 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct SegmentedControlItem: Equatable {
|
||||||
|
public let title: String
|
||||||
|
|
||||||
|
public init(title: String) {
|
||||||
|
self.title = title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class SegmentedControlNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||||
|
private var theme: SegmentedControlTheme
|
||||||
|
private var _items: [SegmentedControlItem]
|
||||||
|
private var _selectedIndex: Int = 0
|
||||||
|
|
||||||
|
private var validLayout: SegmentedControlLayout?
|
||||||
|
|
||||||
|
private let selectionNode: ASImageNode
|
||||||
|
private var itemNodes: [HighlightTrackingButtonNode]
|
||||||
|
private var dividerNodes: [ASDisplayNode]
|
||||||
|
|
||||||
|
private var gestureRecognizer: UIPanGestureRecognizer?
|
||||||
|
private var gestureSelectedIndex: Int?
|
||||||
|
|
||||||
|
public var items: [SegmentedControlItem] {
|
||||||
|
get {
|
||||||
|
return self._items
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
let previousItems = self._items
|
||||||
|
self._items = newValue
|
||||||
|
guard previousItems != newValue else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.itemNodes.forEach { $0.removeFromSupernode() }
|
||||||
|
self.itemNodes = self._items.map { item in
|
||||||
|
let itemNode = HighlightTrackingButtonNode()
|
||||||
|
itemNode.setTitle(item.title, with: textFont, with: self.theme.textColor, for: .normal)
|
||||||
|
itemNode.setTitle(item.title, with: selectedTextFont, with: self.theme.textColor, for: .selected)
|
||||||
|
itemNode.setTitle(item.title, with: selectedTextFont, with: self.theme.textColor, for: [.selected, .highlighted])
|
||||||
|
return itemNode
|
||||||
|
}
|
||||||
|
self.setupButtons()
|
||||||
|
self.itemNodes.forEach(self.addSubnode(_:))
|
||||||
|
|
||||||
|
let dividersCount = self._items.count > 2 ? self._items.count - 1 : 0
|
||||||
|
if self.dividerNodes.count != dividersCount {
|
||||||
|
self.dividerNodes.forEach { $0.removeFromSupernode() }
|
||||||
|
self.dividerNodes = (0 ..< dividersCount).map { _ in ASDisplayNode() }
|
||||||
|
}
|
||||||
|
|
||||||
|
if let layout = self.validLayout {
|
||||||
|
let _ = self.updateLayout(layout, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var selectedIndex: Int {
|
||||||
|
get {
|
||||||
|
return self._selectedIndex
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
guard newValue != self._selectedIndex else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self._selectedIndex = newValue
|
||||||
|
if let layout = self.validLayout {
|
||||||
|
let _ = self.updateLayout(layout, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var selectedIndexChanged: (Int) -> Void = { _ in }
|
||||||
|
|
||||||
|
public init(theme: SegmentedControlTheme, items: [SegmentedControlItem], selectedIndex: Int) {
|
||||||
|
self.theme = theme
|
||||||
|
self._items = items
|
||||||
|
self._selectedIndex = selectedIndex
|
||||||
|
|
||||||
|
self.selectionNode = ASImageNode()
|
||||||
|
self.selectionNode.displaysAsynchronously = false
|
||||||
|
self.selectionNode.displayWithoutProcessing = true
|
||||||
|
|
||||||
|
self.itemNodes = items.map { item in
|
||||||
|
let itemNode = HighlightTrackingButtonNode()
|
||||||
|
itemNode.setTitle(item.title, with: textFont, with: theme.textColor, for: .normal)
|
||||||
|
itemNode.setTitle(item.title, with: selectedTextFont, with: theme.textColor, for: .selected)
|
||||||
|
itemNode.setTitle(item.title, with: selectedTextFont, with: theme.textColor, for: [.selected, .highlighted])
|
||||||
|
return itemNode
|
||||||
|
}
|
||||||
|
|
||||||
|
let dividersCount = items.count > 2 ? items.count - 1 : 0
|
||||||
|
self.dividerNodes = (0 ..< dividersCount).map { _ in
|
||||||
|
let node = ASDisplayNode()
|
||||||
|
node.backgroundColor = theme.dividerColor
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.clipsToBounds = true
|
||||||
|
self.cornerRadius = 9.0
|
||||||
|
|
||||||
|
self.addSubnode(self.selectionNode)
|
||||||
|
self.itemNodes.forEach(self.addSubnode(_:))
|
||||||
|
self.setupButtons()
|
||||||
|
self.dividerNodes.forEach(self.addSubnode(_:))
|
||||||
|
|
||||||
|
self.backgroundColor = self.theme.backgroundColor
|
||||||
|
self.selectionNode.image = generateSelectionImage(theme: self.theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func didLoad() {
|
||||||
|
super.didLoad()
|
||||||
|
|
||||||
|
self.view.disablesInteractiveTransitionGestureRecognizer = true
|
||||||
|
|
||||||
|
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
||||||
|
gestureRecognizer.delegate = self
|
||||||
|
self.view.addGestureRecognizer(gestureRecognizer)
|
||||||
|
self.gestureRecognizer = gestureRecognizer
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupButtons() {
|
||||||
|
for i in 0 ..< self.itemNodes.count {
|
||||||
|
let itemNode = self.itemNodes[i]
|
||||||
|
itemNode.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside)
|
||||||
|
itemNode.highligthedChanged = { [weak self, weak itemNode] highlighted in
|
||||||
|
if let strongSelf = self, let itemNode = itemNode {
|
||||||
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.25, curve: .easeInOut)
|
||||||
|
if strongSelf.selectedIndex == i {
|
||||||
|
if let gestureRecognizer = strongSelf.gestureRecognizer, case .began = gestureRecognizer.state {
|
||||||
|
} else {
|
||||||
|
strongSelf.updateButtonsHighlights(highlightedIndex: highlighted ? i : nil, gestureSelectedIndex: strongSelf.gestureSelectedIndex)
|
||||||
|
}
|
||||||
|
} else if highlighted {
|
||||||
|
transition.updateAlpha(node: itemNode, alpha: 0.4)
|
||||||
|
}
|
||||||
|
if !highlighted {
|
||||||
|
transition.updateAlpha(node: itemNode, alpha: 1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateButtonsHighlights(highlightedIndex: Int?, gestureSelectedIndex: Int?) {
|
||||||
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.25, curve: .easeInOut)
|
||||||
|
if highlightedIndex == nil && gestureSelectedIndex == nil {
|
||||||
|
transition.updateTransformScale(node: self.selectionNode, scale: 1.0)
|
||||||
|
} else {
|
||||||
|
transition.updateTransformScale(node: self.selectionNode, scale: 0.92)
|
||||||
|
}
|
||||||
|
for i in 0 ..< self.itemNodes.count {
|
||||||
|
let itemNode = self.itemNodes[i]
|
||||||
|
if i == highlightedIndex || i == gestureSelectedIndex {
|
||||||
|
transition.updateTransformScale(node: itemNode, scale: 0.92)
|
||||||
|
} else {
|
||||||
|
transition.updateTransformScale(node: itemNode, scale: 1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateButtonsHighlights() {
|
||||||
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.25, curve: .easeInOut)
|
||||||
|
if let gestureSelectedIndex = self.gestureSelectedIndex {
|
||||||
|
for i in 0 ..< self.itemNodes.count {
|
||||||
|
let itemNode = self.itemNodes[i]
|
||||||
|
transition.updateTransformScale(node: itemNode, scale: i == gestureSelectedIndex ? 0.92 : 1.0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for itemNode in self.itemNodes {
|
||||||
|
transition.updateTransformScale(node: itemNode, scale: 1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateTheme(_ theme: SegmentedControlTheme) {
|
||||||
|
guard theme != self.theme else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.theme = theme
|
||||||
|
|
||||||
|
self.backgroundColor = self.theme.backgroundColor
|
||||||
|
self.selectionNode.image = generateSelectionImage(theme: self.theme)
|
||||||
|
|
||||||
|
for itemNode in self.itemNodes {
|
||||||
|
if let title = itemNode.attributedTitle(for: .normal)?.string {
|
||||||
|
itemNode.setTitle(title, with: textFont, with: self.theme.textColor, for: .normal)
|
||||||
|
itemNode.setTitle(title, with: selectedTextFont, with: self.theme.textColor, for: .selected)
|
||||||
|
itemNode.setTitle(title, with: selectedTextFont, with: self.theme.textColor, for: [.selected, .highlighted])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for dividerNode in self.dividerNodes {
|
||||||
|
dividerNode.backgroundColor = theme.dividerColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func updateLayout(_ layout: SegmentedControlLayout, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||||
|
self.validLayout = layout
|
||||||
|
|
||||||
|
let calculatedWidth: CGFloat = 0.0
|
||||||
|
|
||||||
|
let width: CGFloat
|
||||||
|
switch layout {
|
||||||
|
case let .stretchToFill(targetWidth):
|
||||||
|
width = targetWidth
|
||||||
|
case let .sizeToFit(maximumWidth, minimumWidth):
|
||||||
|
width = max(minimumWidth, min(maximumWidth, calculatedWidth))
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = CGSize(width: width, height: 32.0)
|
||||||
|
if !self.itemNodes.isEmpty {
|
||||||
|
let itemSize = CGSize(width: floorToScreenPixels(size.width / CGFloat(self.itemNodes.count)), height: size.height)
|
||||||
|
|
||||||
|
let selectedIndex: Int
|
||||||
|
if let gestureSelectedIndex = self.gestureSelectedIndex {
|
||||||
|
selectedIndex = gestureSelectedIndex
|
||||||
|
} else {
|
||||||
|
selectedIndex = self.selectedIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
transition.updateBounds(node: self.selectionNode, bounds: CGRect(origin: CGPoint(), size: itemSize))
|
||||||
|
transition.updatePosition(node: self.selectionNode, position: CGPoint(x: itemSize.width / 2.0 + itemSize.width * CGFloat(selectedIndex), y: size.height / 2.0))
|
||||||
|
|
||||||
|
for i in 0 ..< self.itemNodes.count {
|
||||||
|
let itemNode = self.itemNodes[i]
|
||||||
|
transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: itemSize.width * CGFloat(i), y: (size.height - itemSize.height) / 2.0), size: itemSize))
|
||||||
|
|
||||||
|
let isSelected = selectedIndex == i
|
||||||
|
if itemNode.isSelected != isSelected {
|
||||||
|
if case .animated = transition {
|
||||||
|
UIView.transition(with: itemNode.view, duration: 0.2, options: .transitionCrossDissolve, animations: {
|
||||||
|
itemNode.isSelected = isSelected
|
||||||
|
}, completion: nil)
|
||||||
|
} else {
|
||||||
|
itemNode.isSelected = isSelected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.dividerNodes.isEmpty {
|
||||||
|
let dividerSize = CGSize(width: 1.0, height: 16.0)
|
||||||
|
let delta: CGFloat = size.width / CGFloat(self.dividerNodes.count + 1)
|
||||||
|
for i in 0 ..< self.dividerNodes.count {
|
||||||
|
let dividerNode = self.dividerNodes[i]
|
||||||
|
transition.updateFrame(node: dividerNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels(delta * CGFloat(i + 1) - dividerSize.width / 2.0), y: (size.height - dividerSize.height) / 2.0), size: dividerSize))
|
||||||
|
|
||||||
|
let dividerAlpha: CGFloat
|
||||||
|
if (self.selectedIndex - 1 ... self.selectedIndex).contains(i) {
|
||||||
|
dividerAlpha = 0.0
|
||||||
|
} else {
|
||||||
|
dividerAlpha = 1.0
|
||||||
|
}
|
||||||
|
transition.updateAlpha(node: dividerNode, alpha: dividerAlpha)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func buttonPressed(_ button: HighlightTrackingButtonNode) {
|
||||||
|
guard let index = self.itemNodes.firstIndex(of: button) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self._selectedIndex = index
|
||||||
|
self.selectedIndexChanged(index)
|
||||||
|
if let layout = self.validLayout {
|
||||||
|
let _ = self.updateLayout(layout, transition: .animated(duration: 0.2, curve: .slide))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
|
let location = gestureRecognizer.location(in: self.view)
|
||||||
|
return self.selectionNode.frame.contains(location)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func panGesture(_ recognizer: UIPanGestureRecognizer) {
|
||||||
|
let location = recognizer.location(in: self.view)
|
||||||
|
switch recognizer.state {
|
||||||
|
case .changed:
|
||||||
|
if !self.selectionNode.frame.contains(location) {
|
||||||
|
let point = CGPoint(x: max(0.0, min(self.bounds.width, location.x)), y: 1.0)
|
||||||
|
for i in 0 ..< self.itemNodes.count {
|
||||||
|
let itemNode = self.itemNodes[i]
|
||||||
|
if itemNode.frame.contains(point) {
|
||||||
|
if i != self.gestureSelectedIndex {
|
||||||
|
self.gestureSelectedIndex = i
|
||||||
|
self.updateButtonsHighlights(highlightedIndex: nil, gestureSelectedIndex: i)
|
||||||
|
if let layout = self.validLayout {
|
||||||
|
let _ = self.updateLayout(layout, transition: .animated(duration: 0.35, curve: .slide))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .ended:
|
||||||
|
if let gestureSelectedIndex = self.gestureSelectedIndex {
|
||||||
|
if gestureSelectedIndex != self.selectedIndex {
|
||||||
|
self._selectedIndex = gestureSelectedIndex
|
||||||
|
self.selectedIndexChanged(self._selectedIndex)
|
||||||
|
}
|
||||||
|
self.gestureSelectedIndex = nil
|
||||||
|
self.updateButtonsHighlights(highlightedIndex: nil, gestureSelectedIndex: nil)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
091EABA5231DAC7500A0EC14 /* ThemeNameGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091EABA4231DAC7500A0EC14 /* ThemeNameGenerator.swift */; };
|
091EABA5231DAC7500A0EC14 /* ThemeNameGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091EABA4231DAC7500A0EC14 /* ThemeNameGenerator.swift */; };
|
||||||
09B4A9B823102B7A005C2E08 /* EditThemeController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B4A9B723102B7A005C2E08 /* EditThemeController.swift */; };
|
09B4A9B823102B7A005C2E08 /* EditThemeController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B4A9B723102B7A005C2E08 /* EditThemeController.swift */; };
|
||||||
|
09CE5B8E2322154400743FF4 /* SegmentedControlNode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09CE5B8D2322154400743FF4 /* SegmentedControlNode.framework */; };
|
||||||
D03E465223075D930049C28B /* SettingsUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E465023075D930049C28B /* SettingsUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D03E465223075D930049C28B /* SettingsUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E465023075D930049C28B /* SettingsUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
D03E466823075E660049C28B /* TabBarAccountSwitchControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E465C23075E630049C28B /* TabBarAccountSwitchControllerNode.swift */; };
|
D03E466823075E660049C28B /* TabBarAccountSwitchControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E465C23075E630049C28B /* TabBarAccountSwitchControllerNode.swift */; };
|
||||||
D03E466923075E660049C28B /* LogoutOptionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E465D23075E630049C28B /* LogoutOptionsController.swift */; };
|
D03E466923075E660049C28B /* LogoutOptionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E465D23075E630049C28B /* LogoutOptionsController.swift */; };
|
||||||
@ -194,6 +195,7 @@
|
|||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
091EABA4231DAC7500A0EC14 /* ThemeNameGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeNameGenerator.swift; sourceTree = "<group>"; };
|
091EABA4231DAC7500A0EC14 /* ThemeNameGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeNameGenerator.swift; sourceTree = "<group>"; };
|
||||||
09B4A9B723102B7A005C2E08 /* EditThemeController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditThemeController.swift; sourceTree = "<group>"; };
|
09B4A9B723102B7A005C2E08 /* EditThemeController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditThemeController.swift; sourceTree = "<group>"; };
|
||||||
|
09CE5B8D2322154400743FF4 /* SegmentedControlNode.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SegmentedControlNode.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D03E464D23075D930049C28B /* SettingsUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SettingsUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
D03E464D23075D930049C28B /* SettingsUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SettingsUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D03E465023075D930049C28B /* SettingsUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SettingsUI.h; sourceTree = "<group>"; };
|
D03E465023075D930049C28B /* SettingsUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SettingsUI.h; sourceTree = "<group>"; };
|
||||||
D03E465123075D930049C28B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
D03E465123075D930049C28B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
@ -383,6 +385,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
09CE5B8E2322154400743FF4 /* SegmentedControlNode.framework in Frameworks */,
|
||||||
D03E493A2308678D0049C28B /* InstantPageCache.framework in Frameworks */,
|
D03E493A2308678D0049C28B /* InstantPageCache.framework in Frameworks */,
|
||||||
D03E490E2308661A0049C28B /* GridMessageSelectionNode.framework in Frameworks */,
|
D03E490E2308661A0049C28B /* GridMessageSelectionNode.framework in Frameworks */,
|
||||||
D03E48E22308649C0049C28B /* CounterContollerTitleView.framework in Frameworks */,
|
D03E48E22308649C0049C28B /* CounterContollerTitleView.framework in Frameworks */,
|
||||||
@ -687,6 +690,7 @@
|
|||||||
D03E4732230761E10049C28B /* Frameworks */ = {
|
D03E4732230761E10049C28B /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
09CE5B8D2322154400743FF4 /* SegmentedControlNode.framework */,
|
||||||
D03E49392308678D0049C28B /* InstantPageCache.framework */,
|
D03E49392308678D0049C28B /* InstantPageCache.framework */,
|
||||||
D03E490D2308661A0049C28B /* GridMessageSelectionNode.framework */,
|
D03E490D2308661A0049C28B /* GridMessageSelectionNode.framework */,
|
||||||
D03E48E12308649C0049C28B /* CounterContollerTitleView.framework */,
|
D03E48E12308649C0049C28B /* CounterContollerTitleView.framework */,
|
||||||
|
@ -84,15 +84,15 @@ final class RecentSessionsEmptyStateItemNode: ItemListControllerEmptyStateItemNo
|
|||||||
let imageSize = self.imageNode.image?.size ?? CGSize()
|
let imageSize = self.imageNode.image?.size ?? CGSize()
|
||||||
let imageHeight = layout.size.width < layout.size.height ? imageSize.height + imageSpacing : 0.0
|
let imageHeight = layout.size.width < layout.size.height ? imageSize.height + imageSpacing : 0.0
|
||||||
|
|
||||||
let titleSize = self.titleNode.measure(CGSize(width: layout.size.width - 50.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
let titleSize = self.titleNode.measure(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - layout.intrinsicInsets.left - layout.intrinsicInsets.right - 50.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||||
let textSize = self.textNode.measure(CGSize(width: layout.size.width - 50.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
let textSize = self.textNode.measure(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - layout.intrinsicInsets.left - layout.intrinsicInsets.right - 50.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||||
|
|
||||||
let totalHeight = imageHeight + titleSize.height + textSpacing + textSize.height
|
let totalHeight = imageHeight + titleSize.height + textSpacing + textSize.height
|
||||||
let topOffset = insets.top + floor((layout.size.height - insets.top - insets.bottom - totalHeight) / 2.0)
|
let topOffset = insets.top + floor((layout.size.height - insets.top - insets.bottom - totalHeight) / 2.0)
|
||||||
|
|
||||||
transition.updateAlpha(node: self.imageNode, alpha: imageHeight > 0.0 ? 1.0 : 0.0)
|
transition.updateAlpha(node: self.imageNode, alpha: imageHeight > 0.0 ? 1.0 : 0.0)
|
||||||
transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: topOffset), size: imageSize))
|
transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: topOffset), size: imageSize))
|
||||||
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: topOffset + imageHeight), size: titleSize))
|
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width - layout.safeInsets.left - layout.safeInsets.right - layout.intrinsicInsets.left - layout.intrinsicInsets.right) / 2.0), y: topOffset + imageHeight), size: titleSize))
|
||||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - textSize.width) / 2.0), y: self.titleNode.frame.maxY + textSpacing), size: textSize))
|
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - textSize.width - layout.safeInsets.left - layout.safeInsets.right - layout.intrinsicInsets.left - layout.intrinsicInsets.right) / 2.0), y: self.titleNode.frame.maxY + textSpacing), size: textSize))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -335,9 +335,10 @@ func generateThemeName(accentColor: UIColor) -> String {
|
|||||||
|
|
||||||
if let color = nearest?.color, let colorName = colors[color]?.capitalized {
|
if let color = nearest?.color, let colorName = colors[color]?.capitalized {
|
||||||
if arc4random() % 2 == 0 {
|
if arc4random() % 2 == 0 {
|
||||||
return "\(adjectives[Int(arc4random()) % adjectives.count].capitalized) \(colorName)"
|
|
||||||
|
return "\((adjectives.randomElement() ?? "").capitalized) \(colorName)"
|
||||||
} else {
|
} else {
|
||||||
return "\(colorName) \(subjectives[Int(arc4random()) % subjectives.count].capitalized)"
|
return "\(colorName) \((subjectives.randomElement() ?? "").capitalized)"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return ""
|
return ""
|
||||||
|
@ -83,6 +83,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.chatListBackgroundNode = ASDisplayNode()
|
self.chatListBackgroundNode = ASDisplayNode()
|
||||||
|
|
||||||
self.chatContainerNode = ASDisplayNode()
|
self.chatContainerNode = ASDisplayNode()
|
||||||
|
self.chatContainerNode.clipsToBounds = true
|
||||||
self.instantChatBackgroundNode = WallpaperBackgroundNode()
|
self.instantChatBackgroundNode = WallpaperBackgroundNode()
|
||||||
self.instantChatBackgroundNode.displaysAsynchronously = false
|
self.instantChatBackgroundNode.displaysAsynchronously = false
|
||||||
self.instantChatBackgroundNode.image = chatControllerBackgroundImage(theme: previewTheme, wallpaper: previewTheme.chat.defaultWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper)
|
self.instantChatBackgroundNode.image = chatControllerBackgroundImage(theme: previewTheme, wallpaper: previewTheme.chat.defaultWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper)
|
||||||
@ -94,7 +95,6 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.remoteChatBackgroundNode.view.contentMode = .scaleAspectFill
|
self.remoteChatBackgroundNode.view.contentMode = .scaleAspectFill
|
||||||
|
|
||||||
self.blurredNode = BlurredImageNode()
|
self.blurredNode = BlurredImageNode()
|
||||||
self.blurredNode.clipsToBounds = true
|
|
||||||
self.blurredNode.blurView.contentMode = .scaleAspectFill
|
self.blurredNode.blurView.contentMode = .scaleAspectFill
|
||||||
|
|
||||||
self.toolbarNode = WallpaperGalleryToolbarNode(theme: self.previewTheme, strings: self.presentationData.strings)
|
self.toolbarNode = WallpaperGalleryToolbarNode(theme: self.previewTheme, strings: self.presentationData.strings)
|
||||||
|
@ -362,6 +362,10 @@ public final class ManagedAudioSession {
|
|||||||
} |> runOn(queue)
|
} |> runOn(queue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func isOtherAudioPlaying() -> Bool {
|
||||||
|
return AVAudioSession.sharedInstance().secondaryAudioShouldBeSilencedHint
|
||||||
|
}
|
||||||
|
|
||||||
public func push(audioSessionType: ManagedAudioSessionType, outputMode: AudioSessionOutputMode = .system, once: Bool = false, activate: @escaping (AudioSessionActivationState) -> Void, deactivate: @escaping () -> Signal<Void, NoError>) -> Disposable {
|
public func push(audioSessionType: ManagedAudioSessionType, outputMode: AudioSessionOutputMode = .system, once: Bool = false, activate: @escaping (AudioSessionActivationState) -> Void, deactivate: @escaping () -> Signal<Void, NoError>) -> Disposable {
|
||||||
return self.push(audioSessionType: audioSessionType, once: once, manualActivate: { control in
|
return self.push(audioSessionType: audioSessionType, once: once, manualActivate: { control in
|
||||||
control.setupAndActivate(synchronous: false, { state in
|
control.setupAndActivate(synchronous: false, { state in
|
||||||
|
@ -47,13 +47,13 @@ public enum PresentationResourceKey: Int32 {
|
|||||||
case itemListAddExceptionIcon
|
case itemListAddExceptionIcon
|
||||||
case itemListAddPhoneIcon
|
case itemListAddPhoneIcon
|
||||||
case itemListClearInputIcon
|
case itemListClearInputIcon
|
||||||
|
|
||||||
case itemListStickerItemUnreadDot
|
case itemListStickerItemUnreadDot
|
||||||
case itemListVerifiedPeerIcon
|
case itemListVerifiedPeerIcon
|
||||||
|
|
||||||
case itemListCloudFetchIcon
|
case itemListCloudFetchIcon
|
||||||
|
|
||||||
case itemListCloseIconImage
|
case itemListCloseIconImage
|
||||||
|
case itemListCornersTop
|
||||||
|
case itemListCornersBottom
|
||||||
|
case itemListCornersBoth
|
||||||
|
|
||||||
case chatListLockTopUnlockedImage
|
case chatListLockTopUnlockedImage
|
||||||
case chatListLockBottomUnlockedImage
|
case chatListLockBottomUnlockedImage
|
||||||
|
@ -144,4 +144,40 @@ public struct PresentationResourcesItemList {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func cornersImage(_ theme: PresentationTheme, top: Bool, bottom: Bool) -> UIImage? {
|
||||||
|
if !top && !bottom {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let key: PresentationResourceKey
|
||||||
|
if top && bottom {
|
||||||
|
key = PresentationResourceKey.itemListCornersBoth
|
||||||
|
} else if top {
|
||||||
|
key = PresentationResourceKey.itemListCornersTop
|
||||||
|
} else {
|
||||||
|
key = PresentationResourceKey.itemListCornersBottom
|
||||||
|
}
|
||||||
|
return theme.image(key.rawValue, { theme in
|
||||||
|
return generateImage(CGSize(width: 50.0, height: 50.0), rotatedContext: { (size, context) in
|
||||||
|
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||||
|
context.setFillColor(theme.list.blocksBackgroundColor.cgColor)
|
||||||
|
context.fill(bounds)
|
||||||
|
|
||||||
|
context.setBlendMode(.clear)
|
||||||
|
|
||||||
|
var corners: UIRectCorner = []
|
||||||
|
if top {
|
||||||
|
corners.insert(.topLeft)
|
||||||
|
corners.insert(.topRight)
|
||||||
|
}
|
||||||
|
if bottom {
|
||||||
|
corners.insert(.bottomLeft)
|
||||||
|
corners.insert(.bottomRight)
|
||||||
|
}
|
||||||
|
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: 11.0, height: 11.0))
|
||||||
|
context.addPath(path.cgPath)
|
||||||
|
context.fillPath()
|
||||||
|
})?.stretchableImage(withLeftCapWidth: 25, topCapHeight: 25)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ final class ChatButtonKeyboardInputNode: ChatInputNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, standardInputHeight: CGFloat, inputHeight: CGFloat, maximumHeight: CGFloat, inputPanelHeight: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, isVisible: Bool) -> (CGFloat, CGFloat) {
|
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, standardInputHeight: CGFloat, inputHeight: CGFloat, maximumHeight: CGFloat, inputPanelHeight: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, deviceMetrics: DeviceMetrics, isVisible: Bool) -> (CGFloat, CGFloat) {
|
||||||
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: UIScreenPixel)))
|
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: UIScreenPixel)))
|
||||||
|
|
||||||
if self.theme !== interfaceState.theme {
|
if self.theme !== interfaceState.theme {
|
||||||
|
@ -4152,7 +4152,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
subscriber.putCompletion()
|
subscriber.putCompletion()
|
||||||
return EmptyDisposable
|
return EmptyDisposable
|
||||||
}
|
}
|
||||||
subscriber.putNext(strongSelf.traceVisibility() && isTopmostChatController(strongSelf))
|
|
||||||
|
subscriber.putNext(strongSelf.traceVisibility() && isTopmostChatController(strongSelf) && !strongSelf.context.sharedContext.mediaManager.audioSession.isOtherAudioPlaying())
|
||||||
subscriber.putCompletion()
|
subscriber.putCompletion()
|
||||||
return EmptyDisposable
|
return EmptyDisposable
|
||||||
} |> then(.complete() |> delay(1.0, queue: Queue.mainQueue())) |> restart
|
} |> then(.complete() |> delay(1.0, queue: Queue.mainQueue())) |> restart
|
||||||
|
@ -591,7 +591,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.insertSubnode(inputNode, aboveSubnode: self.inputPanelBackgroundNode)
|
self.insertSubnode(inputNode, aboveSubnode: self.inputPanelBackgroundNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inputNodeHeightAndOverflow = inputNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: cleanInsets.bottom, standardInputHeight: layout.standardInputHeight, inputHeight: layout.inputHeight ?? 0.0, maximumHeight: maximumInputNodeHeight, inputPanelHeight: inputPanelNodeBaseHeight, transition: immediatelyLayoutInputNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState, isVisible: true)
|
inputNodeHeightAndOverflow = inputNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: cleanInsets.bottom, standardInputHeight: layout.standardInputHeight, inputHeight: layout.inputHeight ?? 0.0, maximumHeight: maximumInputNodeHeight, inputPanelHeight: inputPanelNodeBaseHeight, transition: immediatelyLayoutInputNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState, deviceMetrics: layout.deviceMetrics, isVisible: true)
|
||||||
} else if let inputNode = self.inputNode {
|
} else if let inputNode = self.inputNode {
|
||||||
dismissedInputNode = inputNode
|
dismissedInputNode = inputNode
|
||||||
self.inputNode = nil
|
self.inputNode = nil
|
||||||
@ -672,7 +672,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let inputMediaNode = self.inputMediaNode, inputMediaNode != self.inputNode {
|
if let inputMediaNode = self.inputMediaNode, inputMediaNode != self.inputNode {
|
||||||
let _ = inputMediaNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: cleanInsets.bottom, standardInputHeight: layout.standardInputHeight, inputHeight: layout.inputHeight ?? 0.0, maximumHeight: maximumInputNodeHeight, inputPanelHeight: inputPanelSize?.height ?? 0.0, transition: .immediate, interfaceState: self.chatPresentationInterfaceState, isVisible: false)
|
let _ = inputMediaNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: cleanInsets.bottom, standardInputHeight: layout.standardInputHeight, inputHeight: layout.inputHeight ?? 0.0, maximumHeight: maximumInputNodeHeight, inputPanelHeight: inputPanelSize?.height ?? 0.0, transition: .immediate, interfaceState: self.chatPresentationInterfaceState, deviceMetrics: layout.deviceMetrics, isVisible: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
transition.updateFrame(node: self.titleAccessoryPanelContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: 56.0)))
|
transition.updateFrame(node: self.titleAccessoryPanelContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: 56.0)))
|
||||||
@ -1573,7 +1573,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
inputNode.interfaceInteraction = interfaceInteraction
|
inputNode.interfaceInteraction = interfaceInteraction
|
||||||
self.inputMediaNode = inputNode
|
self.inputMediaNode = inputNode
|
||||||
if let (validLayout, _) = self.validLayout {
|
if let (validLayout, _) = self.validLayout {
|
||||||
let _ = inputNode.updateLayout(width: validLayout.size.width, leftInset: validLayout.safeInsets.left, rightInset: validLayout.safeInsets.right, bottomInset: validLayout.intrinsicInsets.bottom, standardInputHeight: validLayout.standardInputHeight, inputHeight: validLayout.inputHeight ?? 0.0, maximumHeight: validLayout.standardInputHeight, inputPanelHeight: 44.0, transition: .immediate, interfaceState: self.chatPresentationInterfaceState, isVisible: false)
|
let _ = inputNode.updateLayout(width: validLayout.size.width, leftInset: validLayout.safeInsets.left, rightInset: validLayout.safeInsets.right, bottomInset: validLayout.intrinsicInsets.bottom, standardInputHeight: validLayout.standardInputHeight, inputHeight: validLayout.inputHeight ?? 0.0, maximumHeight: validLayout.standardInputHeight, inputPanelHeight: 44.0, transition: .immediate, interfaceState: self.chatPresentationInterfaceState, deviceMetrics: validLayout.deviceMetrics, isVisible: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.textInputPanelNode?.loadTextInputNodeIfNeeded()
|
self.textInputPanelNode?.loadTextInputNodeIfNeeded()
|
||||||
|
@ -10,7 +10,7 @@ class ChatInputNode: ASDisplayNode {
|
|||||||
return .single(Void())
|
return .single(Void())
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, standardInputHeight: CGFloat, inputHeight: CGFloat, maximumHeight: CGFloat, inputPanelHeight: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, isVisible: Bool) -> (CGFloat, CGFloat) {
|
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, standardInputHeight: CGFloat, inputHeight: CGFloat, maximumHeight: CGFloat, inputPanelHeight: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, deviceMetrics: DeviceMetrics, isVisible: Bool) -> (CGFloat, CGFloat) {
|
||||||
return (0.0, 0.0)
|
return (0.0, 0.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ private func canEditMessage(accountPeerId: PeerId, limitsConfiguration: LimitsCo
|
|||||||
if let peer = message.peers[message.id.peerId], let channel = peer as? TelegramChannel {
|
if let peer = message.peers[message.id.peerId], let channel = peer as? TelegramChannel {
|
||||||
switch channel.info {
|
switch channel.info {
|
||||||
case .broadcast:
|
case .broadcast:
|
||||||
if channel.hasPermission(.editAllMessages) {
|
if message.author?.id == message.id.peerId || channel.hasPermission(.editAllMessages) {
|
||||||
hasEditRights = true
|
hasEditRights = true
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -36,7 +36,7 @@ final class ChatMediaInputGifPane: ChatMediaInputPane, UIScrollViewDelegate {
|
|||||||
private let disposable = MetaDisposable()
|
private let disposable = MetaDisposable()
|
||||||
let trendingPromise = Promise<[FileMediaReference]?>(nil)
|
let trendingPromise = Promise<[FileMediaReference]?>(nil)
|
||||||
|
|
||||||
private var validLayout: (CGSize, CGFloat, CGFloat, Bool, Bool)?
|
private var validLayout: (CGSize, CGFloat, CGFloat, Bool, Bool, DeviceMetrics)?
|
||||||
private var didScrollPreviousOffset: CGFloat?
|
private var didScrollPreviousOffset: CGFloat?
|
||||||
|
|
||||||
private var didScrollPreviousState: ChatMediaInputPaneScrollState?
|
private var didScrollPreviousState: ChatMediaInputPaneScrollState?
|
||||||
@ -76,18 +76,18 @@ final class ChatMediaInputGifPane: ChatMediaInputPane, UIScrollViewDelegate {
|
|||||||
self.searchPlaceholderNode.setup(theme: theme, strings: strings, type: .gifs)
|
self.searchPlaceholderNode.setup(theme: theme, strings: strings, type: .gifs)
|
||||||
|
|
||||||
if let layout = self.validLayout {
|
if let layout = self.validLayout {
|
||||||
self.updateLayout(size: layout.0, topInset: layout.1, bottomInset: layout.2, isExpanded: layout.3, isVisible: layout.4, transition: .immediate)
|
self.updateLayout(size: layout.0, topInset: layout.1, bottomInset: layout.2, isExpanded: layout.3, isVisible: layout.4, deviceMetrics: layout.5, transition: .immediate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateLayout(size: CGSize, topInset: CGFloat, bottomInset: CGFloat, isExpanded: Bool, isVisible: Bool, transition: ContainedViewLayoutTransition) {
|
override func updateLayout(size: CGSize, topInset: CGFloat, bottomInset: CGFloat, isExpanded: Bool, isVisible: Bool, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition) {
|
||||||
var changedIsExpanded = false
|
var changedIsExpanded = false
|
||||||
if let (_, _, _, previousIsExpanded, _) = self.validLayout {
|
if let (_, _, _, previousIsExpanded, _, _) = self.validLayout {
|
||||||
if previousIsExpanded != isExpanded {
|
if previousIsExpanded != isExpanded {
|
||||||
changedIsExpanded = true
|
changedIsExpanded = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.validLayout = (size, topInset, bottomInset, isExpanded, isVisible)
|
self.validLayout = (size, topInset, bottomInset, isExpanded, isVisible, deviceMetrics)
|
||||||
|
|
||||||
let emptySize = self.emptyNode.updateLayout(size)
|
let emptySize = self.emptyNode.updateLayout(size)
|
||||||
transition.updateFrame(node: self.emptyNode, frame: CGRect(origin: CGPoint(x: floor(size.width - emptySize.width) / 2.0, y: topInset + floor(size.height - topInset - emptySize.height) / 2.0), size: emptySize))
|
transition.updateFrame(node: self.emptyNode, frame: CGRect(origin: CGPoint(x: floor(size.width - emptySize.width) / 2.0, y: topInset + floor(size.height - topInset - emptySize.height) / 2.0), size: emptySize))
|
||||||
@ -96,6 +96,13 @@ final class ChatMediaInputGifPane: ChatMediaInputPane, UIScrollViewDelegate {
|
|||||||
let previousBounds = multiplexedNode.layer.bounds
|
let previousBounds = multiplexedNode.layer.bounds
|
||||||
multiplexedNode.topInset = topInset + 60.0
|
multiplexedNode.topInset = topInset + 60.0
|
||||||
multiplexedNode.bottomInset = bottomInset
|
multiplexedNode.bottomInset = bottomInset
|
||||||
|
|
||||||
|
if case .tablet = deviceMetrics.type, size.width > 480.0 {
|
||||||
|
multiplexedNode.idealHeight = 120.0
|
||||||
|
} else {
|
||||||
|
multiplexedNode.idealHeight = 93.0
|
||||||
|
}
|
||||||
|
|
||||||
let nodeFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height))
|
let nodeFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height))
|
||||||
|
|
||||||
var targetBounds = CGRect(origin: previousBounds.origin, size: nodeFrame.size)
|
var targetBounds = CGRect(origin: previousBounds.origin, size: nodeFrame.size)
|
||||||
|
@ -425,7 +425,7 @@ final class ChatMediaInputNode: ChatInputNode {
|
|||||||
private var currentView: ItemCollectionsView?
|
private var currentView: ItemCollectionsView?
|
||||||
private let dismissedPeerSpecificStickerPack = Promise<Bool>()
|
private let dismissedPeerSpecificStickerPack = Promise<Bool>()
|
||||||
|
|
||||||
private var validLayout: (CGFloat, CGFloat, CGFloat, CGFloat, CGFloat, CGFloat, CGFloat, CGFloat, ChatPresentationInterfaceState, Bool)?
|
private var validLayout: (CGFloat, CGFloat, CGFloat, CGFloat, CGFloat, CGFloat, CGFloat, CGFloat, ChatPresentationInterfaceState, DeviceMetrics, Bool)?
|
||||||
private var paneArrangement: ChatMediaInputPaneArrangement
|
private var paneArrangement: ChatMediaInputPaneArrangement
|
||||||
private var initializedArrangement = false
|
private var initializedArrangement = false
|
||||||
|
|
||||||
@ -1045,8 +1045,8 @@ final class ChatMediaInputNode: ChatInputNode {
|
|||||||
if let index = self.paneArrangement.panes.firstIndex(of: pane), index != self.paneArrangement.currentIndex {
|
if let index = self.paneArrangement.panes.firstIndex(of: pane), index != self.paneArrangement.currentIndex {
|
||||||
let previousGifPanelWasActive = self.paneArrangement.panes[self.paneArrangement.currentIndex] == .gifs
|
let previousGifPanelWasActive = self.paneArrangement.panes[self.paneArrangement.currentIndex] == .gifs
|
||||||
self.paneArrangement = self.paneArrangement.withIndexTransition(0.0).withCurrentIndex(index)
|
self.paneArrangement = self.paneArrangement.withIndexTransition(0.0).withCurrentIndex(index)
|
||||||
if let (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, isVisible) = self.validLayout {
|
if let (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, deviceMetrics, isVisible) = self.validLayout {
|
||||||
let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, standardInputHeight: standardInputHeight, inputHeight: inputHeight, maximumHeight: maximumHeight, inputPanelHeight: inputPanelHeight, transition: .animated(duration: 0.25, curve: .spring), interfaceState: interfaceState, isVisible: isVisible)
|
let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, standardInputHeight: standardInputHeight, inputHeight: inputHeight, maximumHeight: maximumHeight, inputPanelHeight: inputPanelHeight, transition: .animated(duration: 0.25, curve: .spring), interfaceState: interfaceState, deviceMetrics: deviceMetrics, isVisible: isVisible)
|
||||||
self.updateAppearanceTransition(transition: transition)
|
self.updateAppearanceTransition(transition: transition)
|
||||||
}
|
}
|
||||||
let updatedGifPanelWasActive = self.paneArrangement.panes[self.paneArrangement.currentIndex] == .gifs
|
let updatedGifPanelWasActive = self.paneArrangement.panes[self.paneArrangement.currentIndex] == .gifs
|
||||||
@ -1066,8 +1066,8 @@ final class ChatMediaInputNode: ChatInputNode {
|
|||||||
self.setHighlightedItemCollectionId(ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.trending.rawValue, id: 0))
|
self.setHighlightedItemCollectionId(ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.trending.rawValue, id: 0))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, isVisible) = self.validLayout {
|
if let (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, deviceMetrics, isVisible) = self.validLayout {
|
||||||
let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, standardInputHeight: standardInputHeight, inputHeight: inputHeight, maximumHeight: maximumHeight, inputPanelHeight: inputPanelHeight, transition: .animated(duration: 0.25, curve: .spring), interfaceState: interfaceState, isVisible: isVisible)
|
let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, standardInputHeight: standardInputHeight, inputHeight: inputHeight, maximumHeight: maximumHeight, inputPanelHeight: inputPanelHeight, transition: .animated(duration: 0.25, curve: .spring), interfaceState: interfaceState, deviceMetrics: deviceMetrics, isVisible: isVisible)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1195,13 +1195,13 @@ final class ChatMediaInputNode: ChatInputNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, standardInputHeight: CGFloat, inputHeight: CGFloat, maximumHeight: CGFloat, inputPanelHeight: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, isVisible: Bool) -> (CGFloat, CGFloat) {
|
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, standardInputHeight: CGFloat, inputHeight: CGFloat, maximumHeight: CGFloat, inputPanelHeight: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, deviceMetrics: DeviceMetrics, isVisible: Bool) -> (CGFloat, CGFloat) {
|
||||||
var searchMode: ChatMediaInputSearchMode?
|
var searchMode: ChatMediaInputSearchMode?
|
||||||
if let (_, _, _, _, _, _, _, _, interfaceState, _) = self.validLayout, case let .media(_, maybeExpanded) = interfaceState.inputMode, let expanded = maybeExpanded, case let .search(mode) = expanded {
|
if let (_, _, _, _, _, _, _, _, interfaceState, _, _) = self.validLayout, case let .media(_, maybeExpanded) = interfaceState.inputMode, let expanded = maybeExpanded, case let .search(mode) = expanded {
|
||||||
searchMode = mode
|
searchMode = mode
|
||||||
}
|
}
|
||||||
|
|
||||||
self.validLayout = (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, isVisible)
|
self.validLayout = (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, deviceMetrics, isVisible)
|
||||||
|
|
||||||
if self.theme !== interfaceState.theme || self.strings !== interfaceState.strings {
|
if self.theme !== interfaceState.theme || self.strings !== interfaceState.strings {
|
||||||
self.updateThemeAndStrings(theme: interfaceState.theme, strings: interfaceState.strings)
|
self.updateThemeAndStrings(theme: interfaceState.theme, strings: interfaceState.strings)
|
||||||
@ -1235,12 +1235,12 @@ final class ChatMediaInputNode: ChatInputNode {
|
|||||||
let containerFrame = CGRect(origin: CGPoint(x: 0.0, y: -inputPanelHeight), size: CGSize(width: width, height: panelHeight + inputPanelHeight))
|
let containerFrame = CGRect(origin: CGPoint(x: 0.0, y: -inputPanelHeight), size: CGSize(width: width, height: panelHeight + inputPanelHeight))
|
||||||
if searchContainerNode.supernode != nil {
|
if searchContainerNode.supernode != nil {
|
||||||
transition.updateFrame(node: searchContainerNode, frame: containerFrame)
|
transition.updateFrame(node: searchContainerNode, frame: containerFrame)
|
||||||
searchContainerNode.updateLayout(size: containerFrame.size, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, inputHeight: inputHeight, transition: transition)
|
searchContainerNode.updateLayout(size: containerFrame.size, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, inputHeight: inputHeight, deviceMetrics: deviceMetrics, transition: transition)
|
||||||
} else {
|
} else {
|
||||||
self.searchContainerNode = searchContainerNode
|
self.searchContainerNode = searchContainerNode
|
||||||
self.insertSubnode(searchContainerNode, belowSubnode: self.collectionListContainer)
|
self.insertSubnode(searchContainerNode, belowSubnode: self.collectionListContainer)
|
||||||
searchContainerNode.frame = containerFrame
|
searchContainerNode.frame = containerFrame
|
||||||
searchContainerNode.updateLayout(size: containerFrame.size, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, inputHeight: inputHeight, transition: .immediate)
|
searchContainerNode.updateLayout(size: containerFrame.size, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, inputHeight: inputHeight, deviceMetrics: deviceMetrics, transition: .immediate)
|
||||||
var placeholderNode: PaneSearchBarPlaceholderNode?
|
var placeholderNode: PaneSearchBarPlaceholderNode?
|
||||||
if let searchMode = searchMode {
|
if let searchMode = searchMode {
|
||||||
switch searchMode {
|
switch searchMode {
|
||||||
@ -1349,10 +1349,9 @@ final class ChatMediaInputNode: ChatInputNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.gifPane.updateLayout(size: CGSize(width: width - leftInset - rightInset, height: panelHeight), topInset: 41.0, bottomInset: bottomInset, isExpanded: isExpanded, isVisible: isVisible, transition: transition)
|
self.gifPane.updateLayout(size: CGSize(width: width - leftInset - rightInset, height: panelHeight), topInset: 41.0, bottomInset: bottomInset, isExpanded: isExpanded, isVisible: isVisible, deviceMetrics: deviceMetrics, transition: transition)
|
||||||
|
self.stickerPane.updateLayout(size: CGSize(width: width - leftInset - rightInset, height: panelHeight), topInset: 41.0, bottomInset: bottomInset, isExpanded: isExpanded, isVisible: isVisible && visiblePanes.contains(where: { $0.0 == .stickers }), deviceMetrics: deviceMetrics, transition: transition)
|
||||||
self.stickerPane.updateLayout(size: CGSize(width: width - leftInset - rightInset, height: panelHeight), topInset: 41.0, bottomInset: bottomInset, isExpanded: isExpanded, isVisible: isVisible && visiblePanes.contains(where: { $0.0 == .stickers }), transition: transition)
|
self.trendingPane.updateLayout(size: CGSize(width: width - leftInset - rightInset, height: panelHeight), topInset: 41.0, bottomInset: bottomInset, isExpanded: isExpanded, isVisible: isVisible, deviceMetrics: deviceMetrics, transition: transition)
|
||||||
self.trendingPane.updateLayout(size: CGSize(width: width - leftInset - rightInset, height: panelHeight), topInset: 41.0, bottomInset: bottomInset, isExpanded: isExpanded, isVisible: isVisible, transition: transition)
|
|
||||||
|
|
||||||
if self.gifPane.supernode != nil {
|
if self.gifPane.supernode != nil {
|
||||||
if !visiblePanes.contains(where: { $0.0 == .gifs }) {
|
if !visiblePanes.contains(where: { $0.0 == .gifs }) {
|
||||||
@ -1525,7 +1524,7 @@ final class ChatMediaInputNode: ChatInputNode {
|
|||||||
self.trendingPane.removeFromSupernode()
|
self.trendingPane.removeFromSupernode()
|
||||||
}
|
}
|
||||||
case .changed:
|
case .changed:
|
||||||
if let (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, isVisible) = self.validLayout {
|
if let (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, deviceMetrics, isVisible) = self.validLayout {
|
||||||
let translationX = -recognizer.translation(in: self.view).x
|
let translationX = -recognizer.translation(in: self.view).x
|
||||||
var indexTransition = translationX / width
|
var indexTransition = translationX / width
|
||||||
if self.paneArrangement.currentIndex == 0 {
|
if self.paneArrangement.currentIndex == 0 {
|
||||||
@ -1534,10 +1533,10 @@ final class ChatMediaInputNode: ChatInputNode {
|
|||||||
indexTransition = min(0.0, indexTransition)
|
indexTransition = min(0.0, indexTransition)
|
||||||
}
|
}
|
||||||
self.paneArrangement = self.paneArrangement.withIndexTransition(indexTransition)
|
self.paneArrangement = self.paneArrangement.withIndexTransition(indexTransition)
|
||||||
let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, standardInputHeight: standardInputHeight, inputHeight: inputHeight, maximumHeight: maximumHeight, inputPanelHeight: inputPanelHeight, transition: .immediate, interfaceState: interfaceState, isVisible: isVisible)
|
let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, standardInputHeight: standardInputHeight, inputHeight: inputHeight, maximumHeight: maximumHeight, inputPanelHeight: inputPanelHeight, transition: .immediate, interfaceState: interfaceState, deviceMetrics: deviceMetrics, isVisible: isVisible)
|
||||||
}
|
}
|
||||||
case .ended:
|
case .ended:
|
||||||
if let (width, _, _, _, _, _, _, _, _, _) = self.validLayout {
|
if let (width, _, _, _, _, _, _, _, _, _, _) = self.validLayout {
|
||||||
var updatedIndex = self.paneArrangement.currentIndex
|
var updatedIndex = self.paneArrangement.currentIndex
|
||||||
if abs(self.paneArrangement.indexTransition * width) > 30.0 {
|
if abs(self.paneArrangement.indexTransition * width) > 30.0 {
|
||||||
if self.paneArrangement.indexTransition < 0.0 {
|
if self.paneArrangement.indexTransition < 0.0 {
|
||||||
@ -1550,9 +1549,9 @@ final class ChatMediaInputNode: ChatInputNode {
|
|||||||
self.setCurrentPane(self.paneArrangement.panes[updatedIndex], transition: .animated(duration: 0.25, curve: .spring))
|
self.setCurrentPane(self.paneArrangement.panes[updatedIndex], transition: .animated(duration: 0.25, curve: .spring))
|
||||||
}
|
}
|
||||||
case .cancelled:
|
case .cancelled:
|
||||||
if let (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, isVisible) = self.validLayout {
|
if let (width, leftInset, rightInset, bottomInset, standardInputHeight, inputHeight, maximumHeight, inputPanelHeight, interfaceState, deviceMetrics, isVisible) = self.validLayout {
|
||||||
self.paneArrangement = self.paneArrangement.withIndexTransition(0.0)
|
self.paneArrangement = self.paneArrangement.withIndexTransition(0.0)
|
||||||
let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, standardInputHeight: standardInputHeight, inputHeight: inputHeight, maximumHeight: maximumHeight, inputPanelHeight: inputPanelHeight, transition: .animated(duration: 0.25, curve: .spring), interfaceState: interfaceState, isVisible: isVisible)
|
let _ = self.updateLayout(width: width, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, standardInputHeight: standardInputHeight, inputHeight: inputHeight, maximumHeight: maximumHeight, inputPanelHeight: inputPanelHeight, transition: .animated(duration: 0.25, curve: .spring), interfaceState: interfaceState, deviceMetrics: deviceMetrics, isVisible: isVisible)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
@ -16,7 +16,7 @@ class ChatMediaInputPane: ASDisplayNode {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(size: CGSize, topInset: CGFloat, bottomInset: CGFloat, isExpanded: Bool, isVisible: Bool, transition: ContainedViewLayoutTransition) {
|
func updateLayout(size: CGSize, topInset: CGFloat, bottomInset: CGFloat, isExpanded: Bool, isVisible: Bool, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
|
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
|
||||||
|
@ -251,7 +251,7 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
|
|||||||
if self.currentSize != size {
|
if self.currentSize != size {
|
||||||
self.currentSize = size
|
self.currentSize = size
|
||||||
|
|
||||||
let sideSize: CGFloat = min(75.0 - 10.0, size.width)
|
let sideSize: CGFloat = size.width - 10.0 //min(75.0 - 10.0, size.width)
|
||||||
let boundingSize = CGSize(width: sideSize, height: sideSize)
|
let boundingSize = CGSize(width: sideSize, height: sideSize)
|
||||||
|
|
||||||
if let (_, _, mediaDimensions) = self.currentState {
|
if let (_, _, mediaDimensions) = self.currentState {
|
||||||
@ -271,7 +271,7 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let interfaceInteraction = self.interfaceInteraction, let (_, item, _) = self.currentState, case .ended = recognizer.state {
|
if let interfaceInteraction = self.interfaceInteraction, let (_, item, _) = self.currentState, case .ended = recognizer.state {
|
||||||
interfaceInteraction.sendSticker(.standalone(media: item.file), false, self, self.bounds)
|
let _ = interfaceInteraction.sendSticker(.standalone(media: item.file), false, self, self.bounds)
|
||||||
self.imageNode.layer.animateAlpha(from: 0.5, to: 1.0, duration: 1.0)
|
self.imageNode.layer.animateAlpha(from: 0.5, to: 1.0, duration: 1.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ final class ChatMediaInputStickerPane: ChatMediaInputPane {
|
|||||||
self.gridNode.scrollView.alwaysBounceVertical = true
|
self.gridNode.scrollView.alwaysBounceVertical = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateLayout(size: CGSize, topInset: CGFloat, bottomInset: CGFloat, isExpanded: Bool, isVisible: Bool, transition: ContainedViewLayoutTransition) {
|
override func updateLayout(size: CGSize, topInset: CGFloat, bottomInset: CGFloat, isExpanded: Bool, isVisible: Bool, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition) {
|
||||||
var changedIsExpanded = false
|
var changedIsExpanded = false
|
||||||
if let previousIsExpanded = self.isExpanded {
|
if let previousIsExpanded = self.isExpanded {
|
||||||
if previousIsExpanded != isExpanded {
|
if previousIsExpanded != isExpanded {
|
||||||
@ -123,10 +123,17 @@ final class ChatMediaInputStickerPane: ChatMediaInputPane {
|
|||||||
}
|
}
|
||||||
self.isExpanded = isExpanded
|
self.isExpanded = isExpanded
|
||||||
|
|
||||||
|
let maxItemSize: CGSize
|
||||||
|
if case .tablet = deviceMetrics.type, size.width > 480.0 {
|
||||||
|
maxItemSize = CGSize(width: 90.0, height: 96.0)
|
||||||
|
} else {
|
||||||
|
maxItemSize = CGSize(width: 75.0, height: 80.0)
|
||||||
|
}
|
||||||
|
|
||||||
let sideInset: CGFloat = 2.0
|
let sideInset: CGFloat = 2.0
|
||||||
var itemSide: CGFloat = floor((size.width - sideInset * 2.0) / 5.0)
|
var itemSide: CGFloat = floor((size.width - sideInset * 2.0) / 5.0)
|
||||||
itemSide = min(itemSide, 75.0)
|
itemSide = min(itemSide, maxItemSize.width)
|
||||||
let itemSize = CGSize(width: itemSide, height: max(itemSide, 80.0))
|
let itemSize = CGSize(width: itemSide, height: max(itemSide, maxItemSize.height))
|
||||||
|
|
||||||
var scrollToItem: GridNodeScrollToItem?
|
var scrollToItem: GridNodeScrollToItem?
|
||||||
if changedIsExpanded {
|
if changedIsExpanded {
|
||||||
|
@ -75,24 +75,31 @@ private final class TrendingPaneEntry: Identifiable, Comparable {
|
|||||||
return lhs.index < rhs.index
|
return lhs.index < rhs.index
|
||||||
}
|
}
|
||||||
|
|
||||||
func item(account: Account, interaction: TrendingPaneInteraction) -> ListViewItem {
|
func item(account: Account, interaction: TrendingPaneInteraction) -> GridItem {
|
||||||
return MediaInputPaneTrendingItem(account: account, theme: self.theme, strings: self.strings, interaction: interaction, info: self.info, topItems: self.topItems, installed: self.installed, unread: self.unread)
|
let info = self.info
|
||||||
|
return StickerPaneSearchGlobalItem(account: account, theme: self.theme, strings: self.strings, info: self.info, topItems: self.topItems, grid: true, installed: self.installed, unread: self.unread, open: {
|
||||||
|
interaction.openPack(info)
|
||||||
|
}, install: {
|
||||||
|
interaction.installPack(info)
|
||||||
|
}, getItemIsPreviewed: { item in
|
||||||
|
return interaction.getItemIsPreviewed(item)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct TrendingPaneTransition {
|
private struct TrendingPaneTransition {
|
||||||
let deletions: [ListViewDeleteItem]
|
let deletions: [Int]
|
||||||
let insertions: [ListViewInsertItem]
|
let insertions: [GridNodeInsertItem]
|
||||||
let updates: [ListViewUpdateItem]
|
let updates: [GridNodeUpdateItem]
|
||||||
let initial: Bool
|
let initial: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
private func preparedTransition(from fromEntries: [TrendingPaneEntry], to toEntries: [TrendingPaneEntry], account: Account, interaction: TrendingPaneInteraction, initial: Bool) -> TrendingPaneTransition {
|
private func preparedTransition(from fromEntries: [TrendingPaneEntry], to toEntries: [TrendingPaneEntry], account: Account, interaction: TrendingPaneInteraction, initial: Bool) -> TrendingPaneTransition {
|
||||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||||
|
|
||||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
let deletions = deleteIndices
|
||||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interaction: interaction), directionHint: nil) }
|
let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, interaction: interaction), previousIndex: $0.2) }
|
||||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interaction: interaction), directionHint: nil) }
|
let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, interaction: interaction)) }
|
||||||
|
|
||||||
return TrendingPaneTransition(deletions: deletions, insertions: insertions, updates: updates, initial: initial)
|
return TrendingPaneTransition(deletions: deletions, insertions: insertions, updates: updates, initial: initial)
|
||||||
}
|
}
|
||||||
@ -114,7 +121,7 @@ final class ChatMediaInputTrendingPane: ChatMediaInputPane {
|
|||||||
private let controllerInteraction: ChatControllerInteraction
|
private let controllerInteraction: ChatControllerInteraction
|
||||||
private let getItemIsPreviewed: (StickerPackItem) -> Bool
|
private let getItemIsPreviewed: (StickerPackItem) -> Bool
|
||||||
|
|
||||||
private let listNode: ListView
|
let gridNode: GridNode
|
||||||
|
|
||||||
private var enqueuedTransitions: [TrendingPaneTransition] = []
|
private var enqueuedTransitions: [TrendingPaneTransition] = []
|
||||||
private var validLayout: (CGSize, CGFloat)?
|
private var validLayout: (CGSize, CGFloat)?
|
||||||
@ -135,13 +142,13 @@ final class ChatMediaInputTrendingPane: ChatMediaInputPane {
|
|||||||
self.controllerInteraction = controllerInteraction
|
self.controllerInteraction = controllerInteraction
|
||||||
self.getItemIsPreviewed = getItemIsPreviewed
|
self.getItemIsPreviewed = getItemIsPreviewed
|
||||||
|
|
||||||
self.listNode = ListView()
|
self.gridNode = GridNode()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.listNode)
|
self.addSubnode(self.gridNode)
|
||||||
|
|
||||||
self.listNode.beganInteractiveDragging = { [weak self] in
|
self.gridNode.scrollingInitiated = { [weak self] in
|
||||||
self?.scrollingInitiated?()
|
self?.scrollingInitiated?()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,28 +231,39 @@ final class ChatMediaInputTrendingPane: ChatMediaInputPane {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateLayout(size: CGSize, topInset: CGFloat, bottomInset: CGFloat, isExpanded: Bool, isVisible: Bool, transition: ContainedViewLayoutTransition) {
|
override func updateLayout(size: CGSize, topInset: CGFloat, bottomInset: CGFloat, isExpanded: Bool, isVisible: Bool, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition) {
|
||||||
let hadValidLayout = self.validLayout != nil
|
let hadValidLayout = self.validLayout != nil
|
||||||
self.validLayout = (size, bottomInset)
|
self.validLayout = (size, bottomInset)
|
||||||
|
|
||||||
transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size))
|
let itemSize: CGSize
|
||||||
|
if case .tablet = deviceMetrics.type, size.width > 480.0 {
|
||||||
var duration: Double = 0.0
|
itemSize = CGSize(width: floor(size.width / 2.0), height: 128.0)
|
||||||
var listViewCurve: ListViewAnimationCurve = .Default(duration: nil)
|
} else {
|
||||||
switch transition {
|
itemSize = CGSize(width: size.width, height: 128.0)
|
||||||
case .immediate:
|
|
||||||
break
|
|
||||||
case let .animated(animationDuration, animationCurve):
|
|
||||||
duration = animationDuration
|
|
||||||
switch animationCurve {
|
|
||||||
case .easeInOut, .custom:
|
|
||||||
listViewCurve = .Default(duration: duration)
|
|
||||||
case .spring:
|
|
||||||
listViewCurve = .Spring(duration: duration)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: size, insets: UIEdgeInsets(top: topInset, left: 0.0, bottom: bottomInset, right: 0.0), duration: duration, curve: listViewCurve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: size, insets: UIEdgeInsets(top: topInset, left: 0.0, bottom: bottomInset, right: 0.0), preloadSize: isVisible ? 300.0 : 0.0, type: .fixed(itemSize: itemSize, fillWidth: nil, lineSpacing: 0.0, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.gridNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height)))
|
||||||
|
|
||||||
|
// transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||||
|
//
|
||||||
|
// var duration: Double = 0.0
|
||||||
|
// var listViewCurve: ListViewAnimationCurve = .Default(duration: nil)
|
||||||
|
// switch transition {
|
||||||
|
// case .immediate:
|
||||||
|
// break
|
||||||
|
// case let .animated(animationDuration, animationCurve):
|
||||||
|
// duration = animationDuration
|
||||||
|
// switch animationCurve {
|
||||||
|
// case .easeInOut, .custom:
|
||||||
|
// listViewCurve = .Default(duration: duration)
|
||||||
|
// case .spring:
|
||||||
|
// listViewCurve = .Spring(duration: duration)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: size, insets: UIEdgeInsets(top: topInset, left: 0.0, bottom: bottomInset, right: 0.0), duration: duration, curve: listViewCurve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
|
||||||
if !hadValidLayout {
|
if !hadValidLayout {
|
||||||
while !self.enqueuedTransitions.isEmpty {
|
while !self.enqueuedTransitions.isEmpty {
|
||||||
@ -274,38 +292,28 @@ final class ChatMediaInputTrendingPane: ChatMediaInputPane {
|
|||||||
if let transition = self.enqueuedTransitions.first {
|
if let transition = self.enqueuedTransitions.first {
|
||||||
self.enqueuedTransitions.remove(at: 0)
|
self.enqueuedTransitions.remove(at: 0)
|
||||||
|
|
||||||
var options = ListViewDeleteAndInsertOptions()
|
let itemTransition: ContainedViewLayoutTransition = .immediate
|
||||||
if transition.initial {
|
self.gridNode.transaction(GridNodeTransaction(deleteItems: transition.deletions, insertItems: transition.insertions, updateItems: transition.updates, scrollToItem: nil, updateLayout: nil, itemTransition: itemTransition, stationaryItems: .none, updateFirstIndexInSectionOffset: nil, synchronousLoads: transition.initial), completion: { _ in })
|
||||||
options.insert(.Synchronous)
|
|
||||||
options.insert(.LowLatency)
|
|
||||||
options.insert(.PreferSynchronousResourceLoading)
|
|
||||||
} else {
|
|
||||||
options.insert(.AnimateInsertion)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { _ in
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func itemAt(point: CGPoint) -> (ASDisplayNode, StickerPackItem)? {
|
func itemAt(point: CGPoint) -> (ASDisplayNode, StickerPackItem)? {
|
||||||
let localPoint = self.view.convert(point, to: self.listNode.view)
|
let localPoint = self.view.convert(point, to: self.gridNode.view)
|
||||||
var resultNode: MediaInputPaneTrendingItemNode?
|
var resultNode: StickerPaneSearchGlobalItemNode?
|
||||||
self.listNode.forEachItemNode { itemNode in
|
self.gridNode.forEachItemNode { itemNode in
|
||||||
if itemNode.frame.contains(localPoint), let itemNode = itemNode as? MediaInputPaneTrendingItemNode {
|
if itemNode.frame.contains(localPoint), let itemNode = itemNode as? StickerPaneSearchGlobalItemNode {
|
||||||
resultNode = itemNode
|
resultNode = itemNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let resultNode = resultNode {
|
if let resultNode = resultNode {
|
||||||
return resultNode.itemAt(point: self.listNode.view.convert(localPoint, to: resultNode.view))
|
return resultNode.itemAt(point: self.gridNode.view.convert(localPoint, to: resultNode.view))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updatePreviewing(animated: Bool) {
|
func updatePreviewing(animated: Bool) {
|
||||||
self.listNode.forEachItemNode { itemNode in
|
self.gridNode.forEachItemNode { itemNode in
|
||||||
if let itemNode = itemNode as? MediaInputPaneTrendingItemNode {
|
if let itemNode = itemNode as? StickerPaneSearchGlobalItemNode {
|
||||||
itemNode.updatePreviewing(animated: animated)
|
itemNode.updatePreviewing(animated: animated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ struct ChatMessageItemBubbleLayoutConstants {
|
|||||||
let minimumSize: CGSize
|
let minimumSize: CGSize
|
||||||
let contentInsets: UIEdgeInsets
|
let contentInsets: UIEdgeInsets
|
||||||
let borderInset: CGFloat
|
let borderInset: CGFloat
|
||||||
|
let strokeInsets: UIEdgeInsets
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChatMessageItemTextLayoutConstants {
|
struct ChatMessageItemTextLayoutConstants {
|
||||||
@ -81,7 +82,7 @@ struct ChatMessageItemLayoutConstants {
|
|||||||
self.avatarDiameter = 37.0
|
self.avatarDiameter = 37.0
|
||||||
self.timestampHeaderHeight = 34.0
|
self.timestampHeaderHeight = 34.0
|
||||||
|
|
||||||
self.bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 1.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.85), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel)
|
self.bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 1.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.85), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0 - UIScreenPixel, left: 1.0 - UIScreenPixel, bottom: 1.0 - UIScreenPixel, right: 1.0 - UIScreenPixel))
|
||||||
self.text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
|
self.text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
|
||||||
self.image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 1.0 + UIScreenPixel, left: 1.0 + UIScreenPixel, bottom: 1.0 + UIScreenPixel, right: 1.0 + UIScreenPixel), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 17.0, mergedCornerRadius: 5.0, contentMergedCornerRadius: 5.0, maxDimensions: CGSize(width: 300.0, height: 300.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
self.image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 1.0 + UIScreenPixel, left: 1.0 + UIScreenPixel, bottom: 1.0 + UIScreenPixel, right: 1.0 + UIScreenPixel), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 17.0, mergedCornerRadius: 5.0, contentMergedCornerRadius: 5.0, maxDimensions: CGSize(width: 300.0, height: 300.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
||||||
self.video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)
|
self.video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)
|
||||||
|
@ -6,6 +6,7 @@ import SwiftSignalKit
|
|||||||
import Postbox
|
import Postbox
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
|
import TelegramPresentationData
|
||||||
import AccountContext
|
import AccountContext
|
||||||
import GridMessageSelectionNode
|
import GridMessageSelectionNode
|
||||||
|
|
||||||
@ -115,7 +116,17 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
switch preparePosition {
|
switch preparePosition {
|
||||||
case .linear:
|
case .linear:
|
||||||
if case .color = item.presentationData.theme.wallpaper {
|
if case .color = item.presentationData.theme.wallpaper {
|
||||||
|
let colors: PresentationThemeBubbleColorComponents
|
||||||
|
if item.message.effectivelyIncoming(item.context.account.peerId) {
|
||||||
|
colors = item.presentationData.theme.theme.chat.message.incoming.bubble.withoutWallpaper
|
||||||
|
} else {
|
||||||
|
colors = item.presentationData.theme.theme.chat.message.outgoing.bubble.withoutWallpaper
|
||||||
|
}
|
||||||
|
if colors.fill == colors.stroke {
|
||||||
bubbleInsets = UIEdgeInsets()
|
bubbleInsets = UIEdgeInsets()
|
||||||
|
} else {
|
||||||
|
bubbleInsets = layoutConstants.bubble.strokeInsets
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
bubbleInsets = layoutConstants.image.bubbleInsets
|
bubbleInsets = layoutConstants.image.bubbleInsets
|
||||||
}
|
}
|
||||||
|
@ -666,7 +666,6 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
|
|
||||||
func animateLayoutTransition() {
|
func animateLayoutTransition() {
|
||||||
UIView.transition(with: self, duration: 0.25, options: [.transitionCrossDissolve], animations: {
|
UIView.transition(with: self, duration: 0.25, options: [.transitionCrossDissolve], animations: {
|
||||||
|
|
||||||
}, completion: nil)
|
}, completion: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ final class GifPaneSearchContentNode: ASDisplayNode & PaneSearchContentNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, inputHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, inputHeight: CGFloat, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition) {
|
||||||
let firstLayout = self.validLayout == nil
|
let firstLayout = self.validLayout == nil
|
||||||
self.validLayout = size
|
self.validLayout = size
|
||||||
|
|
||||||
|
@ -51,6 +51,12 @@ final class MultiplexedVideoNode: ASScrollNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var idealHeight: CGFloat = 93.0 {
|
||||||
|
didSet {
|
||||||
|
self.setNeedsLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var files: [FileMediaReference] = [] {
|
var files: [FileMediaReference] = [] {
|
||||||
didSet {
|
didSet {
|
||||||
self.updateVisibleItems()
|
self.updateVisibleItems()
|
||||||
@ -341,7 +347,7 @@ final class MultiplexedVideoNode: ASScrollNode, UIScrollViewDelegate {
|
|||||||
if !drawableSize.width.isZero {
|
if !drawableSize.width.isZero {
|
||||||
var displayItems: [VisibleVideoItem] = []
|
var displayItems: [VisibleVideoItem] = []
|
||||||
|
|
||||||
let idealHeight: CGFloat = 93.0
|
let idealHeight = self.idealHeight
|
||||||
|
|
||||||
var weights: [Int] = []
|
var weights: [Int] = []
|
||||||
var totalItemSize: CGFloat = 0.0
|
var totalItemSize: CGFloat = 0.0
|
||||||
|
@ -17,7 +17,7 @@ protocol PaneSearchContentNode {
|
|||||||
|
|
||||||
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings)
|
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings)
|
||||||
func updateText(_ text: String, languageCode: String?)
|
func updateText(_ text: String, languageCode: String?)
|
||||||
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, inputHeight: CGFloat, transition: ContainedViewLayoutTransition)
|
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, inputHeight: CGFloat, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition)
|
||||||
|
|
||||||
func animateIn(additivePosition: CGFloat, transition: ContainedViewLayoutTransition)
|
func animateIn(additivePosition: CGFloat, transition: ContainedViewLayoutTransition)
|
||||||
func animateOut(transition: ContainedViewLayoutTransition)
|
func animateOut(transition: ContainedViewLayoutTransition)
|
||||||
@ -103,7 +103,7 @@ final class PaneSearchContainerNode: ASDisplayNode {
|
|||||||
return self.contentNode.itemAt(point: CGPoint(x: point.x, y: point.y - searchBarHeight))
|
return self.contentNode.itemAt(point: CGPoint(x: point.x, y: point.y - searchBarHeight))
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, inputHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, inputHeight: CGFloat, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition) {
|
||||||
self.validLayout = size
|
self.validLayout = size
|
||||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
|
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ final class PaneSearchContainerNode: ASDisplayNode {
|
|||||||
let contentFrame = CGRect(origin: CGPoint(x: leftInset, y: searchBarHeight), size: CGSize(width: size.width - leftInset - rightInset, height: size.height - searchBarHeight))
|
let contentFrame = CGRect(origin: CGPoint(x: leftInset, y: searchBarHeight), size: CGSize(width: size.width - leftInset - rightInset, height: size.height - searchBarHeight))
|
||||||
|
|
||||||
transition.updateFrame(node: self.contentNode, frame: contentFrame)
|
transition.updateFrame(node: self.contentNode, frame: contentFrame)
|
||||||
self.contentNode.updateLayout(size: contentFrame.size, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, inputHeight: inputHeight, transition: transition)
|
self.contentNode.updateLayout(size: contentFrame.size, leftInset: leftInset, rightInset: rightInset, bottomInset: bottomInset, inputHeight: inputHeight, deviceMetrics: deviceMetrics, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deactivate() {
|
func deactivate() {
|
||||||
|
@ -4,12 +4,13 @@ import AsyncDisplayKit
|
|||||||
import Display
|
import Display
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import SegmentedControlNode
|
||||||
|
|
||||||
final class PeerMediaCollectionSectionsNode: ASDisplayNode {
|
final class PeerMediaCollectionSectionsNode: ASDisplayNode {
|
||||||
private var theme: PresentationTheme
|
private var theme: PresentationTheme
|
||||||
private var strings: PresentationStrings
|
private var strings: PresentationStrings
|
||||||
|
|
||||||
private let segmentedControl: UISegmentedControl
|
private let segmentedControlNode: SegmentedControlNode
|
||||||
private let separatorNode: ASDisplayNode
|
private let separatorNode: ASDisplayNode
|
||||||
|
|
||||||
var indexUpdated: ((Int) -> Void)?
|
var indexUpdated: ((Int) -> Void)?
|
||||||
@ -18,14 +19,13 @@ final class PeerMediaCollectionSectionsNode: ASDisplayNode {
|
|||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
|
|
||||||
self.segmentedControl = UISegmentedControl(items: [
|
let items = [
|
||||||
strings.SharedMedia_CategoryMedia,
|
strings.SharedMedia_CategoryMedia,
|
||||||
strings.SharedMedia_CategoryDocs,
|
strings.SharedMedia_CategoryDocs,
|
||||||
strings.SharedMedia_CategoryLinks,
|
strings.SharedMedia_CategoryLinks,
|
||||||
strings.SharedMedia_CategoryOther
|
strings.SharedMedia_CategoryOther
|
||||||
])
|
]
|
||||||
self.segmentedControl.selectedSegmentIndex = 0
|
self.segmentedControlNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: theme), items: items.map { SegmentedControlItem(title: $0) }, selectedIndex: 0)
|
||||||
self.segmentedControl.tintColor = theme.rootController.navigationBar.accentTextColor
|
|
||||||
|
|
||||||
self.separatorNode = ASDisplayNode()
|
self.separatorNode = ASDisplayNode()
|
||||||
self.separatorNode.isLayerBacked = true
|
self.separatorNode.isLayerBacked = true
|
||||||
@ -34,22 +34,22 @@ final class PeerMediaCollectionSectionsNode: ASDisplayNode {
|
|||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.separatorNode)
|
|
||||||
self.view.addSubview(self.segmentedControl)
|
|
||||||
|
|
||||||
self.backgroundColor = self.theme.rootController.navigationBar.backgroundColor
|
self.backgroundColor = self.theme.rootController.navigationBar.backgroundColor
|
||||||
|
|
||||||
self.segmentedControl.addTarget(self, action: #selector(indexChanged), for: .valueChanged)
|
self.segmentedControlNode.selectedIndexChanged = { [weak self] index in
|
||||||
|
self?.indexUpdated?(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.addSubnode(self.separatorNode)
|
||||||
|
self.addSubnode(self.segmentedControlNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: PeerMediaCollectionInterfaceState) -> CGFloat {
|
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: PeerMediaCollectionInterfaceState) -> CGFloat {
|
||||||
let panelHeight: CGFloat = 39.0 + additionalInset
|
let panelHeight: CGFloat = 39.0 + additionalInset
|
||||||
|
|
||||||
let controlHeight: CGFloat = 29.0
|
|
||||||
let sideInset: CGFloat = 8.0
|
let sideInset: CGFloat = 8.0
|
||||||
transition.animateView {
|
|
||||||
self.segmentedControl.frame = CGRect(origin: CGPoint(x: sideInset + leftInset, y: panelHeight - 11.0 - controlHeight), size: CGSize(width: width - sideInset * 2.0 - leftInset - rightInset, height: controlHeight))
|
let controlSize = self.segmentedControlNode.updateLayout(.stretchToFill(width: width - sideInset * 2.0 - leftInset - rightInset), transition: transition)
|
||||||
}
|
transition.updateFrame(node: self.segmentedControlNode, frame: CGRect(origin: CGPoint(x: sideInset + leftInset, y: panelHeight - 8.0 - controlSize.height), size: controlSize))
|
||||||
|
|
||||||
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel)))
|
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel)))
|
||||||
|
|
||||||
@ -57,13 +57,9 @@ final class PeerMediaCollectionSectionsNode: ASDisplayNode {
|
|||||||
self.theme = interfaceState.theme
|
self.theme = interfaceState.theme
|
||||||
self.separatorNode.backgroundColor = self.theme.rootController.navigationBar.separatorColor
|
self.separatorNode.backgroundColor = self.theme.rootController.navigationBar.separatorColor
|
||||||
self.backgroundColor = self.theme.rootController.navigationBar.backgroundColor
|
self.backgroundColor = self.theme.rootController.navigationBar.backgroundColor
|
||||||
self.segmentedControl.tintColor = theme.rootController.navigationBar.accentTextColor
|
self.segmentedControlNode.updateTheme(SegmentedControlTheme(theme: self.theme))
|
||||||
}
|
}
|
||||||
|
|
||||||
return panelHeight
|
return panelHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func indexChanged() {
|
|
||||||
self.indexUpdated?(self.segmentedControl.selectedSegmentIndex)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import SearchBarNode
|
|||||||
import SearchUI
|
import SearchUI
|
||||||
import ContactListUI
|
import ContactListUI
|
||||||
import ChatListUI
|
import ChatListUI
|
||||||
|
import SegmentedControlNode
|
||||||
|
|
||||||
final class PeerSelectionControllerNode: ASDisplayNode {
|
final class PeerSelectionControllerNode: ASDisplayNode {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
@ -28,7 +29,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
private let toolbarBackgroundNode: ASDisplayNode?
|
private let toolbarBackgroundNode: ASDisplayNode?
|
||||||
private let toolbarSeparatorNode: ASDisplayNode?
|
private let toolbarSeparatorNode: ASDisplayNode?
|
||||||
private let segmentedControl: UISegmentedControl?
|
private let segmentedControlNode: SegmentedControlNode?
|
||||||
|
|
||||||
var contactListNode: ContactListNode?
|
var contactListNode: ContactListNode?
|
||||||
let chatListNode: ChatListNode
|
let chatListNode: ChatListNode
|
||||||
@ -71,13 +72,15 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
self.toolbarSeparatorNode = ASDisplayNode()
|
self.toolbarSeparatorNode = ASDisplayNode()
|
||||||
self.toolbarSeparatorNode?.backgroundColor = self.presentationData.theme.rootController.navigationBar.separatorColor
|
self.toolbarSeparatorNode?.backgroundColor = self.presentationData.theme.rootController.navigationBar.separatorColor
|
||||||
|
|
||||||
self.segmentedControl = UISegmentedControl(items: [self.presentationData.strings.DialogList_TabTitle, self.presentationData.strings.Contacts_TabTitle])
|
let items = [
|
||||||
self.segmentedControl?.tintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor
|
self.presentationData.strings.DialogList_TabTitle,
|
||||||
self.segmentedControl?.selectedSegmentIndex = 0
|
self.presentationData.strings.Contacts_TabTitle
|
||||||
|
]
|
||||||
|
self.segmentedControlNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: self.presentationData.theme), items: items.map { SegmentedControlItem(title: $0) }, selectedIndex: 0)
|
||||||
} else {
|
} else {
|
||||||
self.toolbarBackgroundNode = nil
|
self.toolbarBackgroundNode = nil
|
||||||
self.toolbarSeparatorNode = nil
|
self.toolbarSeparatorNode = nil
|
||||||
self.segmentedControl = nil
|
self.segmentedControlNode = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -121,10 +124,13 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if hasContactSelector {
|
if hasContactSelector {
|
||||||
|
self.segmentedControlNode!.selectedIndexChanged = { [weak self] index in
|
||||||
|
self?.indexChanged(index)
|
||||||
|
}
|
||||||
|
|
||||||
self.addSubnode(self.toolbarBackgroundNode!)
|
self.addSubnode(self.toolbarBackgroundNode!)
|
||||||
self.addSubnode(self.toolbarSeparatorNode!)
|
self.addSubnode(self.toolbarSeparatorNode!)
|
||||||
self.view.addSubview(self.segmentedControl!)
|
self.addSubnode(self.segmentedControlNode!)
|
||||||
self.segmentedControl!.addTarget(self, action: #selector(indexChanged), for: .valueChanged)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -142,7 +148,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.toolbarBackgroundNode?.backgroundColor = self.presentationData.theme.rootController.navigationBar.backgroundColor
|
self.toolbarBackgroundNode?.backgroundColor = self.presentationData.theme.rootController.navigationBar.backgroundColor
|
||||||
self.toolbarSeparatorNode?.backgroundColor = self.presentationData.theme.rootController.navigationBar.separatorColor
|
self.toolbarSeparatorNode?.backgroundColor = self.presentationData.theme.rootController.navigationBar.separatorColor
|
||||||
self.segmentedControl?.tintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor
|
self.segmentedControlNode?.updateTheme(SegmentedControlTheme(theme: self.presentationData.theme))
|
||||||
}
|
}
|
||||||
|
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, actualNavigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, actualNavigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
@ -152,14 +158,13 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
var toolbarHeight: CGFloat = cleanInsets.bottom
|
var toolbarHeight: CGFloat = cleanInsets.bottom
|
||||||
|
|
||||||
if let segmentedControl = segmentedControl, let toolbarBackgroundNode = toolbarBackgroundNode, let toolbarSeparatorNode = toolbarSeparatorNode {
|
if let segmentedControlNode = self.segmentedControlNode, let toolbarBackgroundNode = self.toolbarBackgroundNode, let toolbarSeparatorNode = self.toolbarSeparatorNode {
|
||||||
toolbarHeight += 44
|
toolbarHeight += 44
|
||||||
transition.updateFrame(node: toolbarBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: toolbarHeight)))
|
transition.updateFrame(node: toolbarBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: toolbarHeight)))
|
||||||
transition.updateFrame(node: toolbarSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
transition.updateFrame(node: toolbarSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
||||||
|
|
||||||
var controlSize = segmentedControl.sizeThatFits(layout.size)
|
let controlSize = segmentedControlNode.updateLayout(.sizeToFit(maximumWidth: layout.size.width, minimumWidth: 200.0), transition: transition)
|
||||||
controlSize.width = min(layout.size.width, max(200.0, controlSize.width))
|
transition.updateFrame(node: segmentedControlNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - controlSize.width) / 2.0), y: layout.size.height - toolbarHeight + floor((44.0 - controlSize.height) / 2.0)), size: controlSize))
|
||||||
transition.updateFrame(view: segmentedControl, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - controlSize.width) / 2.0), y: layout.size.height - toolbarHeight + floor((44.0 - controlSize.height) / 2.0)), size: controlSize))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var insets = layout.insets(options: [.input])
|
var insets = layout.insets(options: [.input])
|
||||||
@ -318,12 +323,12 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func indexChanged() {
|
private func indexChanged(_ index: Int) {
|
||||||
guard let (layout, navigationHeight, actualNavigationHeight) = self.containerLayout, let segmentedControl = self.segmentedControl else {
|
guard let (layout, navigationHeight, actualNavigationHeight) = self.containerLayout else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let contactListActive = segmentedControl.selectedSegmentIndex == 1
|
let contactListActive = index == 1
|
||||||
if contactListActive != self.contactListActive {
|
if contactListActive != self.contactListActive {
|
||||||
self.contactListActive = contactListActive
|
self.contactListActive = contactListActive
|
||||||
if contactListActive {
|
if contactListActive {
|
||||||
|
@ -99,7 +99,7 @@ private enum StickerSearchEntry: Identifiable, Comparable {
|
|||||||
interaction.sendSticker(.standalone(media: stickerItem.file), node, rect)
|
interaction.sendSticker(.standalone(media: stickerItem.file), node, rect)
|
||||||
})
|
})
|
||||||
case let .global(_, info, topItems, installed):
|
case let .global(_, info, topItems, installed):
|
||||||
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, info: info, topItems: topItems, installed: installed, unread: false, open: {
|
return StickerPaneSearchGlobalItem(account: account, theme: theme, strings: strings, info: info, topItems: topItems, grid: false, installed: installed, unread: false, open: {
|
||||||
interaction.open(info)
|
interaction.open(info)
|
||||||
}, install: {
|
}, install: {
|
||||||
interaction.install(info)
|
interaction.install(info)
|
||||||
@ -247,7 +247,7 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
|
|||||||
}
|
}
|
||||||
}, sendSticker: { [weak self] file, sourceNode, sourceRect in
|
}, sendSticker: { [weak self] file, sourceNode, sourceRect in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.controllerInteraction.sendSticker(file, false, sourceNode, sourceRect)
|
let _ = strongSelf.controllerInteraction.sendSticker(file, false, sourceNode, sourceRect)
|
||||||
}
|
}
|
||||||
}, getItemIsPreviewed: { item in
|
}, getItemIsPreviewed: { item in
|
||||||
return inputNodeInteraction.previewedStickerPackItem == .pack(item)
|
return inputNodeInteraction.previewedStickerPackItem == .pack(item)
|
||||||
@ -460,7 +460,7 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, inputHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, inputHeight: CGFloat, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition) {
|
||||||
let firstLayout = self.validLayout == nil
|
let firstLayout = self.validLayout == nil
|
||||||
|
|
||||||
self.validLayout = size
|
self.validLayout = size
|
||||||
@ -478,7 +478,7 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
|
|||||||
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: contentFrame.size, insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0 + bottomInset, right: 0.0), preloadSize: 300.0, type: .fixed(itemSize: CGSize(width: 75.0, height: 75.0), fillWidth: nil, lineSpacing: 0.0, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: contentFrame.size, insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0 + bottomInset, right: 0.0), preloadSize: 300.0, type: .fixed(itemSize: CGSize(width: 75.0, height: 75.0), fillWidth: nil, lineSpacing: 0.0, itemSpacing: nil)), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
||||||
|
|
||||||
transition.updateFrame(node: self.trendingPane, frame: contentFrame)
|
transition.updateFrame(node: self.trendingPane, frame: contentFrame)
|
||||||
self.trendingPane.updateLayout(size: contentFrame.size, topInset: 0.0, bottomInset: bottomInset, isExpanded: false, isVisible: true, transition: transition)
|
self.trendingPane.updateLayout(size: contentFrame.size, topInset: 0.0, bottomInset: bottomInset, isExpanded: false, isVisible: true, deviceMetrics: deviceMetrics, transition: transition)
|
||||||
|
|
||||||
transition.updateFrame(node: self.gridNode, frame: contentFrame)
|
transition.updateFrame(node: self.gridNode, frame: contentFrame)
|
||||||
if firstLayout {
|
if firstLayout {
|
||||||
|
@ -37,6 +37,7 @@ final class StickerPaneSearchGlobalItem: GridItem {
|
|||||||
let strings: PresentationStrings
|
let strings: PresentationStrings
|
||||||
let info: StickerPackCollectionInfo
|
let info: StickerPackCollectionInfo
|
||||||
let topItems: [StickerPackItem]
|
let topItems: [StickerPackItem]
|
||||||
|
let grid: Bool
|
||||||
let installed: Bool
|
let installed: Bool
|
||||||
let unread: Bool
|
let unread: Bool
|
||||||
let open: () -> Void
|
let open: () -> Void
|
||||||
@ -44,14 +45,17 @@ final class StickerPaneSearchGlobalItem: GridItem {
|
|||||||
let getItemIsPreviewed: (StickerPackItem) -> Bool
|
let getItemIsPreviewed: (StickerPackItem) -> Bool
|
||||||
|
|
||||||
let section: GridSection? = StickerPaneSearchGlobalSection()
|
let section: GridSection? = StickerPaneSearchGlobalSection()
|
||||||
let fillsRowWithHeight: CGFloat? = 128.0
|
var fillsRowWithHeight: CGFloat? {
|
||||||
|
return self.grid ? nil : 128.0
|
||||||
|
}
|
||||||
|
|
||||||
init(account: Account, theme: PresentationTheme, strings: PresentationStrings, info: StickerPackCollectionInfo, topItems: [StickerPackItem], installed: Bool, unread: Bool, open: @escaping () -> Void, install: @escaping () -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool) {
|
init(account: Account, theme: PresentationTheme, strings: PresentationStrings, info: StickerPackCollectionInfo, topItems: [StickerPackItem], grid: Bool, installed: Bool, unread: Bool, open: @escaping () -> Void, install: @escaping () -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool) {
|
||||||
self.account = account
|
self.account = account
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.info = info
|
self.info = info
|
||||||
self.topItems = topItems
|
self.topItems = topItems
|
||||||
|
self.grid = grid
|
||||||
self.installed = installed
|
self.installed = installed
|
||||||
self.unread = unread
|
self.unread = unread
|
||||||
self.open = open
|
self.open = open
|
||||||
|
@ -126,7 +126,6 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
|
|||||||
private var enqueuedTransitions: [(VerticalListContextResultsChatInputContextPanelTransition, Bool)] = []
|
private var enqueuedTransitions: [(VerticalListContextResultsChatInputContextPanelTransition, Bool)] = []
|
||||||
private var validLayout: (CGSize, CGFloat, CGFloat)?
|
private var validLayout: (CGSize, CGFloat, CGFloat)?
|
||||||
|
|
||||||
|
|
||||||
override init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings) {
|
override init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings) {
|
||||||
self.listView = ListView()
|
self.listView = ListView()
|
||||||
self.listView.isOpaque = false
|
self.listView.isOpaque = false
|
||||||
|
@ -8,6 +8,7 @@ import Postbox
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import RadialStatusNode
|
import RadialStatusNode
|
||||||
import PhotoResources
|
import PhotoResources
|
||||||
|
import StickerResources
|
||||||
|
|
||||||
final class VerticalListContextResultsChatInputPanelItem: ListViewItem {
|
final class VerticalListContextResultsChatInputPanelItem: ListViewItem {
|
||||||
fileprivate let account: Account
|
fileprivate let account: Account
|
||||||
@ -165,7 +166,6 @@ final class VerticalListContextResultsChatInputPanelItemNode: ListViewItemNode {
|
|||||||
var textString: NSAttributedString?
|
var textString: NSAttributedString?
|
||||||
var iconText: NSAttributedString?
|
var iconText: NSAttributedString?
|
||||||
|
|
||||||
var iconImageRepresentation: TelegramMediaImageRepresentation?
|
|
||||||
var updateIconImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?
|
var updateIconImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?
|
||||||
var updatedStatusSignal: Signal<MediaResourceStatus, NoError>?
|
var updatedStatusSignal: Signal<MediaResourceStatus, NoError>?
|
||||||
|
|
||||||
@ -178,8 +178,9 @@ final class VerticalListContextResultsChatInputPanelItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var imageResource: TelegramMediaResource?
|
var imageResource: TelegramMediaResource?
|
||||||
|
var stickerFile: TelegramMediaFile?
|
||||||
switch item.result {
|
switch item.result {
|
||||||
case let .externalReference(_, _, _, title, _, url, content, thumbnail, _):
|
case let .externalReference(_, _, _, _, _, url, content, thumbnail, _):
|
||||||
if let thumbnail = thumbnail {
|
if let thumbnail = thumbnail {
|
||||||
imageResource = thumbnail.resource
|
imageResource = thumbnail.resource
|
||||||
}
|
}
|
||||||
@ -198,13 +199,18 @@ final class VerticalListContextResultsChatInputPanelItemNode: ListViewItemNode {
|
|||||||
iconText = NSAttributedString(string: host.substring(to: host.index(after: host.startIndex)).uppercased(), font: iconFont, textColor: UIColor.white)
|
iconText = NSAttributedString(string: host.substring(to: host.index(after: host.startIndex)).uppercased(), font: iconFont, textColor: UIColor.white)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .internalReference(_, _, _, title, _, image, file, _):
|
case let .internalReference(_, _, _, _, _, image, file, _):
|
||||||
if let image = image {
|
if let image = image {
|
||||||
imageResource = imageRepresentationLargerThan(image.representations, size: CGSize(width: 200.0, height: 200.0))?.resource
|
imageResource = imageRepresentationLargerThan(image.representations, size: CGSize(width: 200.0, height: 200.0))?.resource
|
||||||
} else if let file = file {
|
} else if let file = file {
|
||||||
|
if file.isSticker {
|
||||||
|
stickerFile = file
|
||||||
|
imageResource = file.resource
|
||||||
|
} else {
|
||||||
imageResource = smallestImageRepresentation(file.previewRepresentations)?.resource
|
imageResource = smallestImageRepresentation(file.previewRepresentations)?.resource
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if iconText == nil {
|
if iconText == nil {
|
||||||
if let title = item.result.title, !title.isEmpty {
|
if let title = item.result.title, !title.isEmpty {
|
||||||
@ -215,9 +221,15 @@ final class VerticalListContextResultsChatInputPanelItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
var iconImageApply: (() -> Void)?
|
var iconImageApply: (() -> Void)?
|
||||||
if let imageResource = imageResource {
|
if let imageResource = imageResource {
|
||||||
let iconSize = CGSize(width: 55.0, height: 55.0)
|
let boundingSize = CGSize(width: 55.0, height: 55.0)
|
||||||
|
let iconSize: CGSize
|
||||||
|
if let stickerFile = stickerFile, let dimensions = stickerFile.dimensions {
|
||||||
|
iconSize = dimensions.fitted(boundingSize)
|
||||||
|
} else {
|
||||||
|
iconSize = boundingSize
|
||||||
|
}
|
||||||
let imageCorners = ImageCorners(topLeft: .Corner(2.0), topRight: .Corner(2.0), bottomLeft: .Corner(2.0), bottomRight: .Corner(2.0))
|
let imageCorners = ImageCorners(topLeft: .Corner(2.0), topRight: .Corner(2.0), bottomLeft: .Corner(2.0), bottomRight: .Corner(2.0))
|
||||||
let arguments = TransformImageArguments(corners: imageCorners, imageSize: iconSize, boundingSize: iconSize, intrinsicInsets: UIEdgeInsets())
|
let arguments = TransformImageArguments(corners: imageCorners, imageSize: iconSize, boundingSize: boundingSize, intrinsicInsets: UIEdgeInsets())
|
||||||
iconImageApply = iconImageLayout(arguments)
|
iconImageApply = iconImageLayout(arguments)
|
||||||
|
|
||||||
updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(imageResource)
|
updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(imageResource)
|
||||||
@ -235,9 +247,13 @@ final class VerticalListContextResultsChatInputPanelItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
if updatedIconImageResource {
|
if updatedIconImageResource {
|
||||||
if let imageResource = imageResource {
|
if let imageResource = imageResource {
|
||||||
|
if let stickerFile = stickerFile {
|
||||||
|
updateIconImageSignal = chatMessageSticker(account: item.account, file: stickerFile, small: false, fetched: true)
|
||||||
|
} else {
|
||||||
let tmpRepresentation = TelegramMediaImageRepresentation(dimensions: CGSize(width: 55.0, height: 55.0), resource: imageResource)
|
let tmpRepresentation = TelegramMediaImageRepresentation(dimensions: CGSize(width: 55.0, height: 55.0), resource: imageResource)
|
||||||
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
||||||
updateIconImageSignal = chatWebpageSnippetPhoto(account: item.account, photoReference: .standalone(media: tmpImage))
|
updateIconImageSignal = chatWebpageSnippetPhoto(account: item.account, photoReference: .standalone(media: tmpImage))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
updateIconImageSignal = .complete()
|
updateIconImageSignal = .complete()
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import MergeLists
|
|||||||
import AccountContext
|
import AccountContext
|
||||||
import GalleryUI
|
import GalleryUI
|
||||||
import ChatListSearchItemHeader
|
import ChatListSearchItemHeader
|
||||||
|
import SegmentedControlNode
|
||||||
|
|
||||||
private struct WebSearchContextResultStableId: Hashable {
|
private struct WebSearchContextResultStableId: Hashable {
|
||||||
let result: ChatContextResult
|
let result: ChatContextResult
|
||||||
@ -135,7 +136,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
private let segmentedBackgroundNode: ASDisplayNode
|
private let segmentedBackgroundNode: ASDisplayNode
|
||||||
private let segmentedSeparatorNode: ASDisplayNode
|
private let segmentedSeparatorNode: ASDisplayNode
|
||||||
private let segmentedControl: UISegmentedControl
|
private let segmentedControlNode: SegmentedControlNode
|
||||||
|
|
||||||
private let toolbarBackgroundNode: ASDisplayNode
|
private let toolbarBackgroundNode: ASDisplayNode
|
||||||
private let toolbarSeparatorNode: ASDisplayNode
|
private let toolbarSeparatorNode: ASDisplayNode
|
||||||
@ -189,8 +190,11 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
self.segmentedBackgroundNode = ASDisplayNode()
|
self.segmentedBackgroundNode = ASDisplayNode()
|
||||||
self.segmentedSeparatorNode = ASDisplayNode()
|
self.segmentedSeparatorNode = ASDisplayNode()
|
||||||
|
|
||||||
self.segmentedControl = UISegmentedControl(items: [strings.WebSearch_Images, strings.WebSearch_GIFs])
|
let items = [
|
||||||
self.segmentedControl.selectedSegmentIndex = 0
|
strings.WebSearch_Images,
|
||||||
|
strings.WebSearch_GIFs
|
||||||
|
]
|
||||||
|
self.segmentedControlNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: theme), items: items.map { SegmentedControlItem(title: $0) }, selectedIndex: 0)
|
||||||
|
|
||||||
self.toolbarBackgroundNode = ASDisplayNode()
|
self.toolbarBackgroundNode = ASDisplayNode()
|
||||||
self.toolbarSeparatorNode = ASDisplayNode()
|
self.toolbarSeparatorNode = ASDisplayNode()
|
||||||
@ -221,7 +225,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
self.addSubnode(self.segmentedBackgroundNode)
|
self.addSubnode(self.segmentedBackgroundNode)
|
||||||
self.addSubnode(self.segmentedSeparatorNode)
|
self.addSubnode(self.segmentedSeparatorNode)
|
||||||
if case .media = mode {
|
if case .media = mode {
|
||||||
self.view.addSubview(self.segmentedControl)
|
self.addSubnode(self.segmentedControlNode)
|
||||||
}
|
}
|
||||||
self.addSubnode(self.toolbarBackgroundNode)
|
self.addSubnode(self.toolbarBackgroundNode)
|
||||||
self.addSubnode(self.toolbarSeparatorNode)
|
self.addSubnode(self.toolbarSeparatorNode)
|
||||||
@ -230,7 +234,16 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
self.addSubnode(self.attributionNode)
|
self.addSubnode(self.attributionNode)
|
||||||
self.addSubnode(self.badgeNode)
|
self.addSubnode(self.badgeNode)
|
||||||
|
|
||||||
self.segmentedControl.addTarget(self, action: #selector(self.indexChanged), for: .valueChanged)
|
self.segmentedControlNode.selectedIndexChanged = { [weak self] index in
|
||||||
|
if let strongSelf = self, let scope = WebSearchScope(rawValue: Int32(index)) {
|
||||||
|
let _ = updateWebSearchSettingsInteractively(accountManager: strongSelf.context.sharedContext.accountManager) { _ -> WebSearchSettings in
|
||||||
|
return WebSearchSettings(scope: scope)
|
||||||
|
}.start()
|
||||||
|
strongSelf.requestUpdateInterfaceState(true) { current in
|
||||||
|
return current.withUpdatedScope(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
self.cancelButton.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside)
|
self.cancelButton.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside)
|
||||||
self.sendButton.addTarget(self, action: #selector(self.sendPressed), forControlEvents: .touchUpInside)
|
self.sendButton.addTarget(self, action: #selector(self.sendPressed), forControlEvents: .touchUpInside)
|
||||||
|
|
||||||
@ -334,7 +347,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.segmentedBackgroundNode.backgroundColor = self.theme.rootController.navigationBar.backgroundColor
|
self.segmentedBackgroundNode.backgroundColor = self.theme.rootController.navigationBar.backgroundColor
|
||||||
self.segmentedSeparatorNode.backgroundColor = self.theme.rootController.navigationBar.separatorColor
|
self.segmentedSeparatorNode.backgroundColor = self.theme.rootController.navigationBar.separatorColor
|
||||||
self.segmentedControl.tintColor = self.theme.rootController.navigationBar.accentTextColor
|
self.segmentedControlNode.updateTheme(SegmentedControlTheme(theme: self.theme))
|
||||||
self.toolbarBackgroundNode.backgroundColor = self.theme.rootController.navigationBar.backgroundColor
|
self.toolbarBackgroundNode.backgroundColor = self.theme.rootController.navigationBar.backgroundColor
|
||||||
self.toolbarSeparatorNode.backgroundColor = self.theme.rootController.navigationBar.separatorColor
|
self.toolbarSeparatorNode.backgroundColor = self.theme.rootController.navigationBar.separatorColor
|
||||||
|
|
||||||
@ -358,16 +371,14 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
var insets = layout.insets(options: [.input])
|
var insets = layout.insets(options: [.input])
|
||||||
insets.top += navigationBarHeight
|
insets.top += navigationBarHeight
|
||||||
|
|
||||||
let segmentedHeight: CGFloat = self.segmentedControl.superview != nil ? 44.0 : 5.0
|
let segmentedHeight: CGFloat = self.segmentedControlNode.supernode != nil ? 44.0 : 5.0
|
||||||
let panelY: CGFloat = insets.top - UIScreenPixel - 4.0
|
let panelY: CGFloat = insets.top - UIScreenPixel - 4.0
|
||||||
|
|
||||||
transition.updateFrame(node: self.segmentedBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY), size: CGSize(width: layout.size.width, height: segmentedHeight)))
|
transition.updateFrame(node: self.segmentedBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY), size: CGSize(width: layout.size.width, height: segmentedHeight)))
|
||||||
transition.updateFrame(node: self.segmentedSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY + segmentedHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
transition.updateFrame(node: self.segmentedSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY + segmentedHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
||||||
|
|
||||||
var controlSize = self.segmentedControl.sizeThatFits(layout.size)
|
let controlSize = self.segmentedControlNode.updateLayout(.stretchToFill(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 10.0 * 2.0), transition: transition)
|
||||||
controlSize.width = layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 10.0 * 2.0
|
transition.updateFrame(node: self.segmentedControlNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - controlSize.width) / 2.0), y: panelY + 5.0), size: controlSize))
|
||||||
|
|
||||||
transition.updateFrame(view: self.segmentedControl, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - controlSize.width) / 2.0), y: panelY + 5.0), size: controlSize))
|
|
||||||
|
|
||||||
insets.top -= 4.0
|
insets.top -= 4.0
|
||||||
|
|
||||||
@ -471,7 +482,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
self.webSearchInterfaceStatePromise.set(self.webSearchInterfaceState)
|
self.webSearchInterfaceStatePromise.set(self.webSearchInterfaceState)
|
||||||
|
|
||||||
if let state = interfaceState.state {
|
if let state = interfaceState.state {
|
||||||
self.segmentedControl.selectedSegmentIndex = Int(state.scope.rawValue)
|
self.segmentedControlNode.selectedIndex = Int(state.scope.rawValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let validLayout = self.containerLayout {
|
if let validLayout = self.containerLayout {
|
||||||
@ -656,17 +667,6 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func indexChanged() {
|
|
||||||
if let scope = WebSearchScope(rawValue: Int32(self.segmentedControl.selectedSegmentIndex)) {
|
|
||||||
let _ = updateWebSearchSettingsInteractively(accountManager: self.context.sharedContext.accountManager) { _ -> WebSearchSettings in
|
|
||||||
return WebSearchSettings(scope: scope)
|
|
||||||
}.start()
|
|
||||||
self.requestUpdateInterfaceState(true) { current in
|
|
||||||
return current.withUpdatedScope(scope)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func cancelPressed() {
|
@objc private func cancelPressed() {
|
||||||
self.cancel?()
|
self.cancel?()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user