mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Initial invite requests implementation
This commit is contained in:
@@ -8,8 +8,9 @@ import AvatarNode
|
||||
import AccountContext
|
||||
import SelectablePeerNode
|
||||
import ShareController
|
||||
import SolidRoundedButtonNode
|
||||
|
||||
private let avatarFont = avatarPlaceholderFont(size: 26.0)
|
||||
private let avatarFont = avatarPlaceholderFont(size: 42.0)
|
||||
|
||||
private final class MoreNode: ASDisplayNode {
|
||||
private let avatarNode = AvatarNode(font: Font.regular(24.0))
|
||||
@@ -27,61 +28,116 @@ private final class MoreNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainerNode {
|
||||
enum Content {
|
||||
case invite(isGroup: Bool, image: TelegramMediaImageRepresentation?, title: String, memberCount: Int32, members: [EnginePeer])
|
||||
case request(isGroup: Bool, image: TelegramMediaImageRepresentation?, title: String, about: String?, memberCount: Int32)
|
||||
|
||||
var isGroup: Bool {
|
||||
switch self {
|
||||
case let .invite(isGroup, _, _, _, _), let .request(isGroup, _, _, _, _):
|
||||
return isGroup
|
||||
}
|
||||
}
|
||||
|
||||
var image: TelegramMediaImageRepresentation? {
|
||||
switch self {
|
||||
case let .invite(_, image, _, _, _), let .request(_, image, _, _, _):
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case let .invite(_, _, title, _, _), let .request(_, _, title, _, _):
|
||||
return title
|
||||
}
|
||||
}
|
||||
|
||||
var memberCount: Int32 {
|
||||
switch self {
|
||||
case let .invite(_, _, _, memberCount, _), let .request(_, _, _, _, memberCount):
|
||||
return memberCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var contentOffsetUpdated: ((CGFloat, ContainedViewLayoutTransition) -> Void)?
|
||||
|
||||
private let avatarNode: AvatarNode
|
||||
private let titleNode: ASTextNode
|
||||
private let countNode: ASTextNode
|
||||
private let aboutNode: ASTextNode
|
||||
private let descriptionNode: ASTextNode
|
||||
private let peersScrollNode: ASScrollNode
|
||||
|
||||
private let peerNodes: [SelectablePeerNode]
|
||||
private let moreNode: MoreNode?
|
||||
|
||||
init(context: AccountContext, image: TelegramMediaImageRepresentation?, title: String, memberCount: Int32, members: [EnginePeer], isGroup: Bool, theme: PresentationTheme, strings: PresentationStrings) {
|
||||
private let actionButtonNode: SolidRoundedButtonNode
|
||||
|
||||
var join: (() -> Void)?
|
||||
|
||||
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, content: JoinLinkPreviewPeerContentNode.Content) {
|
||||
self.avatarNode = AvatarNode(font: avatarFont)
|
||||
self.titleNode = ASTextNode()
|
||||
self.countNode = ASTextNode()
|
||||
self.aboutNode = ASTextNode()
|
||||
self.aboutNode.maximumNumberOfLines = 6
|
||||
self.descriptionNode = ASTextNode()
|
||||
self.descriptionNode.maximumNumberOfLines = 0
|
||||
self.descriptionNode.textAlignment = .center
|
||||
self.peersScrollNode = ASScrollNode()
|
||||
self.peersScrollNode.view.showsHorizontalScrollIndicator = false
|
||||
|
||||
self.actionButtonNode = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(theme: theme), height: 52.0, cornerRadius: 11.0, gloss: false)
|
||||
|
||||
let itemTheme = SelectablePeerNodeTheme(textColor: theme.actionSheet.primaryTextColor, secretTextColor: .green, selectedTextColor: theme.actionSheet.controlAccentColor, checkBackgroundColor: theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: theme.actionSheet.controlAccentColor, checkColor: theme.actionSheet.opaqueItemBackgroundColor, avatarPlaceholderColor: theme.list.mediaPlaceholderColor)
|
||||
|
||||
self.peerNodes = members.map { peer in
|
||||
let node = SelectablePeerNode()
|
||||
node.setup(context: context, theme: theme, strings: strings, peer: EngineRenderedPeer(peer: peer), synchronousLoad: false)
|
||||
node.theme = itemTheme
|
||||
return node
|
||||
}
|
||||
|
||||
if members.count < Int(memberCount) {
|
||||
self.moreNode = MoreNode(count: Int(memberCount) - members.count)
|
||||
if case let .invite(isGroup, _, _, memberCount, members) = content {
|
||||
self.peerNodes = members.map { peer in
|
||||
let node = SelectablePeerNode()
|
||||
node.setup(context: context, theme: theme, strings: strings, peer: EngineRenderedPeer(peer: peer), synchronousLoad: false)
|
||||
node.theme = itemTheme
|
||||
return node
|
||||
}
|
||||
|
||||
if members.count < Int(memberCount) {
|
||||
self.moreNode = MoreNode(count: Int(memberCount) - members.count)
|
||||
} else {
|
||||
self.moreNode = nil
|
||||
}
|
||||
|
||||
self.actionButtonNode.title = isGroup ? strings.Invitation_JoinGroup : strings.Channel_JoinChannel
|
||||
} else {
|
||||
self.peerNodes = []
|
||||
self.moreNode = nil
|
||||
|
||||
self.actionButtonNode.title = content.isGroup ? strings.MemberRequests_RequestToJoinGroup : strings.MemberRequests_RequestToJoinChannel
|
||||
}
|
||||
|
||||
super.init()
|
||||
|
||||
let peer = TelegramGroup(id: EnginePeer.Id(0), title: title, photo: image.flatMap { [$0] } ?? [], participantCount: Int(memberCount), role: .member, membership: .Left, flags: [], defaultBannedRights: nil, migrationReference: nil, creationDate: 0, version: 0)
|
||||
let peer = TelegramGroup(id: EnginePeer.Id(0), title: content.title, photo: content.image.flatMap { [$0] } ?? [], participantCount: Int(content.memberCount), role: .member, membership: .Left, flags: [], defaultBannedRights: nil, migrationReference: nil, creationDate: 0, version: 0)
|
||||
|
||||
self.addSubnode(self.avatarNode)
|
||||
self.avatarNode.setPeer(context: context, theme: theme, peer: EnginePeer(peer), emptyColor: theme.list.mediaPlaceholderColor)
|
||||
|
||||
self.addSubnode(self.titleNode)
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(16.0), textColor: theme.actionSheet.primaryTextColor)
|
||||
self.titleNode.attributedText = NSAttributedString(string: content.title, font: Font.semibold(24.0), textColor: theme.actionSheet.primaryTextColor)
|
||||
|
||||
self.addSubnode(self.countNode)
|
||||
let membersString: String
|
||||
if isGroup {
|
||||
if !members.isEmpty {
|
||||
if content.isGroup {
|
||||
if case let .invite(_, _, _, memberCount, members) = content, !members.isEmpty {
|
||||
membersString = strings.Invitation_Members(memberCount)
|
||||
} else {
|
||||
membersString = strings.Conversation_StatusMembers(memberCount)
|
||||
membersString = strings.Conversation_StatusMembers(content.memberCount)
|
||||
}
|
||||
} else {
|
||||
membersString = strings.Conversation_StatusSubscribers(memberCount)
|
||||
membersString = strings.Conversation_StatusSubscribers(content.memberCount)
|
||||
}
|
||||
|
||||
self.countNode.attributedText = NSAttributedString(string: membersString, font: Font.regular(16.0), textColor: theme.actionSheet.secondaryTextColor)
|
||||
self.countNode.attributedText = NSAttributedString(string: membersString, font: Font.regular(15.0), textColor: theme.actionSheet.secondaryTextColor)
|
||||
|
||||
if !self.peerNodes.isEmpty {
|
||||
for peerNode in peerNodes {
|
||||
@@ -90,6 +146,21 @@ final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainer
|
||||
self.addSubnode(self.peersScrollNode)
|
||||
}
|
||||
self.moreNode.flatMap(self.peersScrollNode.addSubnode)
|
||||
|
||||
if case let .request(isGroup, _, _, about, _) = content {
|
||||
if let about = about, !about.isEmpty {
|
||||
self.aboutNode.attributedText = NSAttributedString(string: about, font: Font.regular(17.0), textColor: theme.actionSheet.primaryTextColor)
|
||||
self.addSubnode(self.aboutNode)
|
||||
}
|
||||
|
||||
self.descriptionNode.attributedText = NSAttributedString(string: isGroup ? strings.MemberRequests_RequestToJoinDescriptionGroup : strings.MemberRequests_RequestToJoinDescriptionChannel, font: Font.regular(15.0), textColor: theme.actionSheet.secondaryTextColor, paragraphAlignment: .center)
|
||||
self.addSubnode(self.descriptionNode)
|
||||
}
|
||||
|
||||
self.actionButtonNode.pressed = { [weak self] in
|
||||
self?.join?()
|
||||
}
|
||||
self.addSubnode(self.actionButtonNode)
|
||||
}
|
||||
|
||||
func activate() {
|
||||
@@ -106,19 +177,41 @@ final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainer
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let nodeHeight: CGFloat = self.peerNodes.isEmpty ? 224.0 : 324.0
|
||||
var nodeHeight: CGFloat = (self.peerNodes.isEmpty ? 264.0 : 364.0)
|
||||
|
||||
let paddedSize = CGSize(width: size.width - 60.0, height: size.height)
|
||||
|
||||
var aboutSize: CGSize?
|
||||
var descriptionSize: CGSize?
|
||||
if self.aboutNode.supernode != nil {
|
||||
let measuredSize = self.aboutNode.measure(paddedSize)
|
||||
nodeHeight += measuredSize.height + 20.0
|
||||
aboutSize = measuredSize
|
||||
}
|
||||
if self.descriptionNode.supernode != nil {
|
||||
let measuredSize = self.descriptionNode.measure(paddedSize)
|
||||
nodeHeight += measuredSize.height + 20.0 + 10.0
|
||||
descriptionSize = measuredSize
|
||||
}
|
||||
|
||||
let verticalOrigin = size.height - nodeHeight
|
||||
|
||||
let avatarSize: CGFloat = 75.0
|
||||
let avatarSize: CGFloat = 100.0
|
||||
|
||||
transition.updateFrame(node: self.avatarNode, frame: CGRect(origin: CGPoint(x: floor((size.width - avatarSize) / 2.0), y: verticalOrigin + 22.0), size: CGSize(width: avatarSize, height: avatarSize)))
|
||||
transition.updateFrame(node: self.avatarNode, frame: CGRect(origin: CGPoint(x: floor((size.width - avatarSize) / 2.0), y: verticalOrigin + 32.0), size: CGSize(width: avatarSize, height: avatarSize)))
|
||||
|
||||
let titleSize = self.titleNode.measure(size)
|
||||
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: verticalOrigin + 22.0 + avatarSize + 15.0), size: titleSize))
|
||||
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: verticalOrigin + 27.0 + avatarSize + 15.0), size: titleSize))
|
||||
|
||||
let countSize = self.countNode.measure(size)
|
||||
transition.updateFrame(node: self.countNode, frame: CGRect(origin: CGPoint(x: floor((size.width - countSize.width) / 2.0), y: verticalOrigin + 22.0 + avatarSize + 15.0 + titleSize.height + 1.0), size: countSize))
|
||||
transition.updateFrame(node: self.countNode, frame: CGRect(origin: CGPoint(x: floor((size.width - countSize.width) / 2.0), y: verticalOrigin + 27.0 + avatarSize + 15.0 + titleSize.height + 3.0), size: countSize))
|
||||
|
||||
var verticalOffset = verticalOrigin + 27.0 + avatarSize + 15.0 + titleSize.height + 3.0 + countSize.height + 18.0
|
||||
|
||||
if let aboutSize = aboutSize {
|
||||
transition.updateFrame(node: self.aboutNode, frame: CGRect(origin: CGPoint(x: floor((size.width - aboutSize.width) / 2.0), y: verticalOffset), size: aboutSize))
|
||||
verticalOffset += aboutSize.height + 20.0
|
||||
}
|
||||
|
||||
let peerSize = CGSize(width: 85.0, height: 95.0)
|
||||
let peerInset: CGFloat = 10.0
|
||||
@@ -136,9 +229,22 @@ final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainer
|
||||
}
|
||||
|
||||
self.peersScrollNode.view.contentSize = CGSize(width: CGFloat(self.peerNodes.count) * peerSize.width + (self.moreNode != nil ? peerSize.width : 0.0) + peerInset * 2.0, height: peerSize.height)
|
||||
transition.updateFrame(node: self.peersScrollNode, frame: CGRect(origin: CGPoint(x: 0.0, y: verticalOrigin + 168.0), size: CGSize(width: size.width, height: peerSize.height)))
|
||||
transition.updateFrame(node: self.peersScrollNode, frame: CGRect(origin: CGPoint(x: 0.0, y: verticalOrigin + 210.0), size: CGSize(width: size.width, height: peerSize.height)))
|
||||
|
||||
self.contentOffsetUpdated?(-size.height + nodeHeight - 64.0, transition)
|
||||
if !self.peerNodes.isEmpty {
|
||||
verticalOffset += 100.0
|
||||
}
|
||||
|
||||
let buttonInset: CGFloat = 16.0
|
||||
let actionButtonHeight = self.actionButtonNode.updateLayout(width: size.width - buttonInset * 2.0, transition: transition)
|
||||
transition.updateFrame(node: self.actionButtonNode, frame: CGRect(x: buttonInset, y: verticalOffset, width: size.width, height: actionButtonHeight))
|
||||
verticalOffset += actionButtonHeight + 20.0
|
||||
|
||||
if let descriptionSize = descriptionSize {
|
||||
transition.updateFrame(node: self.descriptionNode, frame: CGRect(origin: CGPoint(x: floor((size.width - descriptionSize.width) / 2.0), y: verticalOffset), size: descriptionSize))
|
||||
}
|
||||
|
||||
self.contentOffsetUpdated?(-size.height + nodeHeight, transition)
|
||||
}
|
||||
|
||||
func updateSelectedPeers() {
|
||||
|
||||
Reference in New Issue
Block a user