Various improvements

This commit is contained in:
Ilya Laktyushin 2022-06-07 00:04:28 +04:00
parent ac1f276d15
commit b5dcba8bae
6 changed files with 224 additions and 91 deletions

View File

@ -7559,6 +7559,7 @@ Sorry for the inconvenience.";
"Group.Username.RemoveExistingUsernamesFinalInfo" = "You have reserved too many public links. Try revoking the link from an older group or channel, or create a private one instead."; "Group.Username.RemoveExistingUsernamesFinalInfo" = "You have reserved too many public links. Try revoking the link from an older group or channel, or create a private one instead.";
"OldChannels.TooManyCommunitiesText" = "You are a member of **%@** groups and channels. Please leave some before joining a new one or upgrade to **Telegram Premium** to double the limit to **%@** groups and channels."; "OldChannels.TooManyCommunitiesText" = "You are a member of **%@** groups and channels. Please leave some before joining a new one or upgrade to **Telegram Premium** to double the limit to **%@** groups and channels.";
"OldChannels.TooManyCommunitiesNoPremiumText" = "You are a member of **%@** groups and channels. Please leave some before joining a new one. We are working to let you increase this limit in the future.";
"OldChannels.TooManyCommunitiesFinalText" = "You are a member of **%@** groups and channels. Please leave some before joining a new one."; "OldChannels.TooManyCommunitiesFinalText" = "You are a member of **%@** groups and channels. Please leave some before joining a new one.";
"OldChannels.LeaveCommunities_1" = "Leave %@ Community"; "OldChannels.LeaveCommunities_1" = "Leave %@ Community";
"OldChannels.LeaveCommunities_any" = "Leave %@ Communities"; "OldChannels.LeaveCommunities_any" = "Leave %@ Communities";

View File

@ -862,6 +862,7 @@ open class ItemListControllerNode: ASDisplayNode {
updateFooterItem = true updateFooterItem = true
} }
if updateFooterItem { if updateFooterItem {
let hadFooter = self.footerItem != nil
self.footerItem = transition.footerItem self.footerItem = transition.footerItem
if let footerItem = transition.footerItem { if let footerItem = transition.footerItem {
let updatedNode = footerItem.node(current: self.footerItemNode) let updatedNode = footerItem.node(current: self.footerItemNode)
@ -870,13 +871,27 @@ open class ItemListControllerNode: ASDisplayNode {
} }
if self.footerItemNode !== updatedNode { if self.footerItemNode !== updatedNode {
self.footerItemNode = updatedNode self.footerItemNode = updatedNode
let footerHeight: CGFloat
if let validLayout = self.validLayout { if let validLayout = self.validLayout {
let _ = updatedNode.updateLayout(layout: validLayout.0, transition: .immediate) footerHeight = updatedNode.updateLayout(layout: validLayout.0, transition: .immediate)
} else {
footerHeight = 100.0
} }
self.addSubnode(updatedNode) self.addSubnode(updatedNode)
if !hadFooter && !transition.firstTime {
updatedNode.layer.animatePosition(from: CGPoint(x: 0.0, y: footerHeight), to: .zero, duration: 0.25, additive: true)
}
} }
} else if let footerItemNode = self.footerItemNode { } else if let footerItemNode = self.footerItemNode {
footerItemNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak footerItemNode] _ in let footerHeight: CGFloat
if let validLayout = self.validLayout {
footerHeight = footerItemNode.updateLayout(layout: validLayout.0, transition: .immediate)
} else {
footerHeight = 100.0
}
footerItemNode.layer.animatePosition(from: .zero, to: CGPoint(x: 0.0, y: footerHeight), duration: 0.25, removeOnCompletion: false, additive: true, completion: { [weak footerItemNode] _ in
footerItemNode?.removeFromSupernode() footerItemNode?.removeFromSupernode()
}) })
self.footerItemNode = nil self.footerItemNode = nil

View File

@ -89,7 +89,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
case publicLinkHeader(PresentationTheme, String) case publicLinkHeader(PresentationTheme, String)
case publicLinkAvailability(PresentationTheme, String, Bool) case publicLinkAvailability(PresentationTheme, String, Bool)
case linksLimitInfo(PresentationTheme, String, Int32, Int32) case linksLimitInfo(PresentationTheme, String, Int32, Int32, Int32, Bool)
case editablePublicLink(PresentationTheme, PresentationStrings, String, String) case editablePublicLink(PresentationTheme, PresentationStrings, String, String)
case privateLinkHeader(PresentationTheme, String) case privateLinkHeader(PresentationTheme, String)
case privateLink(PresentationTheme, ExportedInvitation?, [EnginePeer], Int32, Bool) case privateLink(PresentationTheme, ExportedInvitation?, [EnginePeer], Int32, Bool)
@ -228,12 +228,12 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .linksLimitInfo(lhsTheme, lhsText, lhsLimit, lhsPremiumLimit): case let .linksLimitInfo(lhsTheme, lhsText, lhsCount, lhsLimit, lhsPremiumLimit, lhsIsPremiumDisabled):
if case let .linksLimitInfo(rhsTheme, rhsText, rhsLimit, rhsPremiumLimit) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsLimit == rhsLimit, lhsPremiumLimit == rhsPremiumLimit { if case let .linksLimitInfo(rhsTheme, rhsText, rhsCount, rhsLimit, rhsPremiumLimit, rhsIsPremiumDisabled) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsCount == rhsCount, lhsLimit == rhsLimit, lhsPremiumLimit == rhsPremiumLimit, lhsIsPremiumDisabled == rhsIsPremiumDisabled {
return true return true
} else { } else {
return false return false
} }
case let .privateLinkHeader(lhsTheme, lhsTitle): case let .privateLinkHeader(lhsTheme, lhsTitle):
if case let .privateLinkHeader(rhsTheme, rhsTitle) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle { if case let .privateLinkHeader(rhsTheme, rhsTitle) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle {
return true return true
@ -394,8 +394,8 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
let attr = NSMutableAttributedString(string: text, textColor: value ? theme.list.freeTextColor : theme.list.freeTextErrorColor) let attr = NSMutableAttributedString(string: text, textColor: value ? theme.list.freeTextColor : theme.list.freeTextErrorColor)
attr.addAttribute(.font, value: Font.regular(13), range: NSMakeRange(0, attr.length)) attr.addAttribute(.font, value: Font.regular(13), range: NSMakeRange(0, attr.length))
return ItemListActivityTextItem(displayActivity: value, presentationData: presentationData, text: attr, sectionId: self.section) return ItemListActivityTextItem(displayActivity: value, presentationData: presentationData, text: attr, sectionId: self.section)
case let .linksLimitInfo(theme, text, limit, premiumLimit): case let .linksLimitInfo(theme, text, count, limit, premiumLimit, isPremiumDisabled):
return IncreaseLimitHeaderItem(theme: theme, strings: presentationData.strings, icon: .link, count: limit, premiumCount: premiumLimit, text: text, sectionId: self.section) return IncreaseLimitHeaderItem(theme: theme, strings: presentationData.strings, icon: .link, count: count, limit: limit, premiumCount: premiumLimit, text: text, isPremiumDisabled: isPremiumDisabled, sectionId: self.section)
case let .privateLinkHeader(_, title): case let .privateLinkHeader(_, title):
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
case let .privateLink(_, invite, peers, importersCount, displayImporters): case let .privateLink(_, invite, peers, importersCount, displayImporters):
@ -728,9 +728,9 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
displayAvailability = publicChannelsToRevoke != nil && !(publicChannelsToRevoke!.isEmpty) displayAvailability = publicChannelsToRevoke != nil && !(publicChannelsToRevoke!.isEmpty)
} }
if displayAvailability { if !"".isEmpty && displayAvailability {
if let publicChannelsToRevoke = publicChannelsToRevoke { if let publicChannelsToRevoke = publicChannelsToRevoke {
entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(20)").string, limits.maxPublicLinksCount, premiumLimits.maxPublicLinksCount)) // entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(20)").string, limits.maxPublicLinksCount, premiumLimits.maxPublicLinksCount))
var index: Int32 = 0 var index: Int32 = 0
for peer in publicChannelsToRevoke.sorted(by: { lhs, rhs in for peer in publicChannelsToRevoke.sorted(by: { lhs, rhs in
@ -859,7 +859,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
switch mode { switch mode {
case .revokeNames: case .revokeNames:
if let publicChannelsToRevoke = publicChannelsToRevoke { if let publicChannelsToRevoke = publicChannelsToRevoke {
entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(20)").string, 10, 20)) // entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(20)").string, limits.maxPublicLinksCount, premiumLimits.maxPublicLinksCount))
entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesInfo, false)) entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesInfo, false))
var index: Int32 = 0 var index: Int32 = 0
@ -922,7 +922,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
if displayAvailability { if displayAvailability {
if let publicChannelsToRevoke = publicChannelsToRevoke { if let publicChannelsToRevoke = publicChannelsToRevoke {
entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(20)").string, 10, 20)) // entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(20)").string, limits.maxPublicLinksCount, premiumLimits.maxPublicLinksCount))
entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesInfo, false)) entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesInfo, false))
var index: Int32 = 0 var index: Int32 = 0
@ -1352,7 +1352,8 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
let signal = combineLatest( let signal = combineLatest(
presentationData, presentationData,
statePromise.get() |> deliverOnMainQueue, statePromise.get() |> deliverOnMainQueue,
peerView, peersDisablingAddressNameAssignment.get() |> deliverOnMainQueue, peerView,
peersDisablingAddressNameAssignment.get() |> deliverOnMainQueue,
importersContext, importersContext,
importersState.get(), importersState.get(),
context.engine.data.get( context.engine.data.get(

View File

@ -20,17 +20,21 @@ class IncreaseLimitHeaderItem: ListViewItem, ItemListItem {
let strings: PresentationStrings let strings: PresentationStrings
let icon: Icon let icon: Icon
let count: Int32 let count: Int32
let limit: Int32
let premiumCount: Int32 let premiumCount: Int32
let text: String let text: String
let isPremiumDisabled: Bool
let sectionId: ItemListSectionId let sectionId: ItemListSectionId
init(theme: PresentationTheme, strings: PresentationStrings, icon: Icon, count: Int32, premiumCount: Int32, text: String, sectionId: ItemListSectionId) { init(theme: PresentationTheme, strings: PresentationStrings, icon: Icon, count: Int32, limit: Int32, premiumCount: Int32, text: String, isPremiumDisabled: Bool, sectionId: ItemListSectionId) {
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
self.icon = icon self.icon = icon
self.count = count self.count = count
self.limit = limit
self.premiumCount = premiumCount self.premiumCount = premiumCount
self.text = text self.text = text
self.isPremiumDisabled = isPremiumDisabled
self.sectionId = sectionId self.sectionId = sectionId
} }
@ -76,7 +80,7 @@ private let textFont = Font.regular(15.0)
private let boldTextFont = Font.semibold(15.0) private let boldTextFont = Font.semibold(15.0)
class IncreaseLimitHeaderItemNode: ListViewItemNode { class IncreaseLimitHeaderItemNode: ListViewItemNode {
private var hostView: ComponentHostView<Empty> private var hostView: ComponentHostView<Empty>?
private let titleNode: TextNode private let titleNode: TextNode
private let textNode: TextNode private let textNode: TextNode
@ -92,9 +96,7 @@ class IncreaseLimitHeaderItemNode: ListViewItemNode {
self.textNode.isUserInteractionEnabled = false self.textNode.isUserInteractionEnabled = false
self.textNode.contentMode = .left self.textNode.contentMode = .left
self.textNode.contentsScale = UIScreen.main.scale self.textNode.contentsScale = UIScreen.main.scale
self.hostView = ComponentHostView<Empty>()
super.init(layerBacked: false, dynamicBounce: false) super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.titleNode) self.addSubnode(self.titleNode)
@ -104,7 +106,9 @@ class IncreaseLimitHeaderItemNode: ListViewItemNode {
override func didLoad() { override func didLoad() {
super.didLoad() super.didLoad()
self.view.addSubview(self.hostView) let hostView = ComponentHostView<Empty>()
self.hostView = hostView
self.view.addSubview(hostView)
} }
func asyncLayout() -> (_ item: IncreaseLimitHeaderItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { func asyncLayout() -> (_ item: IncreaseLimitHeaderItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
@ -142,34 +146,46 @@ class IncreaseLimitHeaderItemNode: ListViewItemNode {
badgeIconName = "Premium/Link" badgeIconName = "Premium/Link"
} }
let size = strongSelf.hostView.update( let gradientColors: [UIColor]
transition: .immediate, if item.isPremiumDisabled {
component: AnyComponent(PremiumLimitDisplayComponent( gradientColors = [
inactiveColor: item.theme.list.itemBlocksSeparatorColor.withAlphaComponent(0.5), UIColor(rgb: 0x007afe),
activeColors: [ UIColor(rgb: 0x5494ff)
UIColor(rgb: 0x0077ff), ]
UIColor(rgb: 0x6b93ff), } else {
UIColor(rgb: 0x8878ff), gradientColors = [
UIColor(rgb: 0xe46ace) UIColor(rgb: 0x0077ff),
], UIColor(rgb: 0x6b93ff),
inactiveTitle: item.strings.Premium_Free, UIColor(rgb: 0x8878ff),
inactiveValue: "", UIColor(rgb: 0xe46ace)
inactiveTitleColor: item.theme.list.itemPrimaryTextColor, ]
activeTitle: item.strings.Premium_Premium, }
activeValue: "\(item.premiumCount)",
activeTitleColor: .white,
badgeIconName: badgeIconName,
badgeText: "\(item.count)",
badgePosition: CGFloat(item.count) / CGFloat(item.premiumCount),
isPremiumDisabled: false
)),
environment: {},
containerSize: CGSize(width: layout.size.width - params.leftInset - params.rightInset, height: 200.0)
)
strongSelf.hostView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - size.width) / 2.0), y: -30.0), size: size)
let _ = textApply() if let hostView = strongSelf.hostView {
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - textLayout.size.width) / 2.0), y: size.height + textSpacing), size: textLayout.size) let size = hostView.update(
transition: .immediate,
component: AnyComponent(PremiumLimitDisplayComponent(
inactiveColor: item.theme.list.itemBlocksSeparatorColor.withAlphaComponent(0.5),
activeColors: gradientColors,
inactiveTitle: item.strings.Premium_Free,
inactiveValue: item.count > item.limit ? "\(item.limit)" : "",
inactiveTitleColor: item.theme.list.itemPrimaryTextColor,
activeTitle: item.strings.Premium_Premium,
activeValue: item.count >= item.premiumCount ? "" : "\(item.premiumCount)",
activeTitleColor: .white,
badgeIconName: badgeIconName,
badgeText: "\(item.count)",
badgePosition: CGFloat(item.count) / CGFloat(item.premiumCount),
isPremiumDisabled: item.isPremiumDisabled
)),
environment: {},
containerSize: CGSize(width: layout.size.width - params.leftInset - params.rightInset, height: 200.0)
)
hostView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - size.width) / 2.0), y: -30.0), size: size)
let _ = textApply()
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - textLayout.size.width) / 2.0), y: size.height + textSpacing), size: textLayout.size)
}
} }
}) })
} }

View File

@ -84,7 +84,7 @@ private enum OldChannelsEntryId: Hashable {
} }
private enum OldChannelsEntry: ItemListNodeEntry { private enum OldChannelsEntry: ItemListNodeEntry {
case info(Int32, Int32, String) case info(Int32, Int32, Int32, String, Bool)
case peersHeader(String) case peersHeader(String)
case peer(Int, InactiveChannel, Bool) case peer(Int, InactiveChannel, Bool)
@ -110,8 +110,8 @@ private enum OldChannelsEntry: ItemListNodeEntry {
static func ==(lhs: OldChannelsEntry, rhs: OldChannelsEntry) -> Bool { static func ==(lhs: OldChannelsEntry, rhs: OldChannelsEntry) -> Bool {
switch lhs { switch lhs {
case let .info(count, premiumCount, text): case let .info(count, limit, premiumLimit, text, isPremiumDisabled):
if case .info(count, premiumCount, text) = rhs { if case .info(count, limit, premiumLimit, text, isPremiumDisabled) = rhs {
return true return true
} else { } else {
return false return false
@ -168,8 +168,8 @@ private enum OldChannelsEntry: ItemListNodeEntry {
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let arguments = arguments as! OldChannelsItemArguments let arguments = arguments as! OldChannelsItemArguments
switch self { switch self {
case let .info(count, premiumCount, text): case let .info(count, limit, premiumLimit, text, isPremiumDisabled):
return IncreaseLimitHeaderItem(theme: presentationData.theme, strings: presentationData.strings, icon: .group, count: count, premiumCount: premiumCount, text: text, sectionId: self.section) return IncreaseLimitHeaderItem(theme: presentationData.theme, strings: presentationData.strings, icon: .group, count: count, limit: limit, premiumCount: premiumLimit, text: text, isPremiumDisabled: isPremiumDisabled, sectionId: self.section)
case let .peersHeader(title): case let .peersHeader(title):
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
case let .peer(_, peer, selected): case let .peer(_, peer, selected):
@ -185,10 +185,24 @@ private struct OldChannelsState: Equatable {
var isSearching: Bool = false var isSearching: Bool = false
} }
private func oldChannelsEntries(presentationData: PresentationData, state: OldChannelsState, limit: Int32, premiumLimit: Int32, peers: [InactiveChannel]?, intent: OldChannelsControllerIntent) -> [OldChannelsEntry] { private func oldChannelsEntries(presentationData: PresentationData, state: OldChannelsState, isPremium: Bool, isPremiumDisabled: Bool, limit: Int32, premiumLimit: Int32, peers: [InactiveChannel]?, intent: OldChannelsControllerIntent) -> [OldChannelsEntry] {
var entries: [OldChannelsEntry] = [] var entries: [OldChannelsEntry] = []
entries.append(.info(limit, premiumLimit, presentationData.strings.OldChannels_TooManyCommunitiesText("\(limit)", "\(premiumLimit)").string)) let count = max(limit, Int32(peers?.count ?? 0))
var text: String?
if count >= premiumLimit {
text = presentationData.strings.OldChannels_TooManyCommunitiesFinalText("\(premiumLimit)").string
} else if count >= limit {
if isPremiumDisabled {
text = presentationData.strings.OldChannels_TooManyCommunitiesNoPremiumText("\(count)").string
} else {
text = presentationData.strings.OldChannels_TooManyCommunitiesText("\(count)", "\(premiumLimit)").string
}
}
if let text = text {
entries.append(.info(count, limit, premiumLimit, text, isPremiumDisabled))
}
if let peers = peers, !peers.isEmpty { if let peers = peers, !peers.isEmpty {
entries.append(.peersHeader(presentationData.strings.OldChannels_ChannelsHeader)) entries.append(.peersHeader(presentationData.strings.OldChannels_ChannelsHeader))
@ -265,8 +279,6 @@ public func oldChannelsController(context: AccountContext, updatedPresentationDa
var previousPeersWereEmpty = true var previousPeersWereEmpty = true
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
let signal = combineLatest( let signal = combineLatest(
queue: Queue.mainQueue(), queue: Queue.mainQueue(),
@ -283,7 +295,8 @@ public func oldChannelsController(context: AccountContext, updatedPresentationDa
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
dismissImpl?() dismissImpl?()
}) })
let (_, limits, premiumLimits) = limits let (accountPeer, limits, premiumLimits) = limits
let isPremium = accountPeer?.isPremium ?? false
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.OldChannels_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.OldChannels_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
@ -322,6 +335,7 @@ public func oldChannelsController(context: AccountContext, updatedPresentationDa
buttonText = presentationData.strings.Premium_IncreaseLimit buttonText = presentationData.strings.Premium_IncreaseLimit
colorful = true colorful = true
} }
let footerItem: IncreaseLimitFooterItem? let footerItem: IncreaseLimitFooterItem?
if state.isSearching && state.selectedPeers.count == 0 { if state.isSearching && state.selectedPeers.count == 0 {
footerItem = nil footerItem = nil
@ -336,7 +350,9 @@ public func oldChannelsController(context: AccountContext, updatedPresentationDa
}) })
} }
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: oldChannelsEntries(presentationData: presentationData, state: state, limit: limits.maxChannelsCount, premiumLimit: premiumLimits.maxChannelsCount, peers: peers, intent: intent), style: .blocks, emptyStateItem: emptyStateItem, searchItem: searchItem, footerItem: footerItem, initialScrollToItem: ListViewScrollToItem(index: 0, position: .top(-navigationBarSearchContentHeight), animated: false, curve: .Default(duration: 0.0), directionHint: .Up), crossfadeState: peersAreEmptyUpdated, animateChanges: false) let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: oldChannelsEntries(presentationData: presentationData, state: state, isPremium: isPremium, isPremiumDisabled: premiumConfiguration.isPremiumDisabled, limit: limits.maxChannelsCount, premiumLimit: premiumLimits.maxChannelsCount, peers: peers, intent: intent), style: .blocks, emptyStateItem: emptyStateItem, searchItem: searchItem, footerItem: footerItem, initialScrollToItem: ListViewScrollToItem(index: 0, position: .top(-navigationBarSearchContentHeight), animated: false, curve: .Default(duration: 0.0), directionHint: .Up), crossfadeState: peersAreEmptyUpdated, animateChanges: false)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} }

View File

@ -66,6 +66,7 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
private let gloss: Bool private let gloss: Bool
private let buttonBackgroundNode: ASImageNode private let buttonBackgroundNode: ASImageNode
private var buttonBackgroundAnimationView: UIImageView?
private var shimmerView: ShimmerEffectForegroundView? private var shimmerView: ShimmerEffectForegroundView?
private var borderView: UIView? private var borderView: UIView?
@ -173,6 +174,8 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
self.buttonBackgroundNode = ASImageNode() self.buttonBackgroundNode = ASImageNode()
self.buttonBackgroundNode.displaysAsynchronously = false self.buttonBackgroundNode.displaysAsynchronously = false
self.buttonBackgroundNode.clipsToBounds = true self.buttonBackgroundNode.clipsToBounds = true
self.buttonBackgroundNode.backgroundColor = theme.backgroundColor
if theme.backgroundColors.count > 1 { if theme.backgroundColors.count > 1 {
self.buttonBackgroundNode.backgroundColor = nil self.buttonBackgroundNode.backgroundColor = nil
@ -182,9 +185,12 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
locations.append(delta * CGFloat(i)) locations.append(delta * CGFloat(i))
} }
self.buttonBackgroundNode.image = generateGradientImage(size: CGSize(width: 200.0, height: height), colors: theme.backgroundColors, locations: locations, direction: .horizontal) self.buttonBackgroundNode.image = generateGradientImage(size: CGSize(width: 200.0, height: height), colors: theme.backgroundColors, locations: locations, direction: .horizontal)
} else {
self.buttonBackgroundNode.backgroundColor = theme.backgroundColor let buttonBackgroundAnimationView = UIImageView()
buttonBackgroundAnimationView.image = generateGradientImage(size: CGSize(width: 200.0, height: height), colors: theme.backgroundColors, locations: locations, direction: .horizontal)
self.buttonBackgroundAnimationView = buttonBackgroundAnimationView
} }
self.buttonBackgroundNode.cornerRadius = cornerRadius self.buttonBackgroundNode.cornerRadius = cornerRadius
self.buttonNode = HighlightTrackingButtonNode() self.buttonNode = HighlightTrackingButtonNode()
@ -244,34 +250,92 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
self.buttonBackgroundNode.layer.cornerCurve = .continuous self.buttonBackgroundNode.layer.cornerCurve = .continuous
} }
if let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView {
self.buttonBackgroundNode.view.addSubview(buttonBackgroundAnimationView)
}
self.setupGloss()
}
private func setupGloss() {
if self.gloss { if self.gloss {
let shimmerView = ShimmerEffectForegroundView() if self.shimmerView == nil {
self.shimmerView = shimmerView let shimmerView = ShimmerEffectForegroundView()
self.shimmerView = shimmerView
if #available(iOS 13.0, *) {
shimmerView.layer.cornerCurve = .continuous if #available(iOS 13.0, *) {
shimmerView.layer.cornerRadius = self.buttonCornerRadius shimmerView.layer.cornerCurve = .continuous
shimmerView.layer.cornerRadius = self.buttonCornerRadius
}
let borderView = UIView()
borderView.isUserInteractionEnabled = false
self.borderView = borderView
let borderMaskView = UIView()
borderMaskView.layer.borderWidth = 1.0 + UIScreenPixel
borderMaskView.layer.borderColor = UIColor.white.cgColor
borderMaskView.layer.cornerRadius = self.buttonCornerRadius
borderView.mask = borderMaskView
self.borderMaskView = borderMaskView
let borderShimmerView = ShimmerEffectForegroundView()
self.borderShimmerView = borderShimmerView
borderView.addSubview(borderShimmerView)
self.view.insertSubview(shimmerView, belowSubview: self.buttonNode.view)
self.view.insertSubview(borderView, belowSubview: self.buttonNode.view)
self.updateShimmerParameters()
if let width = self.validLayout {
_ = self.updateLayout(width: width, transition: .immediate)
}
} }
} else if self.shimmerView != nil {
self.shimmerView?.removeFromSuperview()
self.borderView?.removeFromSuperview()
self.borderMaskView?.removeFromSuperview()
self.borderShimmerView?.removeFromSuperview()
let borderView = UIView() self.shimmerView = nil
borderView.isUserInteractionEnabled = false self.borderView = nil
self.borderView = borderView self.borderMaskView = nil
self.borderShimmerView = nil
}
}
private func setupGradientAnimations() {
guard let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView else {
return
}
if let _ = buttonBackgroundAnimationView.layer.animation(forKey: "movement") {
} else {
let offset = (buttonBackgroundAnimationView.frame.width - self.frame.width) / 2.0
let previousValue = buttonBackgroundAnimationView.center.x
var newValue: CGFloat = offset
if offset - previousValue < buttonBackgroundAnimationView.frame.width * 0.25 {
newValue -= buttonBackgroundAnimationView.frame.width * 0.35
}
buttonBackgroundAnimationView.center = CGPoint(x: newValue, y: buttonBackgroundAnimationView.bounds.size.height / 2.0)
let borderMaskView = UIView() CATransaction.begin()
borderMaskView.layer.borderWidth = 1.0 + UIScreenPixel
borderMaskView.layer.borderColor = UIColor.white.cgColor
borderMaskView.layer.cornerRadius = self.buttonCornerRadius
borderView.mask = borderMaskView
self.borderMaskView = borderMaskView
let borderShimmerView = ShimmerEffectForegroundView() let animation = CABasicAnimation(keyPath: "position.x")
self.borderShimmerView = borderShimmerView animation.duration = 4.5
borderView.addSubview(borderShimmerView) animation.fromValue = previousValue
animation.toValue = newValue
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
self.view.insertSubview(shimmerView, belowSubview: self.buttonNode.view) CATransaction.setCompletionBlock { [weak self] in
self.view.insertSubview(borderView, belowSubview: self.buttonNode.view) // if let isCurrentlyInHierarchy = self?.isCurrentlyInHierarchy, isCurrentlyInHierarchy {
self?.setupGradientAnimations()
self.updateShimmerParameters() // }
}
buttonBackgroundAnimationView.layer.add(animation, forKey: "movement")
CATransaction.commit()
} }
} }
@ -354,6 +418,8 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
animationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) animationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
} }
} }
self.buttonBackgroundNode.backgroundColor = theme.backgroundColor
if theme.backgroundColors.count > 1 { if theme.backgroundColors.count > 1 {
self.buttonBackgroundNode.backgroundColor = nil self.buttonBackgroundNode.backgroundColor = nil
@ -363,9 +429,17 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
locations.append(delta * CGFloat(i)) locations.append(delta * CGFloat(i))
} }
self.buttonBackgroundNode.image = generateGradientImage(size: CGSize(width: 200.0, height: self.buttonHeight), colors: theme.backgroundColors, locations: locations, direction: .horizontal) self.buttonBackgroundNode.image = generateGradientImage(size: CGSize(width: 200.0, height: self.buttonHeight), colors: theme.backgroundColors, locations: locations, direction: .horizontal)
if self.buttonBackgroundAnimationView == nil {
let buttonBackgroundAnimationView = UIImageView()
self.buttonBackgroundAnimationView = buttonBackgroundAnimationView
self.buttonBackgroundNode.view.addSubview(buttonBackgroundAnimationView)
}
self.buttonBackgroundAnimationView?.image = self.buttonBackgroundNode.image
} else { } else {
self.buttonBackgroundNode.backgroundColor = theme.backgroundColor
self.buttonBackgroundNode.image = nil self.buttonBackgroundNode.image = nil
self.buttonBackgroundAnimationView?.image = nil
} }
self.titleNode.attributedText = NSAttributedString(string: self.title ?? "", font: self.font == .bold ? Font.semibold(self.fontSize) : Font.regular(self.fontSize), textColor: theme.foregroundColor) self.titleNode.attributedText = NSAttributedString(string: self.title ?? "", font: self.font == .bold ? Font.semibold(self.fontSize) : Font.regular(self.fontSize), textColor: theme.foregroundColor)
@ -407,6 +481,14 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
borderShimmerView.updateAbsoluteRect(CGRect(origin: CGPoint(x: width * 4.0, y: 0.0), size: buttonSize), within: CGSize(width: width * 9.0, height: buttonHeight)) borderShimmerView.updateAbsoluteRect(CGRect(origin: CGPoint(x: width * 4.0, y: 0.0), size: buttonSize), within: CGSize(width: width * 9.0, height: buttonHeight))
} }
if let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView {
buttonBackgroundAnimationView.bounds = CGRect(origin: CGPoint(), size: CGSize(width: buttonSize.width * 2.4, height: buttonSize.height))
if buttonBackgroundAnimationView.layer.animation(forKey: "movement") == nil {
buttonBackgroundAnimationView.center = CGPoint(x: buttonSize.width * 2.4 / 2.0 - buttonBackgroundAnimationView.frame.width * 0.35, y: buttonSize.height / 2.0)
}
self.setupGradientAnimations()
}
transition.updateFrame(node: self.buttonNode, frame: buttonFrame) transition.updateFrame(node: self.buttonNode, frame: buttonFrame)
if self.title != self.titleNode.attributedText?.string { if self.title != self.titleNode.attributedText?.string {
@ -663,7 +745,7 @@ public final class SolidRoundedButtonView: UIView {
self.buttonBackgroundNode.image = generateGradientImage(size: CGSize(width: 200.0, height: height), colors: theme.backgroundColors, locations: locations, direction: .horizontal) self.buttonBackgroundNode.image = generateGradientImage(size: CGSize(width: 200.0, height: height), colors: theme.backgroundColors, locations: locations, direction: .horizontal)
let buttonBackgroundAnimationView = UIImageView() let buttonBackgroundAnimationView = UIImageView()
buttonBackgroundAnimationView.image = generateGradientImage(size: CGSize(width: 200.0, height: height), colors: theme.backgroundColors, locations: locations, direction: .horizontal) buttonBackgroundAnimationView.image = self.buttonBackgroundNode.image
self.buttonBackgroundNode.addSubview(buttonBackgroundAnimationView) self.buttonBackgroundNode.addSubview(buttonBackgroundAnimationView)
self.buttonBackgroundAnimationView = buttonBackgroundAnimationView self.buttonBackgroundAnimationView = buttonBackgroundAnimationView
} }
@ -723,6 +805,10 @@ public final class SolidRoundedButtonView: UIView {
self.setupGloss() self.setupGloss()
} }
} }
required public init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupGloss() { private func setupGloss() {
if self.gloss { if self.gloss {
@ -772,10 +858,6 @@ public final class SolidRoundedButtonView: UIView {
} }
} }
required public init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupGradientAnimations() { private func setupGradientAnimations() {
guard let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView else { guard let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView else {
return return
@ -943,8 +1025,10 @@ public final class SolidRoundedButtonView: UIView {
locations.append(delta * CGFloat(i)) locations.append(delta * CGFloat(i))
} }
self.buttonBackgroundNode.image = generateGradientImage(size: CGSize(width: 200.0, height: self.buttonHeight), colors: theme.backgroundColors, locations: locations, direction: .horizontal) self.buttonBackgroundNode.image = generateGradientImage(size: CGSize(width: 200.0, height: self.buttonHeight), colors: theme.backgroundColors, locations: locations, direction: .horizontal)
self.buttonBackgroundAnimationView?.image = self.buttonBackgroundNode.image
} else { } else {
self.buttonBackgroundNode.image = nil self.buttonBackgroundNode.image = nil
self.buttonBackgroundAnimationView?.image = nil
} }
self.titleNode.attributedText = NSAttributedString(string: self.title ?? "", font: self.font == .bold ? Font.semibold(self.fontSize) : Font.regular(self.fontSize), textColor: theme.foregroundColor) self.titleNode.attributedText = NSAttributedString(string: self.title ?? "", font: self.font == .bold ? Font.semibold(self.fontSize) : Font.regular(self.fontSize), textColor: theme.foregroundColor)