mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2026-01-03 19:54:31 +00:00
Add credibility icon for voice chat participants
Add segmented control in share menu
This commit is contained in:
@@ -26,6 +26,7 @@ swift_library(
|
||||
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
|
||||
"//submodules/TelegramIntents:TelegramIntents",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/SegmentedControlNode:SegmentedControlNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
||||
@@ -39,6 +39,13 @@ public enum ShareControllerExternalStatus {
|
||||
case done
|
||||
}
|
||||
|
||||
public struct ShareControllerSegmentedValue {
|
||||
let title: String
|
||||
let subject: ShareControllerSubject
|
||||
let actionTitle: String
|
||||
let formatSendTitle: (Int) -> String
|
||||
}
|
||||
|
||||
public enum ShareControllerSubject {
|
||||
case url(String)
|
||||
case text(String)
|
||||
@@ -293,8 +300,7 @@ public final class ShareController: ViewController {
|
||||
private let presetText: String?
|
||||
private let switchableAccounts: [AccountWithInfo]
|
||||
private let immediatePeerId: PeerId?
|
||||
private let openStats: (() -> Void)?
|
||||
private let shares: Int?
|
||||
private let segmentedValues: [ShareControllerSegmentedValue]?
|
||||
private let fromForeignApp: Bool
|
||||
|
||||
private let peers = Promise<([(RenderedPeer, PeerPresence?)], Peer)>()
|
||||
@@ -314,11 +320,11 @@ public final class ShareController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
public convenience init(context: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, openStats: (() -> Void)? = nil, fromForeignApp: Bool = false, shares: Int? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forcedTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) {
|
||||
self.init(sharedContext: context.sharedContext, currentContext: context, subject: subject, presetText: presetText, preferredAction: preferredAction, showInChat: showInChat, openStats: openStats, fromForeignApp: fromForeignApp, shares: shares, externalShare: externalShare, immediateExternalShare: immediateExternalShare, switchableAccounts: switchableAccounts, immediatePeerId: immediatePeerId, forcedTheme: forcedTheme, forcedActionTitle: forcedActionTitle)
|
||||
public convenience init(context: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forcedTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) {
|
||||
self.init(sharedContext: context.sharedContext, currentContext: context, subject: subject, presetText: presetText, preferredAction: preferredAction, showInChat: showInChat, fromForeignApp: fromForeignApp, segmentedValues: segmentedValues, externalShare: externalShare, immediateExternalShare: immediateExternalShare, switchableAccounts: switchableAccounts, immediatePeerId: immediatePeerId, forcedTheme: forcedTheme, forcedActionTitle: forcedActionTitle)
|
||||
}
|
||||
|
||||
public init(sharedContext: SharedAccountContext, currentContext: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, openStats: (() -> Void)? = nil, fromForeignApp: Bool = false, shares: Int? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forcedTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) {
|
||||
public init(sharedContext: SharedAccountContext, currentContext: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forcedTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) {
|
||||
self.sharedContext = sharedContext
|
||||
self.currentContext = currentContext
|
||||
self.currentAccount = currentContext.account
|
||||
@@ -328,9 +334,8 @@ public final class ShareController: ViewController {
|
||||
self.immediateExternalShare = immediateExternalShare
|
||||
self.switchableAccounts = switchableAccounts
|
||||
self.immediatePeerId = immediatePeerId
|
||||
self.openStats = openStats
|
||||
self.fromForeignApp = fromForeignApp
|
||||
self.shares = shares
|
||||
self.segmentedValues = segmentedValues
|
||||
self.forcedTheme = forcedTheme
|
||||
|
||||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
@@ -468,7 +473,7 @@ public final class ShareController: ViewController {
|
||||
return
|
||||
}
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: title, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, externalShare: self.externalShare, immediateExternalShare: self.immediateExternalShare, immediatePeerId: self.immediatePeerId, shares: self.shares, fromForeignApp: self.fromForeignApp, forcedTheme: self.forcedTheme)
|
||||
}, externalShare: self.externalShare, immediateExternalShare: self.immediateExternalShare, immediatePeerId: self.immediatePeerId, fromForeignApp: self.fromForeignApp, forcedTheme: self.forcedTheme, segmentedValues: self.segmentedValues)
|
||||
self.controllerNode.completed = self.completed
|
||||
self.controllerNode.dismiss = { [weak self] shared in
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
@@ -770,11 +775,6 @@ public final class ShareController: ViewController {
|
||||
strongSelf.view.endEditing(true)
|
||||
strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
if case .messages = self.subject, let openStats = self.openStats {
|
||||
self.controllerNode.openStats = {
|
||||
openStats()
|
||||
}
|
||||
}
|
||||
self.displayNodeDidLoad()
|
||||
|
||||
self.peersDisposable.set((self.peers.get()
|
||||
|
||||
@@ -29,8 +29,9 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
private let externalShare: Bool
|
||||
private let immediateExternalShare: Bool
|
||||
private var immediatePeerId: PeerId?
|
||||
private let shares: Int?
|
||||
private let fromForeignApp: Bool
|
||||
private let segmentedValues: [ShareControllerSegmentedValue]?
|
||||
private var selectedSegmentedIndex: Int = 0
|
||||
|
||||
private let defaultAction: ShareControllerAction?
|
||||
private let requestLayout: (ContainedViewLayoutTransition) -> Void
|
||||
@@ -79,16 +80,16 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
|
||||
private let presetText: String?
|
||||
|
||||
init(sharedContext: SharedAccountContext, presetText: String?, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool, immediatePeerId: PeerId?, shares: Int?, fromForeignApp: Bool, forcedTheme: PresentationTheme?) {
|
||||
init(sharedContext: SharedAccountContext, presetText: String?, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool, immediatePeerId: PeerId?, fromForeignApp: Bool, forcedTheme: PresentationTheme?, segmentedValues: [ShareControllerSegmentedValue]?) {
|
||||
self.sharedContext = sharedContext
|
||||
self.presentationData = sharedContext.currentPresentationData.with { $0 }
|
||||
self.forcedTheme = forcedTheme
|
||||
self.externalShare = externalShare
|
||||
self.immediateExternalShare = immediateExternalShare
|
||||
self.immediatePeerId = immediatePeerId
|
||||
self.shares = shares
|
||||
self.fromForeignApp = fromForeignApp
|
||||
self.presentError = presentError
|
||||
self.segmentedValues = segmentedValues
|
||||
|
||||
self.presetText = presetText
|
||||
|
||||
@@ -700,7 +701,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
let animated = self.peersContentNode == nil
|
||||
let peersContentNode = SharePeersContainerNode(sharedContext: self.sharedContext, context: context, switchableAccounts: switchableAccounts, theme: self.presentationData.theme, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder, peers: peers, accountPeer: accountPeer, controllerInteraction: self.controllerInteraction!, externalShare: self.externalShare, switchToAnotherAccount: { [weak self] in
|
||||
self?.switchToAnotherAccount?()
|
||||
}, extendedInitialReveal: self.presetText != nil, statsCount: self.shares)
|
||||
}, extendedInitialReveal: self.presetText != nil, segmentedValues: self.segmentedValues)
|
||||
self.peersContentNode = peersContentNode
|
||||
peersContentNode.openSearch = { [weak self] in
|
||||
let _ = (recentlySearchedPeers(postbox: context.account.postbox)
|
||||
@@ -766,12 +767,10 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
peersContentNode.openShare = {
|
||||
openShare(false)
|
||||
}
|
||||
if let openStats = self.openStats {
|
||||
peersContentNode.openStats = { [weak self] in
|
||||
openStats()
|
||||
self?.animateOut(shared: true, completion: {
|
||||
self?.dismiss?(true)
|
||||
})
|
||||
peersContentNode.segmentedSelectedIndexUpdated = { [weak self] index in
|
||||
if let strongSelf = self, let segmentedValues = strongSelf.segmentedValues {
|
||||
strongSelf.selectedSegmentedIndex = index
|
||||
strongSelf.updateButton()
|
||||
}
|
||||
}
|
||||
if self.immediateExternalShare {
|
||||
@@ -837,6 +836,11 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
self.actionButtonNode.setTitle(self.presentationData.strings.ShareMenu_Send, with: Font.medium(20.0), with: self.presentationData.theme.actionSheet.disabledActionTextColor, for: .normal)
|
||||
self.actionButtonNode.isEnabled = false
|
||||
self.actionButtonNode.badge = nil
|
||||
} else if let segmentedValues = self.segmentedValues {
|
||||
let value = segmentedValues[self.selectedSegmentedIndex]
|
||||
self.actionButtonNode.setTitle(value.actionTitle, with: Font.regular(20.0), with: self.presentationData.theme.actionSheet.standardActionTextColor, for: .normal)
|
||||
self.actionButtonNode.isEnabled = true
|
||||
self.actionButtonNode.badge = nil
|
||||
} else if let defaultAction = self.defaultAction {
|
||||
self.actionButtonNode.setTitle(defaultAction.title, with: Font.regular(20.0), with: self.presentationData.theme.actionSheet.standardActionTextColor, for: .normal)
|
||||
self.actionButtonNode.isEnabled = true
|
||||
@@ -847,8 +851,15 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
self.actionButtonNode.badge = nil
|
||||
}
|
||||
} else {
|
||||
let text: String
|
||||
if let segmentedValues = self.segmentedValues {
|
||||
let value = segmentedValues[self.selectedSegmentedIndex]
|
||||
text = value.formatSendTitle(self.controllerInteraction!.selectedPeers.count)
|
||||
} else {
|
||||
text = self.presentationData.strings.ShareMenu_Send
|
||||
}
|
||||
self.actionButtonNode.isEnabled = true
|
||||
self.actionButtonNode.setTitle(self.presentationData.strings.ShareMenu_Send, with: Font.medium(20.0), with: self.presentationData.theme.actionSheet.standardActionTextColor, for: .normal)
|
||||
self.actionButtonNode.setTitle(text, with: Font.medium(20.0), with: self.presentationData.theme.actionSheet.standardActionTextColor, for: .normal)
|
||||
self.actionButtonNode.badge = "\(self.controllerInteraction!.selectedPeers.count)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import AvatarNode
|
||||
import AccountContext
|
||||
import PeerPresenceStatusManager
|
||||
import AppBundle
|
||||
import SegmentedControlNode
|
||||
|
||||
private let subtitleFont = Font.regular(12.0)
|
||||
|
||||
@@ -81,7 +82,6 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
private let controllerInteraction: ShareControllerInteraction
|
||||
private let switchToAnotherAccount: () -> Void
|
||||
private let extendedInitialReveal: Bool
|
||||
private let statsCount: Int?
|
||||
|
||||
let accountPeer: Peer
|
||||
private let foundPeers = Promise<[RenderedPeer]>([])
|
||||
@@ -97,13 +97,15 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
private let contentSeparatorNode: ASDisplayNode
|
||||
private let searchButtonNode: HighlightableButtonNode
|
||||
private let shareButtonNode: HighlightableButtonNode
|
||||
private let statsButtonNode: HighlightableButtonNode
|
||||
private let segmentedNode: SegmentedControlNode
|
||||
|
||||
private let segmentedValues: [ShareControllerSegmentedValue]?
|
||||
|
||||
private var contentOffsetUpdated: ((CGFloat, ContainedViewLayoutTransition) -> Void)?
|
||||
|
||||
var openSearch: (() -> Void)?
|
||||
var openShare: (() -> Void)?
|
||||
var openStats: (() -> Void)?
|
||||
var segmentedSelectedIndexUpdated: ((Int) -> Void)?
|
||||
|
||||
private var ensurePeerVisibleOnLayout: PeerId?
|
||||
private var validLayout: (CGSize, CGFloat)?
|
||||
@@ -111,7 +113,7 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
|
||||
let peersValue = Promise<[(RenderedPeer, PeerPresence?)]>()
|
||||
|
||||
init(sharedContext: SharedAccountContext, context: AccountContext, switchableAccounts: [AccountWithInfo], theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, peers: [(RenderedPeer, PeerPresence?)], accountPeer: Peer, controllerInteraction: ShareControllerInteraction, externalShare: Bool, switchToAnotherAccount: @escaping () -> Void, extendedInitialReveal: Bool, statsCount: Int?) {
|
||||
init(sharedContext: SharedAccountContext, context: AccountContext, switchableAccounts: [AccountWithInfo], theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, peers: [(RenderedPeer, PeerPresence?)], accountPeer: Peer, controllerInteraction: ShareControllerInteraction, externalShare: Bool, switchToAnotherAccount: @escaping () -> Void, extendedInitialReveal: Bool, segmentedValues: [ShareControllerSegmentedValue]?) {
|
||||
self.sharedContext = sharedContext
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
@@ -121,7 +123,7 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
self.accountPeer = accountPeer
|
||||
self.switchToAnotherAccount = switchToAnotherAccount
|
||||
self.extendedInitialReveal = extendedInitialReveal
|
||||
self.statsCount = statsCount
|
||||
self.segmentedValues = segmentedValues
|
||||
|
||||
self.peersValue.set(.single(peers))
|
||||
|
||||
@@ -176,14 +178,18 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
self.searchButtonNode.setImage(generateTintedImage(image: UIImage(bundleImageName: "Share/SearchIcon"), color: self.theme.actionSheet.controlAccentColor), for: [])
|
||||
|
||||
self.shareButtonNode = HighlightableButtonNode()
|
||||
self.shareButtonNode.setImage(generateTintedImage(image: UIImage(bundleImageName: "Share/ShareIcon"), color: self.theme.actionSheet.controlAccentColor), for: [])
|
||||
self.shareButtonNode.setImage(generateTintedImage(image: UIImage(bundleImageName: "Share/ShareIcon"), color: self.theme.actionSheet.controlAccentColor), for: [])
|
||||
|
||||
let segmentedItems: [SegmentedControlItem]
|
||||
if let segmentedValues = segmentedValues {
|
||||
segmentedItems = segmentedValues.map { SegmentedControlItem(title: $0.title) }
|
||||
} else {
|
||||
segmentedItems = []
|
||||
}
|
||||
self.segmentedNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: theme), items: segmentedItems, selectedIndex: 0)
|
||||
|
||||
self.statsButtonNode = HighlightableButtonNode()
|
||||
self.statsButtonNode.setAttributedTitle(NSAttributedString(string: "\(statsCount ?? 0) Shares", font: Font.regular(17.0), textColor: self.theme.actionSheet.controlAccentColor), for: .normal)
|
||||
self.statsButtonNode.isHidden = statsCount == nil
|
||||
|
||||
self.contentTitleNode.isHidden = !self.statsButtonNode.isHidden
|
||||
self.contentSubtitleNode.isHidden = !self.statsButtonNode.isHidden
|
||||
self.contentTitleNode.isHidden = self.segmentedValues != nil
|
||||
self.contentSubtitleNode.isHidden = self.segmentedValues != nil
|
||||
|
||||
self.contentSeparatorNode = ASDisplayNode()
|
||||
self.contentSeparatorNode.isLayerBacked = true
|
||||
@@ -201,11 +207,12 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
self.addSubnode(self.contentTitleNode)
|
||||
self.addSubnode(self.contentSubtitleNode)
|
||||
self.addSubnode(self.contentTitleAccountNode)
|
||||
self.addSubnode(self.segmentedNode)
|
||||
self.addSubnode(self.searchButtonNode)
|
||||
self.addSubnode(self.shareButtonNode)
|
||||
self.addSubnode(self.statsButtonNode)
|
||||
self.addSubnode(self.contentSeparatorNode)
|
||||
|
||||
|
||||
let previousItems = Atomic<[SharePeerEntry]?>(value: [])
|
||||
self.disposable.set((items
|
||||
|> deliverOnMainQueue).start(next: { [weak self] entries in
|
||||
@@ -225,8 +232,11 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
|
||||
self.searchButtonNode.addTarget(self, action: #selector(self.searchPressed), forControlEvents: .touchUpInside)
|
||||
self.shareButtonNode.addTarget(self, action: #selector(self.sharePressed), forControlEvents: .touchUpInside)
|
||||
self.statsButtonNode.addTarget(self, action: #selector(self.statsPressed), forControlEvents: .touchUpInside)
|
||||
self.contentTitleAccountNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.accountTapGesture(_:))))
|
||||
|
||||
self.segmentedNode.selectedIndexChanged = { [weak self] index in
|
||||
self?.segmentedSelectedIndexUpdated?(index)
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
@@ -353,10 +363,7 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
originalSubtitleFrame.size = subtitleFrame.size
|
||||
self.contentSubtitleNode.frame = originalSubtitleFrame
|
||||
transition.updateFrame(node: self.contentSubtitleNode, frame: subtitleFrame)
|
||||
|
||||
let statsSize = self.statsButtonNode.measure(CGSize(width: size.width - 44.0 * 2.0 - 8.0 * 2.0, height: titleAreaHeight))
|
||||
transition.updateFrame(node: self.statsButtonNode, frame: CGRect(origin: CGPoint(x: floor((size.width - statsSize.width) / 2.0), y: titleOffset + 22.0), size: statsSize))
|
||||
|
||||
|
||||
let titleButtonSize = CGSize(width: 44.0, height: 44.0)
|
||||
let searchButtonFrame = CGRect(origin: CGPoint(x: 12.0, y: titleOffset + 12.0), size: titleButtonSize)
|
||||
transition.updateFrame(node: self.searchButtonNode, frame: searchButtonFrame)
|
||||
@@ -364,6 +371,9 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
let shareButtonFrame = CGRect(origin: CGPoint(x: size.width - titleButtonSize.width - 12.0, y: titleOffset + 12.0), size: titleButtonSize)
|
||||
transition.updateFrame(node: self.shareButtonNode, frame: shareButtonFrame)
|
||||
|
||||
let segmentedSize = self.segmentedNode.updateLayout(.sizeToFit(maximumWidth: size.width - titleButtonSize.width * 2.0, minimumWidth: 160.0, height: 32.0), transition: transition)
|
||||
transition.updateFrame(node: self.segmentedNode, frame: CGRect(origin: CGPoint(x: floor((size.width - segmentedSize.width) / 2.0), y: titleOffset + 18.0), size: segmentedSize))
|
||||
|
||||
let avatarButtonSize = CGSize(width: 36.0, height: 36.0)
|
||||
let avatarButtonFrame = CGRect(origin: CGPoint(x: size.width - avatarButtonSize.width - 20.0, y: titleOffset + 15.0), size: avatarButtonSize)
|
||||
transition.updateFrame(node: self.contentTitleAccountNode, frame: avatarButtonFrame)
|
||||
@@ -392,12 +402,10 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
}
|
||||
|
||||
func updateSelectedPeers() {
|
||||
if let _ = self.openStats, self.controllerInteraction.selectedPeers.isEmpty {
|
||||
self.statsButtonNode.isHidden = false
|
||||
if self.segmentedValues != nil {
|
||||
self.contentTitleNode.isHidden = true
|
||||
self.contentSubtitleNode.isHidden = true
|
||||
} else {
|
||||
self.statsButtonNode.isHidden = true
|
||||
self.contentTitleNode.isHidden = false
|
||||
self.contentSubtitleNode.isHidden = false
|
||||
|
||||
@@ -435,10 +443,6 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode {
|
||||
self.openShare?()
|
||||
}
|
||||
|
||||
@objc func statsPressed() {
|
||||
self.openStats?()
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let nodes: [ASDisplayNode] = [self.searchButtonNode, self.shareButtonNode, self.contentTitleAccountNode]
|
||||
for node in nodes {
|
||||
|
||||
@@ -484,7 +484,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
|
||||
} else {
|
||||
isMuted = false
|
||||
}
|
||||
self.micButtonForegroundNode.update(state: VoiceChatMicrophoneNode.State(muted: isMuted, color: UIColor.white), animated: transition.isAnimated)
|
||||
self.micButtonForegroundNode.update(state: VoiceChatMicrophoneNode.State(muted: isMuted, filled: false, color: UIColor.white), animated: transition.isAnimated)
|
||||
|
||||
if isMuted != self.micButtonBackgroundNodeIsMuted {
|
||||
self.micButtonBackgroundNodeIsMuted = isMuted
|
||||
|
||||
@@ -254,7 +254,7 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode {
|
||||
case .connecting:
|
||||
break
|
||||
}
|
||||
self.iconNode.update(state: VoiceChatMicrophoneNode.State(muted: iconMuted, color: iconColor), animated: true)
|
||||
self.iconNode.update(state: VoiceChatMicrophoneNode.State(muted: iconMuted, filled: true, color: iconColor), animated: true)
|
||||
}
|
||||
|
||||
func update(snap: Bool, animated: Bool) {
|
||||
|
||||
@@ -5,11 +5,13 @@ import Display
|
||||
|
||||
private final class VoiceChatMicrophoneNodeDrawingState: NSObject {
|
||||
let color: UIColor
|
||||
let filled: Bool
|
||||
let transition: CGFloat
|
||||
let reverse: Bool
|
||||
|
||||
init(color: UIColor, transition: CGFloat, reverse: Bool) {
|
||||
init(color: UIColor, filled: Bool, transition: CGFloat, reverse: Bool) {
|
||||
self.color = color
|
||||
self.filled = filled
|
||||
self.transition = transition
|
||||
self.reverse = reverse
|
||||
|
||||
@@ -21,9 +23,11 @@ final class VoiceChatMicrophoneNode: ASDisplayNode {
|
||||
class State: Equatable {
|
||||
let muted: Bool
|
||||
let color: UIColor
|
||||
let filled: Bool
|
||||
|
||||
init(muted: Bool, color: UIColor) {
|
||||
init(muted: Bool, filled: Bool, color: UIColor) {
|
||||
self.muted = muted
|
||||
self.filled = filled
|
||||
self.color = color
|
||||
}
|
||||
|
||||
@@ -34,6 +38,9 @@ final class VoiceChatMicrophoneNode: ASDisplayNode {
|
||||
if lhs.color.argb != rhs.color.argb {
|
||||
return false
|
||||
}
|
||||
if lhs.filled != rhs.filled {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -53,7 +60,7 @@ final class VoiceChatMicrophoneNode: ASDisplayNode {
|
||||
private var animator: ConstantDisplayLinkAnimator?
|
||||
|
||||
private var hasState = false
|
||||
private var state: State = State(muted: false, color: .black)
|
||||
private var state: State = State(muted: false, filled: false, color: .black)
|
||||
private var transitionContext: TransitionContext?
|
||||
|
||||
override init() {
|
||||
@@ -133,7 +140,7 @@ final class VoiceChatMicrophoneNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
return VoiceChatMicrophoneNodeDrawingState(color: color, transition: transitionFraction, reverse: reverse)
|
||||
return VoiceChatMicrophoneNodeDrawingState(color: color, filled: self.state.filled, transition: transitionFraction, reverse: reverse)
|
||||
}
|
||||
|
||||
@objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
|
||||
@@ -167,7 +174,7 @@ final class VoiceChatMicrophoneNode: ASDisplayNode {
|
||||
context.translateBy(x: 18.0, y: 18.0)
|
||||
let _ = try? drawSvgPath(context, path: "M-0.004000000189989805,-9.86400032043457 C2.2960000038146973,-9.86400032043457 4.165999889373779,-8.053999900817871 4.25600004196167,-5.77400016784668 C4.25600004196167,-5.77400016784668 4.265999794006348,-5.604000091552734 4.265999794006348,-5.604000091552734 C4.265999794006348,-5.604000091552734 4.265999794006348,-0.8040000200271606 4.265999794006348,-0.8040000200271606 C4.265999794006348,1.555999994277954 2.3559999465942383,3.4660000801086426 -0.004000000189989805,3.4660000801086426 C-2.2939999103546143,3.4660000801086426 -4.164000034332275,1.6460000276565552 -4.263999938964844,-0.6240000128746033 C-4.263999938964844,-0.6240000128746033 -4.263999938964844,-0.8040000200271606 -4.263999938964844,-0.8040000200271606 C-4.263999938964844,-0.8040000200271606 -4.263999938964844,-5.604000091552734 -4.263999938964844,-5.604000091552734 C-4.263999938964844,-7.953999996185303 -2.3540000915527344,-9.86400032043457 -0.004000000189989805,-9.86400032043457 Z ")
|
||||
}
|
||||
if bounds.width > 30.0 {
|
||||
if bounds.width > 30.0 && !parameters.filled {
|
||||
context.setBlendMode(.clear)
|
||||
|
||||
let _ = try? drawSvgPath(context, path: "M0.004000000189989805,-8.53600025177002 C-1.565999984741211,-8.53600025177002 -2.8459999561309814,-7.306000232696533 -2.936000108718872,-5.75600004196167 C-2.936000108718872,-5.75600004196167 -2.936000108718872,-5.5960001945495605 -2.936000108718872,-5.5960001945495605 C-2.936000108718872,-5.5960001945495605 -2.936000108718872,-0.7960000038146973 -2.936000108718872,-0.7960000038146973 C-2.936000108718872,0.8240000009536743 -1.6260000467300415,2.134000062942505 0.004000000189989805,2.134000062942505 C1.5740000009536743,2.134000062942505 2.8540000915527344,0.9039999842643738 2.934000015258789,-0.6460000276565552 C2.934000015258789,-0.6460000276565552 2.934000015258789,-0.7960000038146973 2.934000015258789,-0.7960000038146973 C2.934000015258789,-0.7960000038146973 2.934000015258789,-5.5960001945495605 2.934000015258789,-5.5960001945495605 C2.934000015258789,-7.22599983215332 1.6239999532699585,-8.53600025177002 0.004000000189989805,-8.53600025177002 Z ")
|
||||
|
||||
@@ -159,6 +159,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
fileprivate let avatarNode: AvatarNode
|
||||
private let titleNode: TextNode
|
||||
private let statusNode: TextNode
|
||||
private var credibilityIconNode: ASImageNode?
|
||||
|
||||
private let actionContainerNode: ASDisplayNode
|
||||
private var animationNode: VoiceChatMicrophoneNode?
|
||||
@@ -390,8 +391,26 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
let verticalInset: CGFloat = 8.0
|
||||
let verticalOffset: CGFloat = 0.0
|
||||
let avatarSize: CGFloat = 40.0
|
||||
|
||||
var titleIconsWidth: CGFloat = 0.0
|
||||
var currentCredibilityIconImage: UIImage?
|
||||
var credibilityIconOffset: CGFloat = 0.0
|
||||
if item.peer.isScam {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.scamIcon(item.presentationData.theme, strings: item.presentationData.strings, type: .regular)
|
||||
credibilityIconOffset = 2.0
|
||||
} else if item.peer.isFake {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.fakeIcon(item.presentationData.theme, strings: item.presentationData.strings, type: .regular)
|
||||
credibilityIconOffset = 2.0
|
||||
} else if item.peer.isVerified {
|
||||
currentCredibilityIconImage = PresentationResourcesChatList.verifiedIcon(item.presentationData.theme)
|
||||
credibilityIconOffset = 3.0
|
||||
}
|
||||
|
||||
if let currentCredibilityIconImage = currentCredibilityIconImage {
|
||||
titleIconsWidth += 4.0 + currentCredibilityIconImage.size.width
|
||||
}
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 12.0 - rightInset - 30.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 12.0 - rightInset - 30.0 - titleIconsWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - rightInset - 30.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let insets = UIEdgeInsets()
|
||||
@@ -549,6 +568,25 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
transition.updateFrame(node: strongSelf.titleNode, frame: CGRect(origin: CGPoint(x: leftInset, y: verticalInset + verticalOffset), size: titleLayout.size))
|
||||
transition.updateFrame(node: strongSelf.statusNode, frame: CGRect(origin: CGPoint(x: leftInset, y: strongSelf.titleNode.frame.maxY + titleSpacing), size: statusLayout.size))
|
||||
|
||||
if let currentCredibilityIconImage = currentCredibilityIconImage {
|
||||
let iconNode: ASImageNode
|
||||
if let current = strongSelf.credibilityIconNode {
|
||||
iconNode = current
|
||||
} else {
|
||||
iconNode = ASImageNode()
|
||||
iconNode.isLayerBacked = true
|
||||
iconNode.displaysAsynchronously = false
|
||||
iconNode.displayWithoutProcessing = true
|
||||
strongSelf.offsetContainerNode.addSubnode(iconNode)
|
||||
strongSelf.credibilityIconNode = iconNode
|
||||
}
|
||||
iconNode.image = currentCredibilityIconImage
|
||||
transition.updateFrame(node: iconNode, frame: CGRect(origin: CGPoint(x: leftInset + titleLayout.size.width + 3.0, y: verticalInset + credibilityIconOffset), size: currentCredibilityIconImage.size))
|
||||
} else if let credibilityIconNode = strongSelf.credibilityIconNode {
|
||||
strongSelf.credibilityIconNode = nil
|
||||
credibilityIconNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
let avatarFrame = CGRect(origin: CGPoint(x: params.leftInset + 15.0, y: floorToScreenPixels((layout.contentSize.height - avatarSize) / 2.0)), size: CGSize(width: avatarSize, height: avatarSize))
|
||||
transition.updateFrameAsPositionAndBounds(node: strongSelf.avatarNode, frame: avatarFrame)
|
||||
|
||||
@@ -636,7 +674,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
|
||||
animationNode.layer.animateScale(from: 0.001, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
animationNode.update(state: VoiceChatMicrophoneNode.State(muted: muted, color: color), animated: true)
|
||||
animationNode.update(state: VoiceChatMicrophoneNode.State(muted: muted, filled: false, color: color), animated: true)
|
||||
strongSelf.actionButtonNode.isUserInteractionEnabled = item.contextAction != nil
|
||||
} else if let animationNode = strongSelf.animationNode {
|
||||
strongSelf.animationNode = nil
|
||||
|
||||
Reference in New Issue
Block a user