mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Various improvements
This commit is contained in:
@@ -48,19 +48,22 @@ public final class TabSelectorComponent: Component {
|
||||
public let items: [Item]
|
||||
public let selectedId: AnyHashable?
|
||||
public let setSelectedId: (AnyHashable) -> Void
|
||||
public let transitionFraction: CGFloat?
|
||||
|
||||
public init(
|
||||
colors: Colors,
|
||||
customLayout: CustomLayout? = nil,
|
||||
items: [Item],
|
||||
selectedId: AnyHashable?,
|
||||
setSelectedId: @escaping (AnyHashable) -> Void
|
||||
setSelectedId: @escaping (AnyHashable) -> Void,
|
||||
transitionFraction: CGFloat? = nil
|
||||
) {
|
||||
self.colors = colors
|
||||
self.customLayout = customLayout
|
||||
self.items = items
|
||||
self.selectedId = selectedId
|
||||
self.setSelectedId = setSelectedId
|
||||
self.transitionFraction = transitionFraction
|
||||
}
|
||||
|
||||
public static func ==(lhs: TabSelectorComponent, rhs: TabSelectorComponent) -> Bool {
|
||||
@@ -76,6 +79,9 @@ public final class TabSelectorComponent: Component {
|
||||
if lhs.selectedId != rhs.selectedId {
|
||||
return false
|
||||
}
|
||||
if lhs.transitionFraction != rhs.transitionFraction {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -143,9 +149,14 @@ public final class TabSelectorComponent: Component {
|
||||
}
|
||||
|
||||
var contentWidth: CGFloat = 0.0
|
||||
var previousBackgroundRect: CGRect?
|
||||
var selectedBackgroundRect: CGRect?
|
||||
var nextBackgroundRect: CGRect?
|
||||
|
||||
let selectedIndex = component.items.firstIndex(where: { $0.id == component.selectedId })
|
||||
|
||||
var validIds: [AnyHashable] = []
|
||||
var index = 0
|
||||
for item in component.items {
|
||||
var itemTransition = transition
|
||||
let itemView: VisibleItem
|
||||
@@ -160,13 +171,30 @@ public final class TabSelectorComponent: Component {
|
||||
let itemId = item.id
|
||||
validIds.append(itemId)
|
||||
|
||||
var selectionFraction: CGFloat = 0.0
|
||||
if let transitionFraction = component.transitionFraction, let selectedIndex {
|
||||
if item.id == component.selectedId {
|
||||
selectionFraction = 1.0 - abs(transitionFraction)
|
||||
} else {
|
||||
if index == selectedIndex - 1 && transitionFraction < 0.0 {
|
||||
selectionFraction = abs(transitionFraction)
|
||||
} else if index == selectedIndex + 1 && transitionFraction > 0.0 {
|
||||
selectionFraction = abs(transitionFraction)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selectionFraction = item.id == component.selectedId ? 1.0 : 0.0
|
||||
}
|
||||
|
||||
let itemSize = itemView.title.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(PlainButtonComponent(
|
||||
content: AnyComponent(Text(
|
||||
content: AnyComponent(ItemComponent(
|
||||
text: item.title,
|
||||
font: itemFont,
|
||||
color: item.id == component.selectedId && isLineSelection ? component.colors.selection : component.colors.foreground
|
||||
color: component.colors.foreground,
|
||||
selectedColor: component.colors.selection,
|
||||
selectionFraction: isLineSelection ? selectionFraction : 0.0
|
||||
)),
|
||||
effectAlignment: .center,
|
||||
minSize: nil,
|
||||
@@ -192,6 +220,11 @@ public final class TabSelectorComponent: Component {
|
||||
if item.id == component.selectedId {
|
||||
selectedBackgroundRect = itemBackgroundRect
|
||||
}
|
||||
if selectedBackgroundRect == nil {
|
||||
previousBackgroundRect = itemBackgroundRect
|
||||
} else if nextBackgroundRect == nil, itemBackgroundRect != selectedBackgroundRect {
|
||||
nextBackgroundRect = itemBackgroundRect
|
||||
}
|
||||
|
||||
if let itemTitleView = itemView.title.view {
|
||||
if itemTitleView.superview == nil {
|
||||
@@ -202,6 +235,7 @@ public final class TabSelectorComponent: Component {
|
||||
itemTransition.setBounds(view: itemTitleView, bounds: CGRect(origin: CGPoint(), size: itemTitleFrame.size))
|
||||
itemTransition.setAlpha(view: itemTitleView, alpha: item.id == component.selectedId || isLineSelection ? 1.0 : 0.4)
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
|
||||
var removeIds: [AnyHashable] = []
|
||||
@@ -217,9 +251,22 @@ public final class TabSelectorComponent: Component {
|
||||
|
||||
if let selectedBackgroundRect {
|
||||
self.selectionView.alpha = 1.0
|
||||
|
||||
|
||||
if isLineSelection {
|
||||
var mappedSelectionFrame = selectedBackgroundRect.insetBy(dx: 12.0, dy: 0.0)
|
||||
var effectiveBackgroundRect = selectedBackgroundRect
|
||||
if let transitionFraction = component.transitionFraction {
|
||||
if transitionFraction < 0.0 {
|
||||
if let previousBackgroundRect {
|
||||
effectiveBackgroundRect = effectiveBackgroundRect.interpolate(with: previousBackgroundRect, fraction: abs(transitionFraction))
|
||||
}
|
||||
} else if transitionFraction > 0.0 {
|
||||
if let nextBackgroundRect {
|
||||
effectiveBackgroundRect = effectiveBackgroundRect.interpolate(with: nextBackgroundRect, fraction: abs(transitionFraction))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var mappedSelectionFrame = effectiveBackgroundRect.insetBy(dx: 12.0, dy: 0.0)
|
||||
mappedSelectionFrame.origin.y = mappedSelectionFrame.maxY + 6.0
|
||||
mappedSelectionFrame.size.height = 3.0
|
||||
transition.setFrame(view: self.selectionView, frame: mappedSelectionFrame)
|
||||
@@ -242,3 +289,94 @@ public final class TabSelectorComponent: Component {
|
||||
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
extension CGRect {
|
||||
func interpolate(with other: CGRect, fraction: CGFloat) -> CGRect {
|
||||
return CGRect(
|
||||
x: self.origin.x * (1.0 - fraction) + (other.origin.x) * fraction,
|
||||
y: self.origin.y * (1.0 - fraction) + (other.origin.y) * fraction,
|
||||
width: self.size.width * (1.0 - fraction) + (other.size.width) * fraction,
|
||||
height: self.size.height * (1.0 - fraction) + (other.size.height) * fraction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private final class ItemComponent: CombinedComponent {
|
||||
let text: String
|
||||
let font: UIFont
|
||||
let color: UIColor
|
||||
let selectedColor: UIColor
|
||||
let selectionFraction: CGFloat
|
||||
|
||||
init(
|
||||
text: String,
|
||||
font: UIFont,
|
||||
color: UIColor,
|
||||
selectedColor: UIColor,
|
||||
selectionFraction: CGFloat
|
||||
) {
|
||||
self.text = text
|
||||
self.font = font
|
||||
self.color = color
|
||||
self.selectedColor = selectedColor
|
||||
self.selectionFraction = selectionFraction
|
||||
}
|
||||
|
||||
static func ==(lhs: ItemComponent, rhs: ItemComponent) -> Bool {
|
||||
if lhs.text != rhs.text {
|
||||
return false
|
||||
}
|
||||
if lhs.font != rhs.font {
|
||||
return false
|
||||
}
|
||||
if lhs.color != rhs.color {
|
||||
return false
|
||||
}
|
||||
if lhs.selectedColor != rhs.selectedColor {
|
||||
return false
|
||||
}
|
||||
if lhs.selectionFraction != rhs.selectionFraction {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
static var body: Body {
|
||||
let title = Child(Text.self)
|
||||
let selectedTitle = Child(Text.self)
|
||||
|
||||
return { context in
|
||||
let component = context.component
|
||||
|
||||
let title = title.update(
|
||||
component: Text(
|
||||
text: component.text,
|
||||
font: component.font,
|
||||
color: component.color
|
||||
),
|
||||
availableSize: context.availableSize,
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(title
|
||||
.position(CGPoint(x: title.size.width / 2.0, y: title.size.height / 2.0))
|
||||
.opacity(1.0 - component.selectionFraction)
|
||||
)
|
||||
|
||||
let selectedTitle = selectedTitle.update(
|
||||
component: Text(
|
||||
text: component.text,
|
||||
font: component.font,
|
||||
color: component.selectedColor
|
||||
),
|
||||
availableSize: context.availableSize,
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(selectedTitle
|
||||
.position(CGPoint(x: selectedTitle.size.width / 2.0, y: selectedTitle.size.height / 2.0))
|
||||
.opacity(component.selectionFraction)
|
||||
)
|
||||
|
||||
return title.size
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user