Add credibility icon for voice chat participants

Add segmented control in share menu
This commit is contained in:
Ilya Laktyushin
2021-03-02 22:22:42 +04:00
parent fed6d34f53
commit fbc8212ee8
8 changed files with 119 additions and 58 deletions

View File

@@ -26,6 +26,7 @@ swift_library(
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
"//submodules/TelegramIntents:TelegramIntents",
"//submodules/AccountContext:AccountContext",
"//submodules/SegmentedControlNode:SegmentedControlNode",
],
visibility = [
"//visibility:public",

View File

@@ -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()

View File

@@ -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)"
}
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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) {

View File

@@ -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 ")

View File

@@ -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