diff --git a/submodules/ContactListUI/Sources/InviteContactsCountPanelNode.swift b/submodules/ContactListUI/Sources/InviteContactsCountPanelNode.swift index 2abe674765..021c4acf53 100644 --- a/submodules/ContactListUI/Sources/InviteContactsCountPanelNode.swift +++ b/submodules/ContactListUI/Sources/InviteContactsCountPanelNode.swift @@ -3,22 +3,23 @@ import UIKit import AsyncDisplayKit import Display import TelegramPresentationData -import SolidRoundedButtonNode +import ComponentFlow +import ButtonComponent +import EdgeEffect final class InviteContactsCountPanelNode: ASDisplayNode { private let theme: PresentationTheme private let strings: PresentationStrings + private let action: () -> Void - private let separatorNode: ASDisplayNode - private let button: SolidRoundedButtonNode - + private let edgeEffectView = EdgeEffectView() + private let button = ComponentView() + private var validLayout: (CGFloat, CGFloat, CGFloat)? var count: Int = 0 { didSet { if self.count != oldValue && self.count > 0 { - self.button.title = self.strings.Contacts_InviteContacts(Int32(self.count)) - if let (width, sideInset, bottomInset) = self.validLayout { let _ = self.updateLayout(width: width, sideInset: sideInset, bottomInset: bottomInset, transition: .immediate) } @@ -29,37 +30,75 @@ final class InviteContactsCountPanelNode: ASDisplayNode { init(theme: PresentationTheme, strings: PresentationStrings, action: @escaping () -> Void) { self.theme = theme self.strings = strings + self.action = action - self.separatorNode = ASDisplayNode() - self.separatorNode.backgroundColor = theme.rootController.navigationBar.separatorColor - - self.button = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(theme: theme), height: 48.0, cornerRadius: 10.0) - super.init() - - self.backgroundColor = theme.rootController.navigationBar.opaqueBackgroundColor - - self.addSubnode(self.button) - self.addSubnode(self.separatorNode) - - self.button.pressed = { - action() - } } func updateLayout(width: CGFloat, sideInset: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { self.validLayout = (width, sideInset, bottomInset) - let topInset: CGFloat = 9.0 - var bottomInset = bottomInset - bottomInset += topInset - (bottomInset.isZero ? 0.0 : 4.0) - let buttonInset: CGFloat = 16.0 + sideInset - let buttonWidth = width - buttonInset * 2.0 - let buttonHeight = self.button.updateLayout(width: buttonWidth, transition: transition) - transition.updateFrame(node: self.button, frame: CGRect(x: buttonInset, y: topInset, width: buttonWidth, height: buttonHeight)) + let buttonInsets = ContainerViewLayout.concentricInsets(bottomInset: bottomInset, innerDiameter: 52.0, sideInset: 30.0) + let height: CGFloat = 52.0 + buttonInsets.bottom - transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: UIScreenPixel))) + let edgeEffectHeight: CGFloat = height + let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: edgeEffectHeight)) + transition.updateFrame(view: self.edgeEffectView, frame: edgeEffectFrame) + self.edgeEffectView.update( + content: self.theme.list.plainBackgroundColor, + blur: true, + rect: edgeEffectFrame, + edge: .bottom, + edgeSize: edgeEffectFrame.height, + transition: ComponentTransition(transition) + ) + if self.edgeEffectView.superview == nil { + self.view.addSubview(self.edgeEffectView) + } - return topInset + buttonHeight + bottomInset + let buttonTransition: ComponentTransition = .easeInOut(duration: 0.2) + let buttonSize = self.button.update( + transition: buttonTransition, + component: AnyComponent( + ButtonComponent( + background: ButtonComponent.Background( + style: .glass, + color: self.theme.list.itemCheckColors.fillColor, + foreground: self.theme.list.itemCheckColors.foregroundColor, + pressedColor: self.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9) + ), + content: AnyComponentWithIdentity( + id: AnyHashable(0), + component: AnyComponent(ButtonTextContentComponent( + text: self.strings.Contacts_InviteContacts(Int32(self.count)), + badge: 0, + textColor: self.theme.list.itemCheckColors.foregroundColor, + badgeBackground: self.theme.list.itemCheckColors.foregroundColor, + badgeForeground: self.theme.list.itemCheckColors.fillColor, + badgeStyle: .roundedRectangle, + badgeIconName: nil, + combinedAlignment: true + )) + ), + isEnabled: true, + action: { [weak self] in + guard let self else { + return + } + self.action() + } + ) + ), + environment: {}, + containerSize: CGSize(width: width - sideInset * 2.0 - buttonInsets.left - buttonInsets.right, height: 52.0) + ) + let buttonFrame = CGRect(origin: CGPoint(x: sideInset + buttonInsets.left, y: 0.0), size: buttonSize) + if let buttonView = self.button.view { + if buttonView.superview == nil { + self.view.addSubview(buttonView) + } + transition.updateFrame(view: buttonView, frame: buttonFrame) + } + return height } } diff --git a/submodules/DatePickerNode/Sources/DatePickerNode.swift b/submodules/DatePickerNode/Sources/DatePickerNode.swift index fd0b9cbeef..91f4af24e9 100644 --- a/submodules/DatePickerNode/Sources/DatePickerNode.swift +++ b/submodules/DatePickerNode/Sources/DatePickerNode.swift @@ -460,12 +460,12 @@ public final class DatePickerNode: ASDisplayNode { self.dateButtonNode = HighlightableButtonNode() self.dateButtonNode.clipsToBounds = true self.dateButtonNode.backgroundColor = theme.segmentedControlTheme.backgroundColor - self.dateButtonNode.cornerRadius = 9.0 + self.dateButtonNode.cornerRadius = 18.0 self.timeButtonNode = HighlightableButtonNode() self.timeButtonNode.clipsToBounds = true self.timeButtonNode.backgroundColor = theme.segmentedControlTheme.backgroundColor - self.timeButtonNode.cornerRadius = 9.0 + self.timeButtonNode.cornerRadius = 18.0 super.init() @@ -828,7 +828,7 @@ public final class DatePickerNode: ASDisplayNode { var timeSize = self.timeButtonNode.measure(size) timeSize.width += 24.0 timeSize.height = 36.0 - self.timeButtonNode.frame = CGRect(x: size.width - timeSize.width - 4.0, y: 4.0, width: timeSize.width, height: timeSize.height) + self.timeButtonNode.frame = CGRect(x: size.width - timeSize.width - 10.0, y: 4.0, width: timeSize.width, height: timeSize.height) let dateString = stringForMediumDate(timestamp: Int32(date.timeIntervalSince1970), strings: self.strings, dateTimeFormat: self.dateTimeFormat, withTime: false) self.dateButtonNode.setTitle(dateString, with: Font.with(size: 17.0, traits: .monospacedNumbers), with: self.state.displayingDateSelection ? self.theme.accentColor : self.theme.textColor, for: .normal) @@ -836,7 +836,7 @@ public final class DatePickerNode: ASDisplayNode { var dateSize = self.dateButtonNode.measure(size) dateSize.width += 24.0 dateSize.height = 36.0 - self.dateButtonNode.frame = CGRect(x: size.width - timeSize.width - 4.0 - 4.0 - dateSize.width, y: 4.0, width: dateSize.width, height: dateSize.height) + self.dateButtonNode.frame = CGRect(x: size.width - timeSize.width - 10.0 - 4.0 - dateSize.width, y: 4.0, width: dateSize.width, height: dateSize.height) let daysSideInset: CGFloat = 12.0 let cellSize: CGFloat = floor((constrainedSize.width - daysSideInset * 2.0) / 7.0) diff --git a/submodules/InviteLinksUI/Sources/InviteLinkEditController.swift b/submodules/InviteLinksUI/Sources/InviteLinkEditController.swift index 13fc11eb8d..79564f02cb 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkEditController.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkEditController.swift @@ -388,7 +388,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry { case let .timeCustomPicker(_, dateTimeFormat, date, displayingDateSelection, displayingTimeSelection, enabled): let _ = enabled let title = presentationData.strings.InviteLink_Create_TimeLimitExpiryTime - return ItemListDatePickerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, date: date, title: title, displayingDateSelection: displayingDateSelection, displayingTimeSelection: displayingTimeSelection, sectionId: self.section, style: .blocks, toggleDateSelection: { + return ItemListDatePickerItem(presentationData: presentationData, systemStyle: .glass, dateTimeFormat: dateTimeFormat, date: date, title: title, displayingDateSelection: displayingDateSelection, displayingTimeSelection: displayingTimeSelection, sectionId: self.section, style: .blocks, toggleDateSelection: { arguments.updateState({ state in var updatedState = state updatedState.pickingExpiryDate = !updatedState.pickingExpiryDate diff --git a/submodules/ItemListUI/Sources/Items/ItemListPlaceholderItem.swift b/submodules/ItemListUI/Sources/Items/ItemListPlaceholderItem.swift index 4bbd49de8f..130c1bfb5c 100644 --- a/submodules/ItemListUI/Sources/Items/ItemListPlaceholderItem.swift +++ b/submodules/ItemListUI/Sources/Items/ItemListPlaceholderItem.swift @@ -7,13 +7,15 @@ import TelegramPresentationData public class ItemListPlaceholderItem: ListViewItem, ItemListItem { let theme: PresentationTheme + let systemStyle: ItemListSystemStyle let text: String public let sectionId: ItemListSectionId let style: ItemListStyle public let tag: ItemListItemTag? - public init(theme: PresentationTheme, text: String, sectionId: ItemListSectionId, style: ItemListStyle, tag: ItemListItemTag? = nil) { + public init(theme: PresentationTheme, systemStyle: ItemListSystemStyle = .legacy, text: String, sectionId: ItemListSectionId, style: ItemListStyle, tag: ItemListItemTag? = nil) { self.theme = theme + self.systemStyle = systemStyle self.text = text self.sectionId = sectionId self.style = style @@ -198,7 +200,7 @@ public class ItemListPlaceholderItemNode: ListViewItemNode, ItemListItemNode { strongSelf.bottomStripeNode.isHidden = hasCorners } - strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners, glass: item.systemStyle == .glass) : 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.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0) diff --git a/submodules/PremiumUI/Sources/CreateGiveawayController.swift b/submodules/PremiumUI/Sources/CreateGiveawayController.swift index 810c269d13..6271348638 100644 --- a/submodules/PremiumUI/Sources/CreateGiveawayController.swift +++ b/submodules/PremiumUI/Sources/CreateGiveawayController.swift @@ -433,7 +433,7 @@ private enum CreateGiveawayEntry: ItemListNodeEntry { case let .modeHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .giftPremium(_, title, subtitle, isSelected): - return GiftOptionItem(presentationData: presentationData, context: arguments.context, icon: .image(color: .premium, name: "Peer Info/PremiumIcon"), title: title, subtitle: subtitle, subtitleActive: true, isSelected: isSelected, sectionId: self.section, action: { + return GiftOptionItem(presentationData: presentationData, systemStyle: .glass, context: arguments.context, icon: .image(color: .premium, name: "Peer Info/PremiumIcon"), title: title, subtitle: subtitle, subtitleActive: true, isSelected: isSelected, sectionId: self.section, action: { var openSelection = false arguments.updateState { state in var updatedState = state @@ -448,7 +448,7 @@ private enum CreateGiveawayEntry: ItemListNodeEntry { } }) case let .giftStars(_, title, subtitle, isSelected): - return GiftOptionItem(presentationData: presentationData, context: arguments.context, icon: .image(color: .stars, name: "Peer Info/PremiumIcon"), title: title, subtitle: subtitle, subtitleActive: false, isSelected: isSelected, sectionId: self.section, action: { + return GiftOptionItem(presentationData: presentationData, systemStyle: .glass, context: arguments.context, icon: .image(color: .stars, name: "Peer Info/PremiumIcon"), title: title, subtitle: subtitle, subtitleActive: false, isSelected: isSelected, sectionId: self.section, action: { arguments.updateState { state in var updatedState = state updatedState.mode = .starsGiveaway @@ -480,7 +480,7 @@ private enum CreateGiveawayEntry: ItemListNodeEntry { icon = "Premium/PremiumStar" boosts = boostCount } - return GiftOptionItem(presentationData: presentationData, context: arguments.context, icon: .image(color: color, name: icon), title: title, titleFont: .bold, titleBadge: "\(boosts)", subtitle: subtitle, sectionId: self.section, action: nil) + return GiftOptionItem(presentationData: presentationData, systemStyle: .glass, context: arguments.context, icon: .image(color: color, name: icon), title: title, titleFont: .bold, titleBadge: "\(boosts)", subtitle: subtitle, sectionId: self.section, action: nil) case let .starsHeader(_, text, additionalText): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, accessoryText: ItemListSectionHeaderAccessoryText(value: additionalText, color: .generic), sectionId: self.section) case let .stars(_, _, stars, title, subtitle, label, isSelected, maxWinners): @@ -501,7 +501,7 @@ private enum CreateGiveawayEntry: ItemListNodeEntry { case let .subscriptionsHeader(_, text, additionalText): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, accessoryText: ItemListSectionHeaderAccessoryText(value: additionalText, color: .generic), sectionId: self.section) case let .subscriptions(_, value, values): - return SubscriptionsCountItem(theme: presentationData.theme, strings: presentationData.strings, value: value, values: values, sectionId: self.section, updated: { value in + return SubscriptionsCountItem(theme: presentationData.theme, strings: presentationData.strings, systemStyle: .glass, value: value, values: values, sectionId: self.section, updated: { value in arguments.updateState { state in var updatedState = state if state.mode == .giveaway { @@ -536,7 +536,7 @@ private enum CreateGiveawayEntry: ItemListNodeEntry { case let .usersHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .usersAll(_, title, subtitle, isSelected): - return GiftOptionItem(presentationData: presentationData, context: arguments.context, title: title, subtitle: subtitle, subtitleActive: true, isSelected: isSelected, sectionId: self.section, action: { + return GiftOptionItem(presentationData: presentationData, systemStyle: .glass, context: arguments.context, title: title, subtitle: subtitle, subtitleActive: true, isSelected: isSelected, sectionId: self.section, action: { var openSelection = false arguments.updateState { state in var updatedState = state @@ -551,7 +551,7 @@ private enum CreateGiveawayEntry: ItemListNodeEntry { } }) case let .usersNew(_, title, subtitle, isSelected): - return GiftOptionItem(presentationData: presentationData, context: arguments.context, title: title, subtitle: subtitle, subtitleActive: true, isSelected: isSelected, sectionId: self.section, action: { + return GiftOptionItem(presentationData: presentationData, systemStyle: .glass, context: arguments.context, title: title, subtitle: subtitle, subtitleActive: true, isSelected: isSelected, sectionId: self.section, action: { var openSelection = false arguments.updateState { state in var updatedState = state @@ -570,7 +570,7 @@ private enum CreateGiveawayEntry: ItemListNodeEntry { case let .durationHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .duration(_, _, months, title, subtitle, label, badge, isSelected): - return GiftOptionItem(presentationData: presentationData, context: arguments.context, title: title, subtitle: subtitle, subtitleFont: .small, label: .generic(label), badge: badge, isSelected: isSelected, sectionId: self.section, action: { + return GiftOptionItem(presentationData: presentationData, systemStyle: .glass, context: arguments.context, title: title, subtitle: subtitle, subtitleFont: .small, label: .generic(label), badge: badge, isSelected: isSelected, sectionId: self.section, action: { arguments.updateState { state in var updatedState = state updatedState.selectedMonths = months @@ -635,7 +635,7 @@ private enum CreateGiveawayEntry: ItemListNodeEntry { }) case let .timeCustomPicker(_, dateTimeFormat, date, minDate, maxDate, displayingDateSelection, displayingTimeSelection): let title = presentationData.strings.BoostGift_DateEnds - return ItemListDatePickerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, date: date, minDate: minDate, maxDate: maxDate, title: title, displayingDateSelection: displayingDateSelection, displayingTimeSelection: displayingTimeSelection, sectionId: self.section, style: .blocks, toggleDateSelection: { + return ItemListDatePickerItem(presentationData: presentationData, systemStyle: .glass, dateTimeFormat: dateTimeFormat, date: date, minDate: minDate, maxDate: maxDate, title: title, displayingDateSelection: displayingDateSelection, displayingTimeSelection: displayingTimeSelection, sectionId: self.section, style: .blocks, toggleDateSelection: { var focus = false arguments.updateState({ state in var updatedState = state diff --git a/submodules/PremiumUI/Sources/CreateGiveawayFooterItem.swift b/submodules/PremiumUI/Sources/CreateGiveawayFooterItem.swift index 066dfb3536..bd5af379b5 100644 --- a/submodules/PremiumUI/Sources/CreateGiveawayFooterItem.swift +++ b/submodules/PremiumUI/Sources/CreateGiveawayFooterItem.swift @@ -7,6 +7,7 @@ import TelegramPresentationData import ItemListUI import PresentationDataUtils import ButtonComponent +import EdgeEffect final class CreateGiveawayFooterItem: ItemListControllerFooterItem { let theme: PresentationTheme @@ -42,8 +43,7 @@ final class CreateGiveawayFooterItem: ItemListControllerFooterItem { } final class CreateGiveawayFooterItemNode: ItemListControllerFooterItemNode { - private let backgroundNode: NavigationBackgroundNode - private let separatorNode: ASDisplayNode + private let edgeEffectView = EdgeEffectView() private let button = ComponentView() private var validLayout: ContainerViewLayout? @@ -51,7 +51,6 @@ final class CreateGiveawayFooterItemNode: ItemListControllerFooterItemNode { private var currentIsLoading = false var item: CreateGiveawayFooterItem { didSet { - self.updateItem() if let layout = self.validLayout { let _ = self.updateLayout(layout: layout, transition: .immediate) } @@ -60,49 +59,35 @@ final class CreateGiveawayFooterItemNode: ItemListControllerFooterItemNode { init(item: CreateGiveawayFooterItem) { self.item = item - - self.backgroundNode = NavigationBackgroundNode(color: item.theme.rootController.tabBar.backgroundColor) - self.separatorNode = ASDisplayNode() - + super.init() - - self.addSubnode(self.backgroundNode) - self.addSubnode(self.separatorNode) - - self.updateItem() } - private func updateItem() { - self.backgroundNode.updateColor(color: self.item.theme.rootController.tabBar.backgroundColor, transition: .immediate) - self.separatorNode.backgroundColor = self.item.theme.rootController.tabBar.separatorColor - } - override func updateBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) { - transition.updateAlpha(node: self.backgroundNode, alpha: alpha) - transition.updateAlpha(node: self.separatorNode, alpha: alpha) } override func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) -> CGFloat { let hadLayout = self.validLayout != nil self.validLayout = layout - let buttonInset: CGFloat = 16.0 - let buttonWidth = layout.size.width - layout.safeInsets.left - layout.safeInsets.right - buttonInset * 2.0 - let inset: CGFloat = 9.0 + let buttonInsets = ContainerViewLayout.concentricInsets(bottomInset: layout.intrinsicInsets.bottom, innerDiameter: 52.0, sideInset: 30.0) + let height: CGFloat = 52.0 + buttonInsets.bottom - let insets = layout.insets(options: [.input]) - - var panelHeight: CGFloat = 50.0 + inset * 2.0 - let totalPanelHeight: CGFloat - if let inputHeight = layout.inputHeight, inputHeight > 0.0 { - totalPanelHeight = panelHeight + insets.bottom - } else { - totalPanelHeight = panelHeight + insets.bottom - panelHeight += insets.bottom + let edgeEffectHeight: CGFloat = height + let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - edgeEffectHeight), size: CGSize(width: layout.size.width, height: edgeEffectHeight)) + transition.updateFrame(view: self.edgeEffectView, frame: edgeEffectFrame) + self.edgeEffectView.update( + content: self.item.theme.list.plainBackgroundColor, + blur: true, + rect: edgeEffectFrame, + edge: .bottom, + edgeSize: edgeEffectFrame.height, + transition: ComponentTransition(transition) + ) + if self.edgeEffectView.superview == nil { + self.view.addSubview(self.edgeEffectView) } - let panelFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - totalPanelHeight), size: CGSize(width: layout.size.width, height: panelHeight)) - var buttonTransition: ComponentTransition = .easeInOut(duration: 0.2) if !hadLayout { buttonTransition = .immediate @@ -112,6 +97,7 @@ final class CreateGiveawayFooterItemNode: ItemListControllerFooterItemNode { component: AnyComponent( ButtonComponent( background: ButtonComponent.Background( + style: .glass, color: self.item.theme.list.itemCheckColors.fillColor, foreground: self.item.theme.list.itemCheckColors.foregroundColor, pressedColor: self.item.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9) @@ -140,26 +126,21 @@ final class CreateGiveawayFooterItemNode: ItemListControllerFooterItemNode { ) ), environment: {}, - containerSize: CGSize(width: buttonWidth, height: 50.0) + containerSize: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - buttonInsets.left - buttonInsets.right, height: 52.0) ) - if let view = self.button.view { - if view.superview == nil { - self.view.addSubview(view) + let buttonFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left + buttonInsets.left, y: layout.size.height - buttonInsets.bottom - buttonSize.height), size: buttonSize) + if let buttonView = self.button.view { + if buttonView.superview == nil { + self.view.addSubview(buttonView) } - transition.updateFrame(view: view, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + buttonInset, y: panelFrame.minY + inset), size: buttonSize)) + transition.updateFrame(view: buttonView, frame: buttonFrame) } - - transition.updateFrame(node: self.backgroundNode, frame: panelFrame) - self.backgroundNode.update(size: panelFrame.size, transition: transition) - - transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: panelFrame.origin, size: CGSize(width: panelFrame.width, height: UIScreenPixel))) - - return totalPanelHeight + return height } override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { - if self.backgroundNode.frame.contains(point) { + if self.edgeEffectView.frame.contains(point) { return true } else { return false diff --git a/submodules/PremiumUI/Sources/CreateGiveawayHeaderItem.swift b/submodules/PremiumUI/Sources/CreateGiveawayHeaderItem.swift index f65c452521..3b40a7bdcc 100644 --- a/submodules/PremiumUI/Sources/CreateGiveawayHeaderItem.swift +++ b/submodules/PremiumUI/Sources/CreateGiveawayHeaderItem.swift @@ -9,6 +9,8 @@ import PresentationDataUtils import Markdown import ComponentFlow import PremiumStarComponent +import GlassBarButtonComponent +import BundleIconComponent final class CreateGiveawayHeaderItem: ItemListControllerHeaderItem { let theme: PresentationTheme @@ -49,13 +51,10 @@ private let titleFont = Font.semibold(20.0) private let textFont = Font.regular(15.0) class CreateGiveawayHeaderItemNode: ItemListControllerHeaderItemNode { - private let backgroundNode: NavigationBackgroundNode - private let separatorNode: ASDisplayNode private let titleNode: ImmediateTextNode private let textNode: ImmediateTextNode - private let cancelNode: HighlightableButtonNode - + private let cancelButton = ComponentView() private var hostView: ComponentHostView? private var component: AnyComponent? @@ -72,11 +71,7 @@ class CreateGiveawayHeaderItemNode: ItemListControllerHeaderItemNode { init(item: CreateGiveawayHeaderItem) { self.item = item - - self.backgroundNode = NavigationBackgroundNode(color: item.theme.rootController.navigationBar.blurredBackgroundColor) - - self.separatorNode = ASDisplayNode() - + self.titleNode = ImmediateTextNode() self.titleNode.isUserInteractionEnabled = false self.titleNode.contentMode = .left @@ -87,26 +82,15 @@ class CreateGiveawayHeaderItemNode: ItemListControllerHeaderItemNode { self.textNode.contentMode = .left self.textNode.contentsScale = UIScreen.main.scale self.textNode.maximumNumberOfLines = 0 - - self.cancelNode = HighlightableButtonNode() - + super.init() self.addSubnode(self.textNode) - self.addSubnode(self.backgroundNode) - self.addSubnode(self.separatorNode) self.addSubnode(self.titleNode) - self.addSubnode(self.cancelNode) - - self.cancelNode.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside) - + self.updateItem() } - - @objc private func cancelPressed() { - self.item.cancel() - } - + override func didLoad() { super.didLoad() @@ -128,23 +112,18 @@ class CreateGiveawayHeaderItemNode: ItemListControllerHeaderItemNode { } func updateItem() { - self.backgroundNode.updateColor(color: self.item.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate) - self.separatorNode.backgroundColor = self.item.theme.rootController.navigationBar.separatorColor - let attributedTitle = NSAttributedString(string: self.item.title, font: titleFont, textColor: self.item.theme.list.itemPrimaryTextColor, paragraphAlignment: .center) let attributedText = NSAttributedString(string: self.item.text, font: textFont, textColor: self.item.theme.list.freeTextColor, paragraphAlignment: .center) self.titleNode.attributedText = attributedTitle self.textNode.attributedText = attributedText - - self.cancelNode.setAttributedTitle(NSAttributedString(string: self.item.strings.Common_Cancel, font: Font.regular(17.0), textColor: self.item.theme.rootController.navigationBar.accentTextColor), for: .normal) } override func updateContentOffset(_ contentOffset: CGFloat, transition: ContainedViewLayoutTransition) { guard let layout = self.validLayout else { return } - let navigationHeight: CGFloat = 56.0 + let navigationHeight: CGFloat = 76.0 let statusBarHeight = layout.statusBarHeight ?? 0.0 let topInset : CGFloat = 0.0 @@ -155,10 +134,6 @@ class CreateGiveawayHeaderItemNode: ItemListControllerHeaderItemNode { let fraction = max(0.0, min(1.0, titleOffset / titleOffsetDelta)) let titleScale = 1.0 - fraction * 0.18 - let topPanelAlpha = min(20.0, max(0.0, contentOffset - 95.0)) / 20.0 - transition.updateAlpha(node: self.backgroundNode, alpha: topPanelAlpha) - transition.updateAlpha(node: self.separatorNode, alpha: topPanelAlpha) - let starPosition = CGPoint( x: layout.size.width / 2.0, y: -contentOffset + 80.0 @@ -185,18 +160,34 @@ class CreateGiveawayHeaderItemNode: ItemListControllerHeaderItemNode { override func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) -> CGFloat { let leftInset: CGFloat = 24.0 - let navigationBarHeight: CGFloat = 56.0 let constrainedSize = CGSize(width: layout.size.width - leftInset * 2.0, height: CGFloat.greatestFiniteMagnitude) let titleSize = self.titleNode.updateLayout(constrainedSize) let textSize = self.textNode.updateLayout(constrainedSize) - - let cancelSize = self.cancelNode.measure(constrainedSize) - transition.updateFrame(node: self.cancelNode, frame: CGRect(origin: CGPoint(x: 16.0 + layout.safeInsets.left, y: floorToScreenPixels((navigationBarHeight - cancelSize.height) / 2.0)), size: cancelSize)) - - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: navigationBarHeight))) - transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel))) - - self.backgroundNode.update(size: CGSize(width: layout.size.width, height: navigationBarHeight), transition: transition) + + let cancelButtonSize = self.cancelButton.update( + transition: .immediate, + component: AnyComponent( + GlassBarButtonComponent( + size: CGSize(width: 44.0, height: 44.0), + backgroundColor: nil, + isDark: self.item.theme.overallDarkAppearance, + state: .glass, + component: AnyComponentWithIdentity(id: "icon", component: AnyComponent(BundleIconComponent(name: "Navigation/Close", tintColor: self.item.theme.chat.inputPanel.panelControlColor))), + action: { [weak self] _ in + self?.item.cancel() + } + ) + ), + environment: {}, + containerSize: CGSize(width: 44.0, height: 44.0) + ) + let cancelButtonFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: cancelButtonSize) + if let cancelButtonView = self.cancelButton.view { + if cancelButtonView.superview == nil { + self.view.addSubview(cancelButtonView) + } + cancelButtonView.frame = cancelButtonFrame + } let colors: [UIColor] let particleColor: UIColor? diff --git a/submodules/PremiumUI/Sources/GiftOptionItem.swift b/submodules/PremiumUI/Sources/GiftOptionItem.swift index eac888a1f6..c11806ae8d 100644 --- a/submodules/PremiumUI/Sources/GiftOptionItem.swift +++ b/submodules/PremiumUI/Sources/GiftOptionItem.swift @@ -53,6 +53,7 @@ public final class GiftOptionItem: ListViewItem, ItemListItem { } let presentationData: ItemListPresentationData + let systemStyle: ItemListSystemStyle let context: AccountContext let icon: Icon? let title: String @@ -68,8 +69,9 @@ public final class GiftOptionItem: ListViewItem, ItemListItem { public let sectionId: ItemListSectionId let action: (() -> Void)? - public init(presentationData: ItemListPresentationData, context: AccountContext, icon: Icon? = nil, title: String, titleFont: Font = .regular, titleBadge: String? = nil, subtitle: String?, subtitleFont: SubtitleFont = .regular, subtitleActive: Bool = false, label: Label? = nil, badge: String? = nil, isSelected: Bool? = nil, stars: Int64? = nil, sectionId: ItemListSectionId, action: (() -> Void)?) { + public init(presentationData: ItemListPresentationData, systemStyle: ItemListSystemStyle = .legacy, context: AccountContext, icon: Icon? = nil, title: String, titleFont: Font = .regular, titleBadge: String? = nil, subtitle: String?, subtitleFont: SubtitleFont = .regular, subtitleActive: Bool = false, label: Label? = nil, badge: String? = nil, isSelected: Bool? = nil, stars: Int64? = nil, sectionId: ItemListSectionId, action: (() -> Void)?) { self.presentationData = presentationData + self.systemStyle = systemStyle self.icon = icon self.context = context self.title = title @@ -518,7 +520,7 @@ class GiftOptionItemNode: ItemListRevealOptionsItemNode { strongSelf.bottomStripeNode.isHidden = hasCorners } - strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners, glass: item.systemStyle == .glass) : 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.containerNode.frame = CGRect(origin: CGPoint(), size: strongSelf.backgroundNode.frame.size) diff --git a/submodules/PremiumUI/Sources/PremiumBoostScreen.swift b/submodules/PremiumUI/Sources/PremiumBoostScreen.swift deleted file mode 100644 index 00a0a4caa5..0000000000 --- a/submodules/PremiumUI/Sources/PremiumBoostScreen.swift +++ /dev/null @@ -1,280 +0,0 @@ -import Foundation -import UIKit -import Display -import SwiftSignalKit -import TelegramCore -import AccountContext -import TelegramPresentationData -import UndoUI -import PresentationDataUtils - -private struct BoostState { - let level: Int32 - let currentLevelBoosts: Int32 - let nextLevelBoosts: Int32? - let boosts: Int32 - - func displayData(peer: EnginePeer, isCurrent: Bool, canBoostAgain: Bool, myBoostCount: Int32, currentMyBoostCount: Int32, replacedBoosts: Int32? = nil) -> (subject: PremiumLimitScreen.Subject, count: Int32) { - var currentLevel = self.level - var nextLevelBoosts = self.nextLevelBoosts - var currentLevelBoosts = self.currentLevelBoosts - var boosts = self.boosts - if let replacedBoosts { - boosts = max(currentLevelBoosts, boosts - replacedBoosts) - } - - if currentMyBoostCount > 0 && self.boosts == currentLevelBoosts { - currentLevel = max(0, currentLevel - 1) - nextLevelBoosts = currentLevelBoosts - currentLevelBoosts = max(0, currentLevelBoosts - 1) - } - - return ( - .storiesChannelBoost( - peer: peer, - boostSubject: .stories, - isCurrent: isCurrent, - level: currentLevel, - currentLevelBoosts: currentLevelBoosts, - nextLevelBoosts: nextLevelBoosts, - link: nil, - myBoostCount: myBoostCount, - canBoostAgain: canBoostAgain - ), - boosts - ) - } -} - -public func PremiumBoostScreen( - context: AccountContext, - contentContext: Any?, - peerId: EnginePeer.Id, - isCurrent: Bool, - status: ChannelBoostStatus?, - myBoostStatus: MyBoostStatus?, - replacedBoosts: (Int32, Int32)? = nil, - forceDark: Bool, - openPeer: @escaping (EnginePeer) -> Void, - presentController: @escaping (ViewController) -> Void, - pushController: @escaping (ViewController) -> Void, - dismissed: @escaping () -> Void -) { - let _ = (context.engine.data.get( - TelegramEngine.EngineData.Item.Peer.Peer(id: peerId), - TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId) - ) - |> deliverOnMainQueue).startStandalone(next: { peer, accountPeer in - guard let peer, let accountPeer, let status else { - return - } - - let isPremium = accountPeer.isPremium - - var myBoostCount: Int32 = 0 - var currentMyBoostCount: Int32 = 0 - var availableBoosts: [MyBoostStatus.Boost] = [] - var occupiedBoosts: [MyBoostStatus.Boost] = [] - if let myBoostStatus { - for boost in myBoostStatus.boosts { - if let boostPeer = boost.peer { - if boostPeer.id == peer.id { - myBoostCount += 1 - } else { - occupiedBoosts.append(boost) - } - } else { - availableBoosts.append(boost) - } - } - } - - let boosts = max(Int32(status.boosts), myBoostCount) - let initialState = BoostState(level: Int32(status.level), currentLevelBoosts: Int32(status.currentLevelBoosts), nextLevelBoosts: status.nextLevelBoosts.flatMap(Int32.init), boosts: boosts) - let updatedState = Promise() - updatedState.set(.single(BoostState(level: Int32(status.level), currentLevelBoosts: Int32(status.currentLevelBoosts), nextLevelBoosts: status.nextLevelBoosts.flatMap(Int32.init), boosts: boosts + 1))) - - var updateImpl: (() -> Void)? - var dismissImpl: (() -> Void)? - - let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with({ $0 })) - let canBoostAgain = premiumConfiguration.boostsPerGiftCount > 0 - - let (initialSubject, initialCount) = initialState.displayData(peer: peer, isCurrent: isCurrent, canBoostAgain: canBoostAgain, myBoostCount: myBoostCount, currentMyBoostCount: 0, replacedBoosts: replacedBoosts?.0) - let controller = PremiumLimitScreen(context: context, subject: initialSubject, count: initialCount, forceDark: forceDark, action: { - let dismiss = false - updateImpl?() - return dismiss - }, - openPeer: { peer in - openPeer(peer) - }) - pushController(controller) - - if let (replacedBoosts, inChannels) = replacedBoosts { - currentMyBoostCount += 1 - let (subject, count) = initialState.displayData(peer: peer, isCurrent: isCurrent, canBoostAgain: canBoostAgain, myBoostCount: myBoostCount, currentMyBoostCount: 1, replacedBoosts: nil) - controller.updateSubject(subject, count: count) - - Queue.mainQueue().after(0.3) { - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let undoController = UndoOverlayController(presentationData: presentationData, content: .image(image: generateTintedImage(image: UIImage(bundleImageName: "Premium/BoostReplaceIcon"), color: .white)!, title: nil, text: presentationData.strings.ReassignBoost_Success(presentationData.strings.ReassignBoost_Boosts(replacedBoosts), presentationData.strings.ReassignBoost_OtherChannels(inChannels)).string, round: false, undoText: nil), elevatedLayout: false, position: .bottom, action: { _ in return true }) - controller.present(undoController, in: .current) - } - } - - controller.disposed = { - dismissed() - } - - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - updateImpl = { [weak controller] in - if let _ = status.nextLevelBoosts { - if let availableBoost = availableBoosts.first { - currentMyBoostCount += 1 - myBoostCount += 1 - - let _ = (context.engine.peers.applyChannelBoost(peerId: peerId, slots: [availableBoost.slot]) - |> deliverOnMainQueue).startStandalone(completed: { - updatedState.set(context.engine.peers.getChannelBoostStatus(peerId: peerId) - |> map { status in - if let status { - return BoostState(level: Int32(status.level), currentLevelBoosts: Int32(status.currentLevelBoosts), nextLevelBoosts: status.nextLevelBoosts.flatMap(Int32.init), boosts: Int32(status.boosts + 1)) - } else { - return nil - } - }) - }) - - let _ = (updatedState.get() - |> take(1) - |> deliverOnMainQueue).startStandalone(next: { state in - guard let state else { - return - } - let (subject, count) = state.displayData(peer: peer, isCurrent: isCurrent, canBoostAgain: canBoostAgain, myBoostCount: myBoostCount, currentMyBoostCount: currentMyBoostCount) - controller?.updateSubject(subject, count: count) - }) - - availableBoosts.removeFirst() - } else if !occupiedBoosts.isEmpty, let myBoostStatus { - if canBoostAgain { - var dismissReplaceImpl: (() -> Void)? - let replaceController = ReplaceBoostScreen(context: context, peerId: peerId, myBoostStatus: myBoostStatus, replaceBoosts: { slots in - var channelIds = Set() - for boost in myBoostStatus.boosts { - if slots.contains(boost.slot) { - if let peer = boost.peer { - channelIds.insert(peer.id) - } - } - } - - let _ = context.engine.peers.applyChannelBoost(peerId: peerId, slots: slots).startStandalone(completed: { - let _ = combineLatest( - queue: Queue.mainQueue(), - context.engine.peers.getChannelBoostStatus(peerId: peerId), - context.engine.peers.getMyBoostStatus() - ).startStandalone(next: { boostStatus, myBoostStatus in - dismissReplaceImpl?() - PremiumBoostScreen(context: context, contentContext: contentContext, peerId: peerId, isCurrent: isCurrent, status: boostStatus, myBoostStatus: myBoostStatus, replacedBoosts: (Int32(slots.count), Int32(channelIds.count)), forceDark: forceDark, openPeer: openPeer, presentController: presentController, pushController: pushController, dismissed: dismissed) - }) - }) - }) - dismissImpl?() - pushController(replaceController) - dismissReplaceImpl = { [weak replaceController] in - replaceController?.dismiss(animated: true) - } - } else if let boost = occupiedBoosts.first, let occupiedPeer = boost.peer { - if let cooldown = boost.cooldownUntil { - let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - let timeout = cooldown - currentTime - let valueText = timeIntervalString(strings: presentationData.strings, value: timeout, usage: .afterTime, preferLowerValue: false) - let controller = textAlertController( - sharedContext: context.sharedContext, - updatedPresentationData: nil, - title: presentationData.strings.ChannelBoost_Error_BoostTooOftenTitle, - text: presentationData.strings.ChannelBoost_Error_BoostTooOftenText(valueText).string, - actions: [ - TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {}) - ], - parseMarkdown: true - ) - presentController(controller) - } else { - let replaceController = replaceBoostConfirmationController(context: context, fromPeers: [occupiedPeer], toPeer: peer, commit: { - currentMyBoostCount += 1 - myBoostCount += 1 - let _ = (context.engine.peers.applyChannelBoost(peerId: peerId, slots: [boost.slot]) - |> deliverOnMainQueue).startStandalone(completed: { [weak controller] in - let _ = (updatedState.get() - |> take(1) - |> deliverOnMainQueue).startStandalone(next: { [weak controller] state in - guard let state else { - return - } - let (subject, count) = state.displayData(peer: peer, isCurrent: isCurrent, canBoostAgain: canBoostAgain, myBoostCount: myBoostCount, currentMyBoostCount: currentMyBoostCount) - controller?.updateSubject(subject, count: count) - }) - }) - }) - presentController(replaceController) - } - } else { - dismissImpl?() - } - } else { - if isPremium { - if !canBoostAgain { - dismissImpl?() - } else { - let controller = textAlertController( - sharedContext: context.sharedContext, - updatedPresentationData: nil, - title: presentationData.strings.ChannelBoost_MoreBoosts_Title, - text: presentationData.strings.ChannelBoost_MoreBoosts_Text(peer.compactDisplayTitle, "\(premiumConfiguration.boostsPerGiftCount)").string, - actions: [ - TextAlertAction(type: .defaultAction, title: presentationData.strings.ChannelBoost_MoreBoosts_Gift, action: { - dismissImpl?() - - Queue.mainQueue().after(0.4) { - let controller = context.sharedContext.makePremiumGiftController(context: context, source: .channelBoost, completion: nil) - pushController(controller) - } - }), - TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Close, action: {}) - ], - actionLayout: .vertical, - parseMarkdown: true - ) - presentController(controller) - } - } else { - let controller = textAlertController( - sharedContext: context.sharedContext, - updatedPresentationData: nil, - title: presentationData.strings.ChannelBoost_Error_PremiumNeededTitle, - text: presentationData.strings.ChannelBoost_Error_PremiumNeededText, - actions: [ - TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), - TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Yes, action: { - dismissImpl?() - let controller = context.sharedContext.makePremiumIntroController(context: context, source: .channelBoost(peerId), forceDark: forceDark, dismissed: nil) - pushController(controller) - }) - ], - parseMarkdown: true - ) - presentController(controller) - } - } - } else { - dismissImpl?() - } - } - dismissImpl = { [weak controller] in - controller?.dismissAnimated() - } - }) -} diff --git a/submodules/PremiumUI/Sources/SubscriptionsCountItem.swift b/submodules/PremiumUI/Sources/SubscriptionsCountItem.swift index 861c43d7e7..b78317fec1 100644 --- a/submodules/PremiumUI/Sources/SubscriptionsCountItem.swift +++ b/submodules/PremiumUI/Sources/SubscriptionsCountItem.swift @@ -12,14 +12,16 @@ import PresentationDataUtils final class SubscriptionsCountItem: ListViewItem, ItemListItem { let theme: PresentationTheme let strings: PresentationStrings + let systemStyle: ItemListSystemStyle let value: Int32 let values: [Int32] let sectionId: ItemListSectionId let updated: (Int32) -> Void - init(theme: PresentationTheme, strings: PresentationStrings, value: Int32, values: [Int32], sectionId: ItemListSectionId, updated: @escaping (Int32) -> Void) { + init(theme: PresentationTheme, strings: PresentationStrings, systemStyle: ItemListSystemStyle = .legacy, value: Int32, values: [Int32], sectionId: ItemListSectionId, updated: @escaping (Int32) -> Void) { self.theme = theme self.strings = strings + self.systemStyle = systemStyle self.value = value self.values = values self.sectionId = sectionId @@ -229,7 +231,7 @@ private final class SubscriptionsCountItemNode: ListViewItemNode { strongSelf.bottomStripeNode.isHidden = hasCorners } - strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners, glass: item.systemStyle == .glass) : 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.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0) diff --git a/submodules/StatisticsUI/Sources/BoostHeaderItem.swift b/submodules/StatisticsUI/Sources/BoostHeaderItem.swift index 34f192ec51..1588f1a1fb 100644 --- a/submodules/StatisticsUI/Sources/BoostHeaderItem.swift +++ b/submodules/StatisticsUI/Sources/BoostHeaderItem.swift @@ -14,6 +14,7 @@ import MultilineTextComponent import BundleIconComponent import PlainButtonComponent import AccountContext +import GlassBackgroundComponent final class BoostHeaderItem: ItemListControllerHeaderItem { let context: AccountContext @@ -291,9 +292,9 @@ private final class BoostHeaderComponent: CombinedComponent { let progress = Child(PremiumLimitDisplayComponent.self) let text = Child(MultilineTextComponent.self) - let boostButton = Child(PlainButtonComponent.self) - let giveawayButton = Child(PlainButtonComponent.self) - let featuresButton = Child(PlainButtonComponent.self) + let boostButton = Child(HeaderButtonComponent.self) + let giveawayButton = Child(HeaderButtonComponent.self) + let featuresButton = Child(HeaderButtonComponent.self) return { context in let size = context.availableSize @@ -393,18 +394,14 @@ private final class BoostHeaderComponent: CombinedComponent { ) let minButtonWidth: CGFloat = 112.0 -// let buttonSpacing = (size.width - sideInset * 2.0 - minButtonWidth * 3.0) / 2.0 let buttonHeight: CGFloat = 58.0 - + let buttonColor = UIColor(rgb: 0x908eff) + let boostButton = boostButton.update( - component: PlainButtonComponent( - content: AnyComponent( - BoostButtonComponent( - iconName: "Premium/Boosts/Boost", - title: component.strings.ChannelBoost_Header_Boost - ) - ), - effectAlignment: .center, + component: HeaderButtonComponent( + title: component.strings.ChannelBoost_Header_Boost, + buttonColor: buttonColor, + iconName: "Premium/Boosts/Boost", action: { component.openBoost() } @@ -417,14 +414,10 @@ private final class BoostHeaderComponent: CombinedComponent { ) let giveawayButton = giveawayButton.update( - component: PlainButtonComponent( - content: AnyComponent( - BoostButtonComponent( - iconName: "Premium/Boosts/Giveaway", - title: component.strings.ChannelBoost_Header_Giveaway - ) - ), - effectAlignment: .center, + component: HeaderButtonComponent( + title: component.strings.ChannelBoost_Header_Giveaway, + buttonColor: buttonColor, + iconName: "Premium/Boosts/Giveaway", action: { component.createGiveaway() } @@ -437,14 +430,10 @@ private final class BoostHeaderComponent: CombinedComponent { ) let featuresButton = featuresButton.update( - component: PlainButtonComponent( - content: AnyComponent( - BoostButtonComponent( - iconName: "Premium/Boosts/Features", - title: component.strings.ChannelBoost_Header_Features - ) - ), - effectAlignment: .center, + component: HeaderButtonComponent( + title: component.strings.ChannelBoost_Header_Features, + buttonColor: buttonColor, + iconName: "Premium/Boosts/Features", action: { component.openFeatures() } @@ -537,3 +526,167 @@ private final class BoostButtonComponent: CombinedComponent { } } } + +private final class HeaderButtonComponent: Component { + let title: String + let buttonColor: UIColor + let iconName: String + let isLocked: Bool + let action: () -> Void + + public init( + title: String, + buttonColor: UIColor, + iconName: String, + isLocked: Bool = false, + action: @escaping () -> Void + ) { + self.title = title + self.buttonColor = buttonColor + self.iconName = iconName + self.isLocked = isLocked + self.action = action + } + + static func ==(lhs: HeaderButtonComponent, rhs: HeaderButtonComponent) -> Bool { + if lhs.title != rhs.title { + return false + } + if lhs.buttonColor != rhs.buttonColor { + return false + } + if lhs.iconName != rhs.iconName { + return false + } + if lhs.isLocked != rhs.isLocked { + return false + } + return true + } + + final class View: UIView { + private var component: HeaderButtonComponent? + private weak var componentState: EmptyComponentState? + + private let backgroundView = GlassBackgroundView() + private let title = ComponentView() + private let icon = ComponentView() + private let lockIcon = ComponentView() + private let button = HighlightTrackingButton() + + override init(frame: CGRect) { + super.init(frame: frame) + + self.addSubview(self.backgroundView) + self.backgroundView.contentView.addSubview(self.button) + + self.button.addTarget(self, action: #selector(self.buttonPressed), for: .touchUpInside) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc private func buttonPressed() { + if let component = self.component { + component.action() + } + } + + func update(component: HeaderButtonComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + self.component = component + self.componentState = state + + let bounds = CGRect(origin: .zero, size: availableSize) + + self.backgroundView.update(size: bounds.size, cornerRadius: 16.0, isDark: true, tintColor: .init(kind: .custom(style: .default, color: component.buttonColor)), isInteractive: true, transition: transition) + transition.setFrame(view: self.backgroundView, frame: bounds) + + let iconSize = self.icon.update( + transition: transition, + component: AnyComponent( + BundleIconComponent( + name: component.iconName, + tintColor: UIColor.white + ) + ), + environment: {}, + containerSize: availableSize + ) + if let iconView = self.icon.view { + if iconView.superview == nil { + iconView.isUserInteractionEnabled = false + self.backgroundView.contentView.addSubview(iconView) + } + iconView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - iconSize.width) / 2.0), y: floorToScreenPixels(22.0 - iconSize.height * 0.5)), size: iconSize) + } + + let titleSize = self.title.update( + transition: transition, + component: AnyComponent( + MultilineTextComponent( + text: .plain(NSAttributedString( + string: component.title, + font: Font.regular(11.0), + textColor: UIColor.white, + paragraphAlignment: .natural + )), + horizontalAlignment: .center, + maximumNumberOfLines: 1 + ) + ), + environment: {}, + containerSize: CGSize(width: availableSize.width - 16.0, height: availableSize.height) + ) + + var totalTitleWidth = titleSize.width + var titleOriginX = availableSize.width / 2.0 - totalTitleWidth / 2.0 + if component.isLocked { + let titleSpacing: CGFloat = 3.0 + + let lockIconSize = self.lockIcon.update( + transition: transition, + component: AnyComponent( + BundleIconComponent( + name: "Chat List/StatusLockIcon", + tintColor: .white + ) + ), + environment: {}, + containerSize: availableSize + ) + totalTitleWidth += lockIconSize.width + titleSpacing + titleOriginX = availableSize.width / 2.0 - totalTitleWidth / 2.0 + + if let lockIconView = self.lockIcon.view { + if lockIconView.superview == nil { + lockIconView.isUserInteractionEnabled = false + self.backgroundView.contentView.addSubview(lockIconView) + } + lockIconView.frame = CGRect(origin: CGPoint(x: titleOriginX, y: floorToScreenPixels(42.0 - lockIconSize.height * 0.5)), size: lockIconSize) + } + titleOriginX += lockIconSize.width + titleSpacing + } + + if let titleView = self.title.view { + if titleView.superview == nil { + titleView.isUserInteractionEnabled = false + self.backgroundView.contentView.addSubview(titleView) + } + titleView.frame = CGRect(origin: CGPoint(x: titleOriginX, y: floorToScreenPixels(42.0 - titleSize.height * 0.5)), size: titleSize) + } + + self.button.frame = bounds + + return availableSize + } + } + + func makeView() -> View { + return View(frame: CGRect()) + } + + func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) + } +} diff --git a/submodules/StatisticsUI/Sources/ChannelStatsController.swift b/submodules/StatisticsUI/Sources/ChannelStatsController.swift index 0eee76ebcc..a0f5a6df6b 100644 --- a/submodules/StatisticsUI/Sources/ChannelStatsController.swift +++ b/submodules/StatisticsUI/Sources/ChannelStatsController.swift @@ -932,7 +932,7 @@ private enum StatsEntry: ItemListNodeEntry { let .adsProceedsInfo(_, text): return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section) case let .overview(_, stats): - return StatsOverviewItem(context: arguments.context, presentationData: presentationData, isGroup: false, stats: stats, sectionId: self.section, style: .blocks) + return StatsOverviewItem(context: arguments.context, presentationData: presentationData, systemStyle: .glass, isGroup: false, stats: stats, sectionId: self.section, style: .blocks) case let .growthGraph(_, _, _, graph, type), let .followersGraph(_, _, _, graph, type), let .notificationsGraph(_, _, _, graph, type), @@ -943,15 +943,15 @@ private enum StatsEntry: ItemListNodeEntry { let .reactionsByEmotionGraph(_, _, _, graph, type), let .storyReactionsByEmotionGraph(_, _, _, graph, type), let .adsImpressionsGraph(_, _, _, graph, type): - return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, sectionId: self.section, style: .blocks) + return StatsGraphItem(presentationData: presentationData, systemStyle: .glass, graph: graph, type: type, sectionId: self.section, style: .blocks) case let .adsTonRevenueGraph(_, _, _, graph, type, rate): - return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, conversionRate: rate, sectionId: self.section, style: .blocks) + return StatsGraphItem(presentationData: presentationData, systemStyle: .glass, graph: graph, type: type, conversionRate: rate, sectionId: self.section, style: .blocks) case let .adsStarsRevenueGraph(_, _, _, graph, type, rate): - return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, conversionRate: rate, sectionId: self.section, style: .blocks) + return StatsGraphItem(presentationData: presentationData, systemStyle: .glass, graph: graph, type: type, conversionRate: rate, sectionId: self.section, style: .blocks) case let .postInteractionsGraph(_, _, _, graph, type), let .instantPageInteractionsGraph(_, _, _, graph, type), let .storyInteractionsGraph(_, _, _, graph, type): - return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, getDetailsData: { date, completion in + return StatsGraphItem(presentationData: presentationData, systemStyle: .glass, graph: graph, type: type, getDetailsData: { date, completion in let _ = arguments.loadDetailedGraph(graph, Int64(date.timeIntervalSince1970) * 1000).start(next: { graph in if let graph = graph, case let .Loaded(_, data) = graph { completion(data) @@ -1035,7 +1035,7 @@ private enum StatsEntry: ItemListNodeEntry { arguments.openBoost(boost) }) case let .boostersExpand(theme, title): - return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: { + return ItemListPeerActionItem(presentationData: presentationData, systemStyle: .glass, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: { arguments.expandBoosters() }) case let .boostLevel(_, count, level, position): @@ -1046,15 +1046,15 @@ private enum StatsEntry: ItemListNodeEntry { return StatsOverviewItem(context: arguments.context, presentationData: presentationData, isGroup: isGroup, stats: stats, sectionId: self.section, style: .blocks) case let .boostLink(_, link): let invite: ExportedInvitation = .link(link: link, title: nil, isPermanent: false, requestApproval: false, isRevoked: false, adminId: PeerId(0), date: 0, startDate: nil, expireDate: nil, usageLimit: nil, count: nil, requestedCount: nil, pricing: nil) - return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, invite: invite, count: 0, peers: [], displayButton: true, displayImporters: false, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: { + return ItemListPermanentInviteLinkItem(context: arguments.context, presentationData: presentationData, systemStyle: .glass, invite: invite, count: 0, peers: [], displayButton: true, displayImporters: false, buttonColor: nil, sectionId: self.section, style: .blocks, copyAction: { arguments.copyBoostLink(link) }, shareAction: { arguments.shareBoostLink(link) }, contextAction: nil, viewAction: nil, openCallAction: nil, tag: nil) case let .boostersPlaceholder(_, text): - return ItemListPlaceholderItem(theme: presentationData.theme, text: text, sectionId: self.section, style: .blocks) + return ItemListPlaceholderItem(theme: presentationData.theme, systemStyle: .glass, text: text, sectionId: self.section, style: .blocks) case let .boostGifts(theme, title): - return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.addBoostsIcon(theme), title: title, sectionId: self.section, editing: false, action: { + return ItemListPeerActionItem(presentationData: presentationData, systemStyle: .glass, icon: PresentationResourcesItemList.addBoostsIcon(theme), title: title, sectionId: self.section, editing: false, action: { arguments.openGifts() }) case let .boostPrepaid(_, _, title, subtitle, prepaidGiveaway): @@ -1200,7 +1200,7 @@ private enum StatsEntry: ItemListNodeEntry { label.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: label.string)) } - return ItemListDisclosureItem(presentationData: presentationData, title: "", attributedTitle: title, label: "", attributedLabel: label, labelStyle: .coloredText(labelColor), additionalDetailLabel: detailText, additionalDetailLabelColor: detailColor, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: { + return ItemListDisclosureItem(presentationData: presentationData, systemStyle: .glass, title: "", attributedTitle: title, label: "", attributedLabel: label, labelStyle: .coloredText(labelColor), additionalDetailLabel: detailText, additionalDetailLabelColor: detailColor, sectionId: self.section, style: .blocks, disclosureStyle: .none, action: { arguments.openTonTransaction(transaction) }) case let .adsStarsTransaction(_, _, transaction): @@ -1208,7 +1208,7 @@ private enum StatsEntry: ItemListNodeEntry { arguments.openStarsTransaction(transaction) }, sectionId: self.section, style: .blocks) case let .adsTransactionsExpand(theme, title, stars): - return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: { + return ItemListPeerActionItem(presentationData: presentationData, systemStyle: .glass, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: { arguments.expandTransactions(stars) }) case let .adsCpmToggle(_, title, minLevel, value): @@ -1219,7 +1219,7 @@ private enum StatsEntry: ItemListNodeEntry { level: Int(minLevel) )) } - return ItemListSwitchItem(presentationData: presentationData, title: title, titleBadgeComponent: badgeComponent, value: value == true, enableInteractiveChanges: value != nil, enabled: true, displayLocked: value == nil, sectionId: self.section, style: .blocks, updated: { updatedValue in + return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: title, titleBadgeComponent: badgeComponent, value: value == true, enableInteractiveChanges: value != nil, enabled: true, displayLocked: value == nil, sectionId: self.section, style: .blocks, updated: { updatedValue in if value != nil { arguments.updateCpmEnabled(updatedValue) } else { @@ -1229,7 +1229,7 @@ private enum StatsEntry: ItemListNodeEntry { arguments.presentCpmLocked() }) case .earnStarsInfo: - return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.earnStars, title: presentationData.strings.Monetization_EarnStarsInfo_Title, titleBadge: nil, label: presentationData.strings.Monetization_EarnStarsInfo_Text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, action: { + return ItemListDisclosureItem(presentationData: presentationData, systemStyle: .glass, icon: PresentationResourcesSettings.earnStars, title: presentationData.strings.Monetization_EarnStarsInfo_Title, titleBadge: nil, label: presentationData.strings.Monetization_EarnStarsInfo_Text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, action: { arguments.openEarnStars() }) } diff --git a/submodules/StatisticsUI/Sources/GroupStatsController.swift b/submodules/StatisticsUI/Sources/GroupStatsController.swift index 324a0a5eaa..7109e9d382 100644 --- a/submodules/StatisticsUI/Sources/GroupStatsController.swift +++ b/submodules/StatisticsUI/Sources/GroupStatsController.swift @@ -381,7 +381,7 @@ private enum StatsEntry: ItemListNodeEntry { let .topInvitersTitle(_, text, dates): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, accessoryText: ItemListSectionHeaderAccessoryText(value: dates, color: .generic), sectionId: self.section) case let .overview(_, stats): - return StatsOverviewItem(context: arguments.context, presentationData: presentationData, isGroup: true, stats: stats, sectionId: self.section, style: .blocks) + return StatsOverviewItem(context: arguments.context, presentationData: presentationData, systemStyle: .glass, isGroup: true, stats: stats, sectionId: self.section, style: .blocks) case let .growthGraph(_, _, _, graph, type), let .membersGraph(_, _, _, graph, type), let .newMembersBySourceGraph(_, _, _, graph, type), @@ -390,7 +390,7 @@ private enum StatsEntry: ItemListNodeEntry { let .actionsGraph(_, _, _, graph, type), let .topHoursGraph(_, _, _, graph, type), let .topWeekdaysGraph(_, _, _, graph, type): - return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, sectionId: self.section, style: .blocks) + return StatsGraphItem(presentationData: presentationData, systemStyle: .glass, graph: graph, type: type, sectionId: self.section, style: .blocks) case let .topPoster(_, _, strings, dateTimeFormat, peer, topPoster, revealed, canPromote): var textComponents: [String] = [] if topPoster.messageCount > 0 { @@ -410,13 +410,13 @@ private enum StatsEntry: ItemListNodeEntry { })) } } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: .firstLast, context: arguments.context, peer: peer, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(textComponents.joined(separator: ", "), .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, highlighted: false, selectable: arguments.context.account.peerId != peer.id, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, systemStyle: .glass, dateTimeFormat: dateTimeFormat, nameDisplayOrder: .firstLast, context: arguments.context, peer: peer, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(textComponents.joined(separator: ", "), .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, highlighted: false, selectable: arguments.context.account.peerId != peer.id, sectionId: self.section, action: { arguments.openPeer(peer) }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in arguments.setPostersPeerIdWithRevealedOptions(peerId, fromPeerId) }, removePeer: { _ in }) case let .topPostersExpand(theme, title): - return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: { + return ItemListPeerActionItem(presentationData: presentationData, systemStyle: .glass, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: { arguments.expandTopPosters() }) case let .topAdmin(_, _, strings, dateTimeFormat, peer, topAdmin, revealed, canPromote): @@ -441,13 +441,13 @@ private enum StatsEntry: ItemListNodeEntry { })) } } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: .firstLast, context: arguments.context, peer: peer, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(textComponents.joined(separator: ", "), .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, highlighted: false, selectable: arguments.context.account.peerId != peer.id, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, systemStyle: .glass, dateTimeFormat: dateTimeFormat, nameDisplayOrder: .firstLast, context: arguments.context, peer: peer, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(textComponents.joined(separator: ", "), .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, highlighted: false, selectable: arguments.context.account.peerId != peer.id, sectionId: self.section, action: { arguments.openPeer(peer) }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in arguments.setAdminsPeerIdWithRevealedOptions(peerId, fromPeerId) }, removePeer: { _ in }) case let .topAdminsExpand(theme, title): - return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: { + return ItemListPeerActionItem(presentationData: presentationData, systemStyle: .glass, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: { arguments.expandTopAdmins() }) case let .topInviter(_, _, strings, dateTimeFormat, peer, topInviter, revealed, canPromote): @@ -464,13 +464,13 @@ private enum StatsEntry: ItemListNodeEntry { })) } } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: .firstLast, context: arguments.context, peer: peer, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(textComponents.joined(separator: ", "), .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, highlighted: false, selectable: arguments.context.account.peerId != peer.id, sectionId: self.section, action: { + return ItemListPeerItem(presentationData: presentationData, systemStyle: .glass, dateTimeFormat: dateTimeFormat, nameDisplayOrder: .firstLast, context: arguments.context, peer: peer, height: .generic, aliasHandling: .standard, nameColor: .primary, nameStyle: .plain, presence: nil, text: .text(textComponents.joined(separator: ", "), .secondary), label: .none, editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, highlighted: false, selectable: arguments.context.account.peerId != peer.id, sectionId: self.section, action: { arguments.openPeer(peer) }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in arguments.setInvitersPeerIdWithRevealedOptions(peerId, fromPeerId) }, removePeer: { _ in }) case let .topInvitersExpand(theme, title): - return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: { + return ItemListPeerActionItem(presentationData: presentationData, systemStyle: .glass, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: { arguments.expandTopInviters() }) } diff --git a/submodules/StatisticsUI/Sources/MessageStatsController.swift b/submodules/StatisticsUI/Sources/MessageStatsController.swift index 2e8e688e4d..a1d3cf316b 100644 --- a/submodules/StatisticsUI/Sources/MessageStatsController.swift +++ b/submodules/StatisticsUI/Sources/MessageStatsController.swift @@ -160,9 +160,9 @@ private enum StatsEntry: ItemListNodeEntry { let .publicForwardsTitle(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .overview(_, stats, storyViews, publicShares): - return StatsOverviewItem(context: arguments.context, presentationData: presentationData, isGroup: false, stats: stats as? Stats, storyViews: storyViews, publicShares: publicShares, sectionId: self.section, style: .blocks) + return StatsOverviewItem(context: arguments.context, presentationData: presentationData, systemStyle: .glass, isGroup: false, stats: stats as? Stats, storyViews: storyViews, publicShares: publicShares, sectionId: self.section, style: .blocks) case let .interactionsGraph(_, _, _, graph, type, noInitialZoom), let .reactionsGraph(_, _, _, graph, type, noInitialZoom): - return StatsGraphItem(presentationData: presentationData, graph: graph, type: type, noInitialZoom: noInitialZoom, getDetailsData: { date, completion in + return StatsGraphItem(presentationData: presentationData, systemStyle: .glass, graph: graph, type: type, noInitialZoom: noInitialZoom, getDetailsData: { date, completion in let _ = arguments.loadDetailedGraph(graph, Int64(date.timeIntervalSince1970) * 1000).start(next: { graph in if let graph = graph, case let .Loaded(_, data) = graph { completion(data) @@ -197,7 +197,7 @@ private enum StatsEntry: ItemListNodeEntry { reactions = Int32(story.views?.reactedCount ?? 0) isStory = true } - return StatsMessageItem(context: arguments.context, presentationData: presentationData, peer: peer, item: item, views: views, reactions: reactions, forwards: forwards, isPeer: true, sectionId: self.section, style: .blocks, action: { + return StatsMessageItem(context: arguments.context, presentationData: presentationData, systemStyle: .glass, peer: peer, item: item, views: views, reactions: reactions, forwards: forwards, isPeer: true, sectionId: self.section, style: .blocks, action: { switch item { case let .message(message): arguments.openMessage(message.id) diff --git a/submodules/StatisticsUI/Sources/StatsGraphItem.swift b/submodules/StatisticsUI/Sources/StatsGraphItem.swift index 0ab64e4546..8fb221d919 100644 --- a/submodules/StatisticsUI/Sources/StatsGraphItem.swift +++ b/submodules/StatisticsUI/Sources/StatsGraphItem.swift @@ -14,6 +14,7 @@ import ListItemComponentAdaptor public final class StatsGraphItem: ListViewItem, ItemListItem, ListItemComponentAdaptor.ItemGenerator { let presentationData: ItemListPresentationData + let systemStyle: ItemListSystemStyle let graph: StatsGraph let type: ChartType let noInitialZoom: Bool @@ -22,8 +23,9 @@ public final class StatsGraphItem: ListViewItem, ItemListItem, ListItemComponent public let sectionId: ItemListSectionId let style: ItemListStyle - public init(presentationData: ItemListPresentationData, graph: StatsGraph, type: ChartType, noInitialZoom: Bool = false, conversionRate: Double = 1.0, getDetailsData: ((Date, @escaping (String?) -> Void) -> Void)? = nil, sectionId: ItemListSectionId, style: ItemListStyle) { + public init(presentationData: ItemListPresentationData, systemStyle: ItemListSystemStyle = .legacy, graph: StatsGraph, type: ChartType, noInitialZoom: Bool = false, conversionRate: Double = 1.0, getDetailsData: ((Date, @escaping (String?) -> Void) -> Void)? = nil, sectionId: ItemListSectionId, style: ItemListStyle) { self.presentationData = presentationData + self.systemStyle = systemStyle self.graph = graph self.type = type self.noInitialZoom = noInitialZoom @@ -215,6 +217,7 @@ public final class StatsGraphItemNode: ListViewItemNode { contentSize.height += visibilityHeight } contentSize.height += 7.0 + contentSize.height += 8.0 let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in @@ -280,9 +283,9 @@ public final class StatsGraphItemNode: ListViewItemNode { strongSelf.bottomStripeNode.isHidden = hasCorners } - strongSelf.chartContainerNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: layout.size.width - leftInset - rightInset, height: contentSize.height)) + strongSelf.chartContainerNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 8.0), size: CGSize(width: layout.size.width - leftInset - rightInset, height: contentSize.height - 8.0)) strongSelf.chartNode.frame = CGRect(origin: CGPoint(x: 0.0, y: item.type == .hourlyStep ? -40.0 : 0.0), size: CGSize(width: layout.size.width - leftInset - rightInset, height: 750.0)) - strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners, glass: item.systemStyle == .glass) : 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.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0) diff --git a/submodules/StatisticsUI/Sources/StatsMessageItem.swift b/submodules/StatisticsUI/Sources/StatsMessageItem.swift index 641da989c6..b7aa9dc8fb 100644 --- a/submodules/StatisticsUI/Sources/StatsMessageItem.swift +++ b/submodules/StatisticsUI/Sources/StatsMessageItem.swift @@ -18,6 +18,7 @@ import AvatarNode public class StatsMessageItem: ListViewItem, ItemListItem { let context: AccountContext let presentationData: ItemListPresentationData + let systemStyle: ItemListSystemStyle let peer: Peer let item: StatsPostItem let views: Int32 @@ -30,9 +31,10 @@ public class StatsMessageItem: ListViewItem, ItemListItem { let openStory: (UIView) -> Void let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? - init(context: AccountContext, presentationData: ItemListPresentationData, peer: Peer, item: StatsPostItem, views: Int32, reactions: Int32, forwards: Int32, isPeer: Bool = false, sectionId: ItemListSectionId, style: ItemListStyle, action: (() -> Void)?, openStory: @escaping (UIView) -> Void, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?) { + init(context: AccountContext, presentationData: ItemListPresentationData, systemStyle: ItemListSystemStyle = .glass, peer: Peer, item: StatsPostItem, views: Int32, reactions: Int32, forwards: Int32, isPeer: Bool = false, sectionId: ItemListSectionId, style: ItemListStyle, action: (() -> Void)?, openStory: @escaping (UIView) -> Void, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?) { self.context = context self.presentationData = presentationData + self.systemStyle = systemStyle self.peer = peer self.item = item self.views = views @@ -576,7 +578,7 @@ final class StatsMessageItemNode: ListViewItemNode, ItemListItemNode { strongSelf.bottomStripeNode.isHidden = hasCorners } - strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners, glass: item.systemStyle == .glass) : 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.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0) diff --git a/submodules/StatisticsUI/Sources/StatsOverviewItem.swift b/submodules/StatisticsUI/Sources/StatsOverviewItem.swift index 789526910c..40a5a34050 100644 --- a/submodules/StatisticsUI/Sources/StatsOverviewItem.swift +++ b/submodules/StatisticsUI/Sources/StatsOverviewItem.swift @@ -40,9 +40,10 @@ extension StarsRevenueStats: Stats { } -class StatsOverviewItem: ListViewItem, ItemListItem { +final class StatsOverviewItem: ListViewItem, ItemListItem { let context: AccountContext let presentationData: ItemListPresentationData + let systemStyle: ItemListSystemStyle let isGroup: Bool let stats: Stats? let additionalStats: Stats? @@ -51,9 +52,10 @@ class StatsOverviewItem: ListViewItem, ItemListItem { let sectionId: ItemListSectionId let style: ItemListStyle - init(context: AccountContext, presentationData: ItemListPresentationData, isGroup: Bool, stats: Stats?, additionalStats: Stats? = nil, storyViews: EngineStoryItem.Views? = nil, publicShares: Int32? = nil, sectionId: ItemListSectionId, style: ItemListStyle) { + init(context: AccountContext, presentationData: ItemListPresentationData, systemStyle: ItemListSystemStyle = .glass, isGroup: Bool, stats: Stats?, additionalStats: Stats? = nil, storyViews: EngineStoryItem.Views? = nil, publicShares: Int32? = nil, sectionId: ItemListSectionId, style: ItemListStyle) { self.context = context self.presentationData = presentationData + self.systemStyle = systemStyle self.isGroup = isGroup self.stats = stats self.additionalStats = additionalStats @@ -968,7 +970,7 @@ class StatsOverviewItemNode: ListViewItemNode { strongSelf.bottomStripeNode.isHidden = hasCorners } - strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners, glass: item.systemStyle == .glass) : 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.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0) diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index db374e57f0..d869bf841a 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -6416,80 +6416,6 @@ private final class HeaderButtonComponent: Component { func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) } - -// static var body: Body { -// let background = Child(RoundedRectangle.self) -// let title = Child(MultilineTextComponent.self) -// let icon = Child(BundleIconComponent.self) -// let lockIcon = Child(BundleIconComponent.self) -// -// return { context in -// let component = context.component -// -// let background = background.update( -// component: RoundedRectangle( -// color: UIColor.white.withAlphaComponent(0.16), -// cornerRadius: 16.0 -// ), -// availableSize: context.availableSize, -// transition: .immediate -// ) -// context.add(background -// .position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0)) -// ) -// -// let icon = icon.update( -// component: BundleIconComponent( -// name: component.iconName, -// tintColor: UIColor.white -// ), -// availableSize: context.availableSize, -// transition: .immediate -// ) -// context.add(icon -// .position(CGPoint(x: context.availableSize.width / 2.0, y: 22.0)) -// ) -// -// let title = title.update( -// component: MultilineTextComponent( -// text: .plain(NSAttributedString( -// string: component.title, -// font: Font.regular(11.0), -// textColor: UIColor.white, -// paragraphAlignment: .natural -// )), -// horizontalAlignment: .center, -// maximumNumberOfLines: 1 -// ), -// availableSize: CGSize(width: context.availableSize.width - 16.0, height: context.availableSize.height), -// transition: .immediate -// ) -// var totalTitleWidth = title.size.width -// var titleOriginX = context.availableSize.width / 2.0 - totalTitleWidth / 2.0 -// if component.isLocked { -// let titleSpacing: CGFloat = 3.0 -// let lockIcon = lockIcon.update( -// component: BundleIconComponent( -// name: "Chat List/StatusLockIcon", -// tintColor: UIColor.white -// ), -// availableSize: context.availableSize, -// transition: .immediate -// ) -// totalTitleWidth += lockIcon.size.width + titleSpacing -// titleOriginX = context.availableSize.width / 2.0 - totalTitleWidth / 2.0 -// context.add(lockIcon -// .position(CGPoint(x: titleOriginX + lockIcon.size.width / 2.0, y: 42.0)) -// ) -// titleOriginX += lockIcon.size.width + titleSpacing -// } -// context.add(title -// .position(CGPoint(x: titleOriginX + title.size.width / 2.0, y: 42.0)) -// ) -// -// return context.availableSize -// } -// } } private struct GiftViewConfiguration { diff --git a/submodules/TelegramUI/Components/ItemListDatePickerItem/Sources/ItemListDatePickerItem.swift b/submodules/TelegramUI/Components/ItemListDatePickerItem/Sources/ItemListDatePickerItem.swift index db1bb62322..b4f89aa2ee 100644 --- a/submodules/TelegramUI/Components/ItemListDatePickerItem/Sources/ItemListDatePickerItem.swift +++ b/submodules/TelegramUI/Components/ItemListDatePickerItem/Sources/ItemListDatePickerItem.swift @@ -9,6 +9,7 @@ import DatePickerNode public class ItemListDatePickerItem: ListViewItem, ItemListItem { let presentationData: ItemListPresentationData + let systemStyle: ItemListSystemStyle let dateTimeFormat: PresentationDateTimeFormat let date: Int32? let minDate: Int32? @@ -28,6 +29,7 @@ public class ItemListDatePickerItem: ListViewItem, ItemListItem { public init( presentationData: ItemListPresentationData, + systemStyle: ItemListSystemStyle = .legacy, dateTimeFormat: PresentationDateTimeFormat, date: Int32?, minDate: Int32? = nil, @@ -43,6 +45,7 @@ public class ItemListDatePickerItem: ListViewItem, ItemListItem { tag: ItemListItemTag? = nil ) { self.presentationData = presentationData + self.systemStyle = systemStyle self.dateTimeFormat = dateTimeFormat self.date = date self.minDate = minDate @@ -158,14 +161,14 @@ public class ItemListDatePickerItemNode: ListViewItemNode, ItemListItemNode { let width = params.width - params.leftInset - params.rightInset let constrainedWidth = min(390.0, width) let cellSize = floor((constrainedWidth - 12.0 * 2.0) / 7.0) - let pickerHeight = 122.0 + cellSize * 6.0 + let pickerHeight = 132.0 + cellSize * 6.0 let height: CGFloat if item.displayingDateSelection { height = pickerHeight } else if item.displayingTimeSelection { height = 260.0 } else { - height = 44.0 + height = 56.0 } switch item.style { case .plain: @@ -244,7 +247,7 @@ public class ItemListDatePickerItemNode: ListViewItemNode, ItemListItemNode { strongSelf.bottomStripeNode.isHidden = hasCorners } - strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil + strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners, glass: item.systemStyle == .glass) : nil transition.updateFrame(node: 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)))) transition.updateFrame(node: strongSelf.maskNode, frame: strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)) @@ -291,7 +294,7 @@ public class ItemListDatePickerItemNode: ListViewItemNode, ItemListItemNode { datePickerNode.date = item.date.flatMap { Date(timeIntervalSince1970: TimeInterval($0)) } let datePickerSize = CGSize(width: width, height: pickerHeight) - datePickerNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((params.width - datePickerSize.width) / 2.0), y: 0.0), size: datePickerSize) + datePickerNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((params.width - datePickerSize.width) / 2.0), y: 6.0), size: datePickerSize) datePickerNode.updateLayout(size: datePickerSize, transition: .immediate) transition.updateFrame(node: strongSelf.containerNode, frame: CGRect(origin: .zero, size: CGSize(width: params.width, height: contentSize.height))) diff --git a/submodules/TelegramUI/Components/PeerInfo/ProfileLevelInfoScreen/Sources/ProfileLevelInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/ProfileLevelInfoScreen/Sources/ProfileLevelInfoScreen.swift index a5ab5c2553..c81e76a89c 100644 --- a/submodules/TelegramUI/Components/PeerInfo/ProfileLevelInfoScreen/Sources/ProfileLevelInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/ProfileLevelInfoScreen/Sources/ProfileLevelInfoScreen.swift @@ -479,10 +479,8 @@ private final class SheetContent: Component { contentHeight += itemSize.height } - contentHeight += 31.0 - - contentHeight += 82.0 - + contentHeight += 113.0 + return CGSize(width: availableSize.width, height: contentHeight) } }