This commit is contained in:
Isaac 2025-12-28 22:39:34 +08:00
parent 9d6518a738
commit 05b667797d
26 changed files with 210 additions and 82 deletions

View file

@ -769,7 +769,8 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
}
transition.updateAlpha(node: strongSelf.infoButtonNode, alpha: item.editing ? 0.0 : 1.0)
let topHighlightInset: CGFloat = (first || !nodeLayout.insets.top.isZero) ? 0.0 : separatorHeight
var topHighlightInset: CGFloat = (first || !nodeLayout.insets.top.isZero) ? 0.0 : separatorHeight
topHighlightInset -= nodeLayout.insets.top
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: nodeLayout.contentSize.width, height: nodeLayout.contentSize.height))
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: strongSelf.backgroundNode.frame.size)
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -nodeLayout.insets.top - topHighlightInset), size: CGSize(width: nodeLayout.size.width, height: nodeLayout.size.height + topHighlightInset))

View file

@ -434,7 +434,8 @@ class CallListGroupCallItemNode: ItemListRevealOptionsItemNode {
let _ = joinTitleApply()
transition.updateFrameAdditive(node: strongSelf.joinTitleNode, frame: CGRect(origin: CGPoint(x: floor((joinButtonSize.width - joinTitleLayout.size.width) / 2.0), y: floor((joinButtonSize.height - joinTitleLayout.size.height) / 2.0) + 1.0), size: joinTitleLayout.size))
let topHighlightInset: CGFloat = (first || !nodeLayout.insets.top.isZero) ? 0.0 : separatorHeight
var topHighlightInset: CGFloat = (first || !nodeLayout.insets.top.isZero) ? 0.0 : separatorHeight
topHighlightInset -= nodeLayout.insets.top
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: nodeLayout.contentSize.width, height: nodeLayout.contentSize.height))
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -nodeLayout.insets.top - topHighlightInset), size: CGSize(width: nodeLayout.size.width, height: nodeLayout.size.height + topHighlightInset))

View file

@ -7016,6 +7016,7 @@ private final class ChatListLocationContext {
}
if strongSelf.toolbar != toolbar {
strongSelf.toolbar = toolbar
transition = .animated(duration: 0.4, curve: .spring)
if parentController.effectiveContext === strongSelf {
parentController.setToolbar(toolbar, transition: transition)
}

View file

@ -218,6 +218,7 @@ public enum ChatListItemContent {
public var message: EngineMessage?
public var unreadCount: Int
public var hiddenByDefault: Bool
public var appearsPinned: Bool
public var storyState: StoryState?
public init(
@ -226,6 +227,7 @@ public enum ChatListItemContent {
message: EngineMessage?,
unreadCount: Int,
hiddenByDefault: Bool,
appearsPinned: Bool,
storyState: StoryState?
) {
self.groupId = groupId
@ -233,6 +235,7 @@ public enum ChatListItemContent {
self.message = message
self.unreadCount = unreadCount
self.hiddenByDefault = hiddenByDefault
self.appearsPinned = appearsPinned
self.storyState = storyState
}
}
@ -5059,8 +5062,8 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
highlightedBackgroundColor = theme.itemHighlightedBackgroundColor
} else if isPinned {
if case let .groupReference(groupReferenceData) = item.content, groupReferenceData.hiddenByDefault {
backgroundColor = theme.itemBackgroundColor
highlightedBackgroundColor = theme.itemHighlightedBackgroundColor
backgroundColor = groupReferenceData.appearsPinned ? theme.pinnedItemBackgroundColor : theme.itemBackgroundColor
highlightedBackgroundColor = groupReferenceData.appearsPinned ? theme.pinnedItemHighlightedBackgroundColor : theme.itemHighlightedBackgroundColor
} else {
backgroundColor = theme.pinnedItemBackgroundColor
highlightedBackgroundColor = theme.pinnedItemHighlightedBackgroundColor

View file

@ -696,6 +696,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
message: groupReferenceEntry.message,
unreadCount: groupReferenceEntry.unreadCount,
hiddenByDefault: groupReferenceEntry.hiddenByDefault,
appearsPinned: groupReferenceEntry.appearsPinned,
storyState: groupReferenceEntry.storyState.flatMap { storyState in
return ChatListItemContent.StoryState(
stats: storyState.stats,
@ -1005,6 +1006,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
message: groupReferenceEntry.message,
unreadCount: groupReferenceEntry.unreadCount,
hiddenByDefault: groupReferenceEntry.hiddenByDefault,
appearsPinned: groupReferenceEntry.appearsPinned,
storyState: groupReferenceEntry.storyState.flatMap { storyState in
return ChatListItemContent.StoryState(
stats: storyState.stats,

View file

@ -322,6 +322,7 @@ enum ChatListNodeEntry: Comparable, Identifiable {
var unreadCount: Int
var revealed: Bool
var hiddenByDefault: Bool
var appearsPinned: Bool
var storyState: ChatListNodeState.StoryState?
init(
@ -334,6 +335,7 @@ enum ChatListNodeEntry: Comparable, Identifiable {
unreadCount: Int,
revealed: Bool,
hiddenByDefault: Bool,
appearsPinned: Bool,
storyState: ChatListNodeState.StoryState?
) {
self.index = index
@ -345,6 +347,7 @@ enum ChatListNodeEntry: Comparable, Identifiable {
self.unreadCount = unreadCount
self.revealed = revealed
self.hiddenByDefault = hiddenByDefault
self.appearsPinned = appearsPinned
self.storyState = storyState
}
@ -376,6 +379,9 @@ enum ChatListNodeEntry: Comparable, Identifiable {
if lhs.hiddenByDefault != rhs.hiddenByDefault {
return false
}
if lhs.appearsPinned != rhs.appearsPinned {
return false
}
if lhs.storyState != rhs.storyState {
return false
}
@ -622,6 +628,8 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
var hiddenGeneralThread: ChatListNodeEntry?
var hasPinned = false
loop: for entry in view.items {
var peerId: EnginePeer.Id?
var threadId: Int64?
@ -673,6 +681,17 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
if let threadData = entry.threadData, let threadId {
threadInfo = ChatListItemContent.ThreadInfo(id: threadId, info: threadData.info, isOwnedByMe: threadData.isOwnedByMe, isClosed: threadData.isClosed, isHidden: threadData.isHidden, threadPeer: nil)
}
switch entry.index {
case let .chatList(chatList):
if chatList.pinningIndex != nil {
hasPinned = true
}
case let .forum(pinnedIndex, _, _, _, _):
if case .index = pinnedIndex {
hasPinned = true
}
}
let entry: ChatListNodeEntry = .PeerEntry(ChatListNodeEntry.PeerEntryData(
index: offsetPinnedIndex(entry.index, offset: pinnedIndexOffset),
@ -762,6 +781,7 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
)))
if foundPinningIndex != 0 {
foundPinningIndex -= 1
hasPinned = true
}
}
}
@ -852,6 +872,7 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
)))
if pinningIndex != 0 {
pinningIndex -= 1
hasPinned = true
}
}
}
@ -874,10 +895,12 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
unreadCount: groupReference.unreadCount,
revealed: state.hiddenItemShouldBeTemporaryRevealed,
hiddenByDefault: hideArchivedFolderByDefault,
appearsPinned: hasPinned,
storyState: mappedStoryState
)))
if pinningIndex != 0 {
pinningIndex -= 1
hasPinned = true
}
}

View file

@ -11,6 +11,7 @@ final class ContactListNameIndexHeader: Equatable, ListViewItemHeader {
let letter: unichar
let stickDirection: ListViewItemHeaderStickDirection = .top
public let stickOverInsets: Bool = true
public let isSticky: Bool = false
let height: CGFloat = 29.0

View file

@ -1857,7 +1857,8 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners, glass: item.systemStyle == .glass) : nil
let topHighlightInset: CGFloat = (first || !nodeLayout.insets.top.isZero) ? 0.0 : separatorHeight
var topHighlightInset: CGFloat = (first || !nodeLayout.insets.top.isZero) ? 0.0 : separatorHeight
topHighlightInset -= nodeLayout.insets.top
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: nodeLayout.contentSize.width, height: nodeLayout.contentSize.height))
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -nodeLayout.insets.top - topHighlightInset), size: CGSize(width: nodeLayout.size.width, height: nodeLayout.size.height + topHighlightInset))

View file

@ -128,11 +128,13 @@ swift_library(
"//submodules/TelegramUI/Components/Settings/PasskeysScreen",
"//submodules/TelegramUI/Components/FaceScanScreen",
"//submodules/ComponentFlow",
"//submodules/Components/ComponentDisplayAdapters",
"//submodules/Components/BundleIconComponent",
"//submodules/TelegramUI/Components/ButtonComponent",
"//submodules/TelegramUI/Components/SliderComponent",
"//submodules/TelegramUI/Components/AlertComponent",
"//submodules/TelegramUI/Components/AlertComponent/AlertInputFieldComponent",
"//submodules/TelegramUI/Components/EdgeEffect",
],
visibility = [
"//visibility:public",

View file

@ -13,6 +13,9 @@ import AccountContext
import SearchBarNode
import SearchUI
import ChatListSearchItemHeader
import EdgeEffect
import ComponentFlow
import ComponentDisplayAdapters
extension SettingsSearchableItemIcon {
func image() -> UIImage? {
@ -226,6 +229,8 @@ public final class SettingsSearchContainerNode: SearchDisplayControllerContentNo
private let listNode: ListView
private let recentListNode: ListView
private let edgeEffectView: EdgeEffectView
private var enqueuedTransitions: [SettingsSearchContainerTransition] = []
private var enqueuedRecentTransitions: [(SettingsSearchContainerRecentTransition, Bool)] = []
private var hasValidLayout = false
@ -258,12 +263,15 @@ public final class SettingsSearchContainerNode: SearchDisplayControllerContentNo
return presentationData.strings.VoiceOver_ScrollStatus(row, count).string
}
self.edgeEffectView = EdgeEffectView()
super.init()
self.backgroundColor = self.presentationData.theme.chatList.backgroundColor
self.addSubnode(self.recentListNode)
self.addSubnode(self.listNode)
self.view.addSubview(self.edgeEffectView)
let interaction = SettingsSearchInteraction(openItem: { result in
addRecentSettingsSearchItem(engine: context.engine, item: result.id)
@ -513,6 +521,12 @@ public final class SettingsSearchContainerNode: SearchDisplayControllerContentNo
self.dequeueTransition()
}
}
let edgeEffectHeight: CGFloat = insets.bottom + 8.0
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.presentationData.theme.list.plainBackgroundColor, rect: edgeEffectFrame, edge: .bottom, edgeSize: min(edgeEffectHeight, 50.0), transition: ComponentTransition(transition))
transition.updateAlpha(layer: self.edgeEffectView.layer, alpha: edgeEffectHeight > 21.0 ? 1.0 : 0.0)
}
public override func scrollToTop() {

View file

@ -19,6 +19,7 @@ swift_library(
"//submodules/ComponentFlow",
"//submodules/Components/ComponentDisplayAdapters",
"//submodules/TelegramUI/Components/TabBarComponent",
"//submodules/TelegramUI/Components/GlassControls",
],
visibility = [
"//visibility:public",

View file

@ -6,12 +6,7 @@ import TelegramPresentationData
import ComponentFlow
import ComponentDisplayAdapters
import TabBarComponent
private extension ToolbarTheme {
convenience init(theme: PresentationTheme) {
self.init(barBackgroundColor: theme.rootController.tabBar.backgroundColor, barSeparatorColor: .clear, barTextColor: theme.rootController.tabBar.textColor, barSelectedTextColor: theme.rootController.tabBar.selectedTextColor)
}
}
import GlassControls
final class TabBarControllerNode: ASDisplayNode {
private struct Params: Equatable {
@ -61,7 +56,7 @@ final class TabBarControllerNode: ASDisplayNode {
private let tabBarView = ComponentView<Empty>()
private let disabledOverlayNode: ASDisplayNode
private var toolbarNode: ToolbarNode?
private var toolbar: ComponentView<Empty>?
private let toolbarActionSelected: (ToolbarActionOption) -> Void
private let disabledPressed: () -> Void
private let activateSearch: () -> Void
@ -162,7 +157,6 @@ final class TabBarControllerNode: ASDisplayNode {
self.backgroundColor = theme.list.plainBackgroundColor
self.disabledOverlayNode.backgroundColor = theme.rootController.tabBar.backgroundColor.withAlphaComponent(0.5)
self.toolbarNode?.updateTheme(ToolbarTheme(theme: theme))
self.requestUpdate()
}
@ -291,34 +285,90 @@ final class TabBarControllerNode: ASDisplayNode {
transition.updateFrame(node: self.disabledOverlayNode, frame: tabBarFrame)
let toolbarHeight = 50.0 + panelsBottomInset
let toolbarFrame = CGRect(origin: CGPoint(x: 0.0, y: params.layout.size.height - toolbarHeight), size: CGSize(width: params.layout.size.width, height: toolbarHeight))
let toolbarHeight = 44.0
let toolbarFrame = CGRect(origin: CGPoint(x: sideInset, y: params.layout.size.height - panelsBottomInset - toolbarHeight), size: CGSize(width: params.layout.size.width - sideInset * 2.0, height: toolbarHeight))
if let toolbar = params.toolbar {
if let toolbarNode = self.toolbarNode {
transition.updateFrame(node: toolbarNode, frame: toolbarFrame)
toolbarNode.updateLayout(size: toolbarFrame.size, leftInset: params.layout.safeInsets.left, rightInset: params.layout.safeInsets.right, additionalSideInsets: params.layout.additionalInsets, bottomInset: panelsBottomInset, toolbar: toolbar, transition: transition)
if let toolbarData = params.toolbar {
let toolbar: ComponentView<Empty>
var toolbarTransition = ComponentTransition(transition)
if let current = self.toolbar {
toolbar = current
} else {
let toolbarNode = ToolbarNode(theme: ToolbarTheme(theme: self.theme), displaySeparator: true, left: { [weak self] in
self?.toolbarActionSelected(.left)
}, right: { [weak self] in
self?.toolbarActionSelected(.right)
}, middle: { [weak self] in
self?.toolbarActionSelected(.middle)
})
toolbarNode.frame = toolbarFrame
toolbarNode.updateLayout(size: toolbarFrame.size, leftInset: params.layout.safeInsets.left, rightInset: params.layout.safeInsets.right, additionalSideInsets: params.layout.additionalInsets, bottomInset: panelsBottomInset, toolbar: toolbar, transition: .immediate)
self.addSubnode(toolbarNode)
self.toolbarNode = toolbarNode
if transition.isAnimated {
toolbarNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
toolbar = ComponentView()
self.toolbar = toolbar
toolbarTransition = .immediate
}
let _ = toolbar.update(
transition: toolbarTransition,
component: AnyComponent(GlassControlPanelComponent(
theme: self.theme,
leftItem: toolbarData.leftAction.flatMap { value in
return GlassControlPanelComponent.Item(
items: [GlassControlGroupComponent.Item(
id: "left_" + value.title,
content: .text(value.title),
action: value.isEnabled ? { [weak self] in
guard let self else {
return
}
self.toolbarActionSelected(.left)
} : nil
)],
background: .panel
)
},
centralItem: toolbarData.middleAction.flatMap { value in
return GlassControlPanelComponent.Item(
items: [GlassControlGroupComponent.Item(
id: "right_" + value.title,
content: .text(value.title),
action: value.isEnabled ? { [weak self] in
guard let self else {
return
}
self.toolbarActionSelected(.middle)
} : nil
)],
background: .panel
)
},
rightItem: toolbarData.rightAction.flatMap { value in
return GlassControlPanelComponent.Item(
items: [GlassControlGroupComponent.Item(
id: "right_" + value.title,
content: .text(value.title),
action: value.isEnabled ? { [weak self] in
guard let self else {
return
}
self.toolbarActionSelected(.right)
} : nil
)],
background: .panel
)
},
centerAlignmentIfPossible: true
)),
environment: {},
containerSize: toolbarFrame.size
)
if let toolbarView = toolbar.view {
if toolbarView.superview == nil {
self.view.addSubview(toolbarView)
toolbarView.alpha = 0.0
}
toolbarTransition.setFrame(view: toolbarView, frame: toolbarFrame)
ComponentTransition(transition).setAlpha(view: toolbarView, alpha: 1.0)
}
} else if let toolbar = self.toolbar {
self.toolbar = nil
if let toolbarView = toolbar.view {
ComponentTransition(transition).setAlpha(view: toolbarView, alpha: 0.0, completion: { [weak toolbarView] _ in
toolbarView?.removeFromSuperview()
})
}
} else if let toolbarNode = self.toolbarNode {
self.toolbarNode = nil
transition.updateAlpha(node: toolbarNode, alpha: 0.0, completion: { [weak toolbarNode] _ in
toolbarNode?.removeFromSupernode()
})
}
return params.layout.size.height - tabBarFrame.minY - 6.0

View file

@ -505,7 +505,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati
pinnedSearchBarColor: UIColor(rgb: 0x272728),
regularSearchBarColor: UIColor(rgb: 0x272728),
sectionHeaderFillColor: .black,
sectionHeaderTextColor: UIColor(rgb: 0xffffff),
sectionHeaderTextColor: UIColor(rgb: 0x8d8e93),
verifiedIconFillColor: UIColor(rgb: 0xffffff),
verifiedIconForegroundColor: UIColor(rgb: 0x000000),
secretIconColor: UIColor(rgb: 0x00b12c),

View file

@ -145,7 +145,7 @@ public func customizeDefaultDarkTintedPresentationTheme(theme: PresentationTheme
navigationSearchBar: rootController.navigationSearchBar.withUpdated(
backgroundColor: mainBackgroundColor,
accentColor: accentColor,
inputFillColor: mainInputColor,
inputFillColor: UIColor(white: 1.0, alpha: 0.1),
inputPlaceholderTextColor: mainSecondaryColor,
inputIconColor: mainSecondaryColor,
inputClearButtonColor: mainSecondaryColor,
@ -581,7 +581,7 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres
let navigationSearchBar = PresentationThemeNavigationSearchBar(
backgroundColor: mainBackgroundColor,
accentColor: accentColor,
inputFillColor: mainInputColor,
inputFillColor: UIColor(white: 1.0, alpha: 0.1),
inputTextColor: UIColor(rgb: 0xffffff),
inputPlaceholderTextColor: mainSecondaryColor,
inputIconColor: mainSecondaryColor,

View file

@ -566,7 +566,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
pinnedSearchBarColor: UIColor(rgb: 0xe5e5e5),
regularSearchBarColor: UIColor(rgb: 0xe9e9e9),
sectionHeaderFillColor: .white,
sectionHeaderTextColor: .black,
sectionHeaderTextColor: UIColor(rgb: 0x6d6d72),
verifiedIconFillColor: defaultDayAccentColor,
verifiedIconForegroundColor: UIColor(rgb: 0xffffff),
secretIconColor: UIColor(rgb: 0x00b12c),

View file

@ -452,7 +452,8 @@ public final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
self?.buttonPressed()
}
)],
background: centerAction.isAccent ? .activeTint : .panel
background: centerAction.isAccent ? .activeTint : .panel,
keepWide: true
)
}

View file

@ -148,13 +148,13 @@ public final class GlassControlGroupComponent: Component {
))
case let .text(string):
content = AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: string, font: Font.semibold(15.0), textColor: component.background == .activeTint ? component.theme.list.itemCheckColors.foregroundColor : component.theme.chat.inputPanel.panelControlColor))
text: .plain(NSAttributedString(string: string, font: Font.medium(17.0), textColor: component.background == .activeTint ? component.theme.list.itemCheckColors.foregroundColor : component.theme.chat.inputPanel.panelControlColor))
))
itemInsets.left = 10.0
itemInsets.right = itemInsets.left
}
var minItemWidth: CGFloat = 40.0
var minItemWidth: CGFloat = availableSize.height
if component.items.count == 1 {
minItemWidth = max(minItemWidth, component.minWidth)
}
@ -163,7 +163,7 @@ public final class GlassControlGroupComponent: Component {
transition: itemTransition,
component: AnyComponent(PlainButtonComponent(
content: content,
minSize: CGSize(width: minItemWidth, height: 40.0),
minSize: CGSize(width: minItemWidth, height: availableSize.height),
contentInsets: itemInsets,
action: {
item.action?()
@ -186,8 +186,9 @@ public final class GlassControlGroupComponent: Component {
itemComponentView.alpha = 0.0
}
itemTransition.setFrame(view: itemComponentView, frame: itemFrame)
alphaTransition.setAlpha(view: itemComponentView, alpha: item.action != nil ? 1.0 : 0.5)
if animateIn {
alphaTransition.setAlpha(view: itemComponentView, alpha: 1.0)
alphaTransition.animateBlur(layer: itemComponentView.layer, fromRadius: 8.0, toRadius: 0.0)
}
}
@ -220,6 +221,7 @@ public final class GlassControlGroupComponent: Component {
tintColor = .init(kind: .panel, color: component.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7), innerColor: component.theme.list.itemCheckColors.fillColor)
}
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(), size: size))
isInteractive = true
self.backgroundView.update(size: size, cornerRadius: size.height * 0.5, isDark: component.theme.overallDarkAppearance, tintColor: tintColor, isInteractive: isInteractive, transition: transition)
return size

View file

@ -9,10 +9,12 @@ public final class GlassControlPanelComponent: Component {
public final class Item: Equatable {
public let items: [GlassControlGroupComponent.Item]
public let background: GlassControlGroupComponent.Background
public let keepWide: Bool
public init(items: [GlassControlGroupComponent.Item], background: GlassControlGroupComponent.Background) {
public init(items: [GlassControlGroupComponent.Item], background: GlassControlGroupComponent.Background, keepWide: Bool = false) {
self.items = items
self.background = background
self.keepWide = keepWide
}
public static func ==(lhs: Item, rhs: Item) -> Bool {
@ -22,6 +24,9 @@ public final class GlassControlPanelComponent: Component {
if lhs.background != rhs.background {
return false
}
if lhs.keepWide != rhs.keepWide {
return false
}
return true
}
}
@ -30,17 +35,20 @@ public final class GlassControlPanelComponent: Component {
public let leftItem: Item?
public let rightItem: Item?
public let centralItem: Item?
public let centerAlignmentIfPossible: Bool
public init(
theme: PresentationTheme,
leftItem: Item?,
centralItem: Item?,
rightItem: Item?
rightItem: Item?,
centerAlignmentIfPossible: Bool = false
) {
self.theme = theme
self.leftItem = leftItem
self.centralItem = centralItem
self.rightItem = rightItem
self.centerAlignmentIfPossible = centerAlignmentIfPossible
}
public static func ==(lhs: GlassControlPanelComponent, rhs: GlassControlPanelComponent) -> Bool {
@ -56,6 +64,9 @@ public final class GlassControlPanelComponent: Component {
if lhs.rightItem != rhs.rightItem {
return false
}
if lhs.centerAlignmentIfPossible != rhs.centerAlignmentIfPossible {
return false
}
return true
}
@ -118,7 +129,7 @@ public final class GlassControlPanelComponent: Component {
theme: component.theme,
background: leftItem.background,
items: leftItem.items,
minWidth: 40.0
minWidth: availableSize.height
)),
environment: {},
containerSize: CGSize(width: availableSize.width, height: availableSize.height)
@ -167,7 +178,7 @@ public final class GlassControlPanelComponent: Component {
theme: component.theme,
background: rightItem.background,
items: rightItem.items,
minWidth: 40.0
minWidth: availableSize.height
)),
environment: {},
containerSize: CGSize(width: availableSize.width, height: availableSize.height)
@ -233,12 +244,19 @@ public final class GlassControlPanelComponent: Component {
theme: component.theme,
background: centralItem.background,
items: centralItem.items,
minWidth: 165.0
minWidth: centralItem.keepWide ? 165.0 : availableSize.height
)),
environment: {},
containerSize: maxCentralItemSize
)
let centralItemFrameValue = CGRect(origin: CGPoint(x: centralLeftInset + floor((availableSize.width - centralLeftInset - centralRightInset - centralItemSize.width) * 0.5), y: 0.0), size: centralItemSize)
var centralItemFrameValue = CGRect(origin: CGPoint(x: centralLeftInset + floor((availableSize.width - centralLeftInset - centralRightInset - centralItemSize.width) * 0.5), y: 0.0), size: centralItemSize)
if component.centerAlignmentIfPossible {
let maxInset = max(centralLeftInset, centralRightInset)
if availableSize.width - maxInset * 2.0 > centralItemSize.width {
centralItemFrameValue.origin.x = maxInset + floor((availableSize.width - maxInset * 2.0 - centralItemSize.width) * 0.5)
}
}
if let centralItemComponentView = centralItemComponent.view {
var animateIn = false
if centralItemComponentView.superview == nil {

View file

@ -141,7 +141,7 @@ public final class HeaderPanelContainerComponent: Component {
transition: tabsTransition,
component: tabs,
environment: {},
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 40.0)
)
let tabsFrame = CGRect(origin: CGPoint(x: 0.0, y: size.height), size: tabsSize)
if let tabsComponentView = tabsView.view {

View file

@ -619,7 +619,7 @@ public final class HorizontalTabsComponent: Component {
self.reorderingGesture?.isEnabled = component.isEditing
let sizeHeight: CGFloat = 40.0
let sizeHeight: CGFloat = availableSize.height
let sideInset: CGFloat = 0.0

View file

@ -447,33 +447,31 @@ public final class PeerInfoCoverComponent: Component {
let gradientWidth: CGFloat
let gradientHeight: CGFloat = component.defaultHeight
let gradientInset: CGFloat = 100.0
let gradientRelativeInset: CGFloat = gradientInset / gradientHeight
if case .custom = component.subject {
gradientWidth = gradientHeight
self.backgroundView.backgroundColor = backgroundColor
self.backgroundGradientLayer.startPoint = CGPoint(x: 0.5, y: component.avatarCenter.y / gradientHeight + gradientRelativeInset)
self.backgroundGradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0 - gradientRelativeInset)
self.backgroundGradientLayer.startPoint = CGPoint(x: 0.5, y: component.avatarCenter.y / gradientHeight)
self.backgroundGradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
self.backgroundGradientLayer.type = .radial
self.backgroundGradientLayer.colors = [secondaryBackgroundColor.cgColor, backgroundColor.cgColor]
} else if case .status = component.subject {
gradientWidth = availableSize.width
self.backgroundView.backgroundColor = secondaryBackgroundColor
self.backgroundGradientLayer.startPoint = component.gradientCenter
self.backgroundGradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0 - gradientRelativeInset)
self.backgroundGradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
self.backgroundGradientLayer.type = .radial
self.backgroundGradientLayer.colors = [backgroundColor.cgColor, secondaryBackgroundColor.cgColor]
} else {
gradientWidth = availableSize.width
self.backgroundView.backgroundColor = secondaryBackgroundColor
self.backgroundGradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0 - gradientRelativeInset)
self.backgroundGradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
self.backgroundGradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
self.backgroundGradientLayer.type = .axial
self.backgroundGradientLayer.colors = [backgroundColor.cgColor, secondaryBackgroundColor.cgColor]
}
self.backgroundGradientLayer.anchorPoint = CGPoint(x: 0.0, y: 1.0)
let backgroundGradientFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - gradientWidth) / 2.0), y: component.gradientOnTop ? 0.0 : availableSize.height - gradientHeight), size: CGSize(width: gradientWidth, height: gradientHeight)).insetBy(dx: 0.0, dy: -gradientInset)
let backgroundGradientFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - gradientWidth) / 2.0), y: component.gradientOnTop ? 0.0 : availableSize.height - gradientHeight), size: CGSize(width: gradientWidth, height: gradientHeight))
if !transition.animation.isImmediate {
let previousPosition = self.backgroundGradientLayer.position
let updatedPosition = CGPoint(x: backgroundGradientFrame.minX, y: backgroundGradientFrame.maxY)

View file

@ -500,6 +500,7 @@ private func tagMaskForType(_ type: PeerInfoGifPaneNode.ContentType) -> MessageT
private enum ItemsLayout {
final class Grid {
let containerWidth: CGFloat
let topInset: CGFloat
let itemCount: Int
let itemSpacing: CGFloat
let itemsInRow: Int
@ -507,8 +508,9 @@ private enum ItemsLayout {
let rowCount: Int
let contentHeight: CGFloat
init(containerWidth: CGFloat, itemCount: Int, bottomInset: CGFloat) {
init(containerWidth: CGFloat, itemCount: Int, topInset: CGFloat, bottomInset: CGFloat) {
self.containerWidth = containerWidth
self.topInset = topInset
self.itemCount = itemCount
self.itemSpacing = 1.0
self.itemsInRow = max(3, min(6, Int(containerWidth / 140.0)))
@ -516,13 +518,13 @@ private enum ItemsLayout {
self.rowCount = itemCount / self.itemsInRow + (itemCount % self.itemsInRow == 0 ? 0 : 1)
self.contentHeight = CGFloat(self.rowCount + 1) * self.itemSpacing + CGFloat(rowCount) * itemSize + bottomInset
self.contentHeight = topInset + CGFloat(self.rowCount + 1) * self.itemSpacing + CGFloat(rowCount) * itemSize + bottomInset
}
func visibleRange(rect: CGRect) -> (Int, Int) {
var minVisibleRow = Int(floor((rect.minY - self.itemSpacing) / (self.itemSize + self.itemSpacing)))
var minVisibleRow = Int(floor((rect.minY - self.topInset - self.itemSpacing) / (self.itemSize + self.itemSpacing)))
minVisibleRow = max(0, minVisibleRow)
var maxVisibleRow = Int(ceil((rect.maxY - self.itemSpacing) / (self.itemSize + itemSpacing)))
var maxVisibleRow = Int(ceil((rect.maxY - self.topInset - self.itemSpacing) / (self.itemSize + itemSpacing)))
maxVisibleRow = min(self.rowCount - 1, maxVisibleRow)
let minVisibleIndex = minVisibleRow * itemsInRow
@ -534,7 +536,7 @@ private enum ItemsLayout {
func frame(forItemAt index: Int, sideInset: CGFloat) -> CGRect {
let rowIndex = index / Int(self.itemsInRow)
let columnIndex = index % Int(self.itemsInRow)
let itemOrigin = CGPoint(x: sideInset + CGFloat(columnIndex) * (self.itemSize + self.itemSpacing), y: self.itemSpacing + CGFloat(rowIndex) * (self.itemSize + self.itemSpacing))
let itemOrigin = CGPoint(x: sideInset + CGFloat(columnIndex) * (self.itemSize + self.itemSpacing), y: self.topInset + self.itemSpacing + CGFloat(rowIndex) * (self.itemSize + self.itemSpacing))
return CGRect(origin: itemOrigin, size: CGSize(width: columnIndex == self.itemsInRow ? (self.containerWidth - itemOrigin.x) : self.itemSize, height: self.itemSize))
}
}
@ -906,7 +908,7 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScrollViewDe
let previousParams = self.currentParams
self.currentParams = (size, topInset, sideInset, bottomInset, deviceMetrics, visibleHeight, isScrollingLockedAtTop, expandProgress, navigationHeight, presentationData)
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(x: 0.0, y: topInset), size: CGSize(width: size.width, height: size.height - topInset)))
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
let availableWidth = size.width - sideInset * 2.0
@ -916,7 +918,7 @@ final class PeerInfoGifPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScrollViewDe
} else {
switch self.contentType {
case .photoOrVideo, .gifs:
itemsLayout = .grid(ItemsLayout.Grid(containerWidth: availableWidth, itemCount: self.mediaItems.count, bottomInset: bottomInset))
itemsLayout = .grid(ItemsLayout.Grid(containerWidth: availableWidth, itemCount: self.mediaItems.count, topInset: topInset, bottomInset: bottomInset))
}
self.itemsLayout = itemsLayout
}

View file

@ -665,7 +665,8 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
theme: params.presentationData.theme,
customLayout: TabSelectorComponent.CustomLayout(
font: Font.medium(15.0),
spacing: 2.0
spacing: 2.0,
height: 44.0 - 5.0 * 2.0
),
items: tabSelectorItems,
selectedId: AnyHashable(self.currentCollection.rawValue),
@ -702,7 +703,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
}
)),
environment: {},
containerSize: CGSize(width: params.size.width - 10.0 * 2.0, height: 50.0)
containerSize: CGSize(width: params.size.width - 10.0 * 2.0, height: 44.0)
)
if let tabSelectorView = self.tabSelector.view {
if tabSelectorView.superview == nil {
@ -713,7 +714,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
tabSelectorView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
}
}
transition.setFrame(view: tabSelectorView, frame: CGRect(origin: CGPoint(x: floor((params.size.width - tabSelectorSize.width) / 2.0), y: 67.0), size: tabSelectorSize))
transition.setFrame(view: tabSelectorView, frame: CGRect(origin: CGPoint(x: floor((params.size.width - tabSelectorSize.width) / 2.0), y: 66.0), size: tabSelectorSize))
topInset += tabSelectorSize.height + 28.0
}

View file

@ -4036,7 +4036,8 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
customLayout: TabSelectorComponent.CustomLayout(
font: Font.medium(15.0),
spacing: 9.0,
verticalInset: 11.0
verticalInset: 11.0,
height: 44.0 - 5.0 * 2.0
),
items: folderItems,
selectedId: selectedId,
@ -4097,7 +4098,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
environment: {},
containerSize: CGSize(width: size.width, height: 44.0)
)
var folderTabFrame = CGRect(origin: CGPoint(x: floor((size.width - folderTabSize.width) * 0.5), y: topInset - 19.0), size: folderTabSize)
var folderTabFrame = CGRect(origin: CGPoint(x: floor((size.width - folderTabSize.width) * 0.5), y: topInset - 21.0), size: folderTabSize)
let effectiveScrollingOffset: CGFloat
effectiveScrollingOffset = self.itemGrid.scrollingOffset

View file

@ -251,7 +251,7 @@ public final class PremiumDiamondComponent: Component {
func update(component: PremiumDiamondComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
self.component = component
self.sceneView.backgroundColor = component.theme.list.blocksBackgroundColor
//self.sceneView.backgroundColor = component.theme.list.blocksBackgroundColor
self.sceneView.bounds = CGRect(origin: .zero, size: CGSize(width: availableSize.width * 2.0, height: availableSize.height * 2.0))
self.sceneView.center = CGPoint(x: availableSize.width / 2.0, y: availableSize.height / 2.0)

View file

@ -65,8 +65,9 @@ public final class TabSelectorComponent: Component {
public var lineSelection: Bool
public var verticalInset: CGFloat
public var allowScroll: Bool
public var height: CGFloat?
public init(font: UIFont, spacing: CGFloat = 2.0, innerSpacing: CGFloat? = nil, fillWidth: Bool = false, lineSelection: Bool = false, verticalInset: CGFloat = 0.0, allowScroll: Bool = true) {
public init(font: UIFont, spacing: CGFloat = 2.0, innerSpacing: CGFloat? = nil, fillWidth: Bool = false, lineSelection: Bool = false, verticalInset: CGFloat = 0.0, allowScroll: Bool = true, height: CGFloat? = nil) {
self.font = font
self.spacing = spacing
self.innerSpacing = innerSpacing
@ -74,6 +75,7 @@ public final class TabSelectorComponent: Component {
self.lineSelection = lineSelection
self.verticalInset = verticalInset
self.allowScroll = allowScroll
self.height = height
}
}
@ -531,14 +533,17 @@ public final class TabSelectorComponent: Component {
self.reorderRecognizer?.isEnabled = component.reorderItem != nil
let baseHeight: CGFloat
switch component.style {
case .glass:
baseHeight = 32.0
case .legacy:
baseHeight = 28.0
if let customLayout = component.customLayout, let height = customLayout.height {
baseHeight = height
} else {
switch component.style {
case .glass:
baseHeight = 32.0
case .legacy:
baseHeight = 28.0
}
}
var verticalInset: CGFloat = 0.0
if let customLayout = component.customLayout {
verticalInset = customLayout.verticalInset * 2.0