mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various improvements
This commit is contained in:
parent
85207874a1
commit
54489f428a
@ -41,6 +41,14 @@ public let sheetComponentTag = GenericComponentViewTag()
|
|||||||
public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
||||||
public typealias EnvironmentType = (ChildEnvironmentType, SheetComponentEnvironment)
|
public typealias EnvironmentType = (ChildEnvironmentType, SheetComponentEnvironment)
|
||||||
|
|
||||||
|
public class ExternalState {
|
||||||
|
public fileprivate(set) var contentHeight: CGFloat
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
self.contentHeight = 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum BackgroundColor: Equatable {
|
public enum BackgroundColor: Equatable {
|
||||||
public enum BlurStyle: Equatable {
|
public enum BlurStyle: Equatable {
|
||||||
case light
|
case light
|
||||||
@ -54,17 +62,20 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
|||||||
public let content: AnyComponent<ChildEnvironmentType>
|
public let content: AnyComponent<ChildEnvironmentType>
|
||||||
public let backgroundColor: BackgroundColor
|
public let backgroundColor: BackgroundColor
|
||||||
public let followContentSizeChanges: Bool
|
public let followContentSizeChanges: Bool
|
||||||
|
public let externalState: ExternalState?
|
||||||
public let animateOut: ActionSlot<Action<()>>
|
public let animateOut: ActionSlot<Action<()>>
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
content: AnyComponent<ChildEnvironmentType>,
|
content: AnyComponent<ChildEnvironmentType>,
|
||||||
backgroundColor: BackgroundColor,
|
backgroundColor: BackgroundColor,
|
||||||
followContentSizeChanges: Bool = false,
|
followContentSizeChanges: Bool = false,
|
||||||
|
externalState: ExternalState? = nil,
|
||||||
animateOut: ActionSlot<Action<()>>
|
animateOut: ActionSlot<Action<()>>
|
||||||
) {
|
) {
|
||||||
self.content = content
|
self.content = content
|
||||||
self.backgroundColor = backgroundColor
|
self.backgroundColor = backgroundColor
|
||||||
self.followContentSizeChanges = followContentSizeChanges
|
self.followContentSizeChanges = followContentSizeChanges
|
||||||
|
self.externalState = externalState
|
||||||
self.animateOut = animateOut
|
self.animateOut = animateOut
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,6 +338,7 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
|||||||
},
|
},
|
||||||
containerSize: containerSize
|
containerSize: containerSize
|
||||||
)
|
)
|
||||||
|
component.externalState?.contentHeight = contentSize.height
|
||||||
|
|
||||||
self.ignoreScrolling = true
|
self.ignoreScrolling = true
|
||||||
if let contentView = self.contentView.view {
|
if let contentView = self.contentView.view {
|
||||||
|
@ -591,7 +591,7 @@ class GiftOptionItemNode: ItemListRevealOptionsItemNode {
|
|||||||
let badgeSize = strongSelf.titleBadge.update(
|
let badgeSize = strongSelf.titleBadge.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(
|
component: AnyComponent(
|
||||||
BoostIconComponent(text: badge)
|
BoostIconComponent(hasIcon: true, text: badge)
|
||||||
),
|
),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: params.width, height: 100.0)
|
containerSize: CGSize(width: params.width, height: 100.0)
|
||||||
|
@ -10,6 +10,34 @@ import PresentationDataUtils
|
|||||||
|
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
|
|
||||||
|
private struct BoostState {
|
||||||
|
let level: Int32
|
||||||
|
let currentLevelBoosts: Int32
|
||||||
|
let nextLevelBoosts: Int32?
|
||||||
|
let boosts: Int32
|
||||||
|
|
||||||
|
func displayData(peer: EnginePeer, isCurrent: 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, isCurrent: isCurrent, level: currentLevel, currentLevelBoosts: currentLevelBoosts, nextLevelBoosts: nextLevelBoosts, link: nil, myBoostCount: myBoostCount),
|
||||||
|
boosts
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func PremiumBoostScreen(
|
public func PremiumBoostScreen(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
contentContext: Any?,
|
contentContext: Any?,
|
||||||
@ -17,6 +45,7 @@ public func PremiumBoostScreen(
|
|||||||
isCurrent: Bool,
|
isCurrent: Bool,
|
||||||
status: ChannelBoostStatus?,
|
status: ChannelBoostStatus?,
|
||||||
myBoostStatus: MyBoostStatus?,
|
myBoostStatus: MyBoostStatus?,
|
||||||
|
replacedBoosts: (Int32, Int32)? = nil,
|
||||||
forceDark: Bool,
|
forceDark: Bool,
|
||||||
openPeer: @escaping (EnginePeer) -> Void,
|
openPeer: @escaping (EnginePeer) -> Void,
|
||||||
presentController: @escaping (ViewController) -> Void,
|
presentController: @escaping (ViewController) -> Void,
|
||||||
@ -35,6 +64,7 @@ public func PremiumBoostScreen(
|
|||||||
let isPremium = accountPeer.isPremium
|
let isPremium = accountPeer.isPremium
|
||||||
|
|
||||||
var myBoostCount: Int32 = 0
|
var myBoostCount: Int32 = 0
|
||||||
|
var currentMyBoostCount: Int32 = 0
|
||||||
var availableBoosts: [MyBoostStatus.Boost] = []
|
var availableBoosts: [MyBoostStatus.Boost] = []
|
||||||
var occupiedBoosts: [MyBoostStatus.Boost] = []
|
var occupiedBoosts: [MyBoostStatus.Boost] = []
|
||||||
if let myBoostStatus {
|
if let myBoostStatus {
|
||||||
@ -51,25 +81,15 @@ public func PremiumBoostScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentLevel = Int32(status.level)
|
let initialState = BoostState(level: Int32(status.level), currentLevelBoosts: Int32(status.currentLevelBoosts), nextLevelBoosts: status.nextLevelBoosts.flatMap(Int32.init), boosts: Int32(status.boosts))
|
||||||
var currentLevelBoosts = Int32(status.currentLevelBoosts)
|
let updatedState = Promise<BoostState?>()
|
||||||
var nextLevelBoosts = status.nextLevelBoosts.flatMap(Int32.init)
|
updatedState.set(.single(BoostState(level: Int32(status.level), currentLevelBoosts: Int32(status.currentLevelBoosts), nextLevelBoosts: status.nextLevelBoosts.flatMap(Int32.init), boosts: Int32(status.boosts + 1))))
|
||||||
|
|
||||||
if myBoostCount > 0 && status.boosts == currentLevelBoosts {
|
|
||||||
currentLevel = max(0, currentLevel - 1)
|
|
||||||
nextLevelBoosts = currentLevelBoosts
|
|
||||||
currentLevelBoosts = max(0, currentLevelBoosts - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
let subject: PremiumLimitScreen.Subject = .storiesChannelBoost(peer: peer, isCurrent: isCurrent, level: currentLevel, currentLevelBoosts: currentLevelBoosts, nextLevelBoosts: nextLevelBoosts, link: nil, myBoostCount: myBoostCount)
|
|
||||||
let nextSubject = Promise<PremiumLimitScreen.Subject>()
|
|
||||||
nextSubject.set(.single(.storiesChannelBoost(peer: peer, isCurrent: isCurrent, level: currentLevel, currentLevelBoosts: currentLevelBoosts, nextLevelBoosts: nextLevelBoosts, link: nil, myBoostCount: myBoostCount + 1)))
|
|
||||||
|
|
||||||
var nextCount = Int32(status.boosts + 1)
|
|
||||||
|
|
||||||
var updateImpl: (() -> Void)?
|
var updateImpl: (() -> Void)?
|
||||||
var dismissImpl: (() -> Void)?
|
var dismissImpl: (() -> Void)?
|
||||||
let controller = PremiumLimitScreen(context: context, subject: subject, count: Int32(status.boosts), forceDark: forceDark, action: {
|
|
||||||
|
let (initialSubject, initialCount) = initialState.displayData(peer: peer, isCurrent: isCurrent, myBoostCount: myBoostCount, currentMyBoostCount: 0, replacedBoosts: replacedBoosts?.0)
|
||||||
|
let controller = PremiumLimitScreen(context: context, subject: initialSubject, count: initialCount, forceDark: forceDark, action: {
|
||||||
let dismiss = false
|
let dismiss = false
|
||||||
updateImpl?()
|
updateImpl?()
|
||||||
return dismiss
|
return dismiss
|
||||||
@ -79,32 +99,87 @@ public func PremiumBoostScreen(
|
|||||||
})
|
})
|
||||||
pushController(controller)
|
pushController(controller)
|
||||||
|
|
||||||
|
if let (replacedBoosts, inChannels) = replacedBoosts {
|
||||||
|
currentMyBoostCount += 1
|
||||||
|
let (subject, count) = initialState.displayData(peer: peer, isCurrent: isCurrent, 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: "\(replacedBoosts) boosts are reassigned from \(inChannels) other channel.", round: false, undoText: nil), elevatedLayout: false, position: .bottom, action: { _ in return true })
|
||||||
|
controller.present(undoController, in: .current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
controller.disposed = {
|
controller.disposed = {
|
||||||
dismissed()
|
dismissed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var updating = false
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
updateImpl = { [weak controller] in
|
updateImpl = { [weak controller] in
|
||||||
|
guard !updating else {
|
||||||
|
return
|
||||||
|
}
|
||||||
if let _ = status.nextLevelBoosts {
|
if let _ = status.nextLevelBoosts {
|
||||||
if let availableBoost = availableBoosts.first {
|
if let availableBoost = availableBoosts.first {
|
||||||
let _ = context.engine.peers.applyChannelBoost(peerId: peerId, slots: [availableBoost.slot]).startStandalone()
|
currentMyBoostCount += 1
|
||||||
let _ = (nextSubject.get()
|
myBoostCount += 1
|
||||||
|
|
||||||
|
updating = true
|
||||||
|
let _ = (context.engine.peers.applyChannelBoost(peerId: peerId, slots: [availableBoost.slot])
|
||||||
|
|> deliverOnMainQueue).startStandalone(completed: {
|
||||||
|
updating = false
|
||||||
|
|
||||||
|
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)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).startStandalone(next: { nextSubject in
|
|> deliverOnMainQueue).startStandalone(next: { state in
|
||||||
controller?.updateSubject(nextSubject, count: nextCount)
|
guard let state else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let (subject, count) = state.displayData(peer: peer, isCurrent: isCurrent, myBoostCount: myBoostCount, currentMyBoostCount: currentMyBoostCount)
|
||||||
|
controller?.updateSubject(subject, count: count)
|
||||||
})
|
})
|
||||||
|
|
||||||
availableBoosts.removeFirst()
|
availableBoosts.removeFirst()
|
||||||
nextCount += 1
|
|
||||||
} else if !occupiedBoosts.isEmpty, let myBoostStatus {
|
} else if !occupiedBoosts.isEmpty, let myBoostStatus {
|
||||||
|
var dismissReplaceImpl: (() -> Void)?
|
||||||
let replaceController = ReplaceBoostScreen(context: context, peerId: peerId, myBoostStatus: myBoostStatus, replaceBoosts: { slots in
|
let replaceController = ReplaceBoostScreen(context: context, peerId: peerId, myBoostStatus: myBoostStatus, replaceBoosts: { slots in
|
||||||
let _ = context.engine.peers.applyChannelBoost(peerId: peerId, slots: slots).startStandalone()
|
var channelIds = Set<EnginePeer.Id>()
|
||||||
|
for boost in myBoostStatus.boosts {
|
||||||
|
if slots.contains(boost.slot) {
|
||||||
|
if let peer = boost.peer {
|
||||||
|
channelIds.insert(peer.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let undoController = UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "\(slots.count) boosts are reassigned from 1 other channel.", timeout: nil, customUndoText: nil), elevatedLayout: true, position: .bottom, action: { _ in return true })
|
let _ = context.engine.peers.applyChannelBoost(peerId: peerId, slots: slots).startStandalone(completed: {
|
||||||
presentController(undoController)
|
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?()
|
dismissImpl?()
|
||||||
pushController(replaceController)
|
pushController(replaceController)
|
||||||
|
dismissReplaceImpl = { [weak replaceController] in
|
||||||
|
replaceController?.dismiss(animated: true)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if isPremium {
|
if isPremium {
|
||||||
let controller = textAlertController(
|
let controller = textAlertController(
|
||||||
|
@ -821,7 +821,7 @@ private final class LimitSheetContent: CombinedComponent {
|
|||||||
let closeButton = Child(Button.self)
|
let closeButton = Child(Button.self)
|
||||||
let title = Child(MultilineTextComponent.self)
|
let title = Child(MultilineTextComponent.self)
|
||||||
let text = Child(BalancedTextComponent.self)
|
let text = Child(BalancedTextComponent.self)
|
||||||
let alternateText = Child(BalancedTextComponent.self)
|
let alternateText = Child(List<Empty>.self)
|
||||||
let limit = Child(PremiumLimitDisplayComponent.self)
|
let limit = Child(PremiumLimitDisplayComponent.self)
|
||||||
let linkButton = Child(SolidRoundedButtonComponent.self)
|
let linkButton = Child(SolidRoundedButtonComponent.self)
|
||||||
let button = Child(SolidRoundedButtonComponent.self)
|
let button = Child(SolidRoundedButtonComponent.self)
|
||||||
@ -881,6 +881,9 @@ private final class LimitSheetContent: CombinedComponent {
|
|||||||
var peerShortcutChild: _UpdatedChildComponent?
|
var peerShortcutChild: _UpdatedChildComponent?
|
||||||
|
|
||||||
var useAlternateText = false
|
var useAlternateText = false
|
||||||
|
var alternateTitle = ""
|
||||||
|
var alternateBadge: String?
|
||||||
|
|
||||||
var titleText = strings.Premium_LimitReached
|
var titleText = strings.Premium_LimitReached
|
||||||
var actionButtonText: String?
|
var actionButtonText: String?
|
||||||
var actionButtonHasGloss = true
|
var actionButtonHasGloss = true
|
||||||
@ -1159,7 +1162,7 @@ private final class LimitSheetContent: CombinedComponent {
|
|||||||
state.myBoostCount = myBoostCount
|
state.myBoostCount = myBoostCount
|
||||||
boostUpdated = true
|
boostUpdated = true
|
||||||
}
|
}
|
||||||
useAlternateText = (myBoostCount % 2) != 0
|
useAlternateText = myBoostCount > 0
|
||||||
|
|
||||||
iconName = "Premium/Boost"
|
iconName = "Premium/Boost"
|
||||||
badgeText = "\(component.count)"
|
badgeText = "\(component.count)"
|
||||||
@ -1217,8 +1220,10 @@ private final class LimitSheetContent: CombinedComponent {
|
|||||||
premiumTitle = ""
|
premiumTitle = ""
|
||||||
|
|
||||||
if myBoostCount > 0 {
|
if myBoostCount > 0 {
|
||||||
let prefixString = isCurrent ? strings.ChannelBoost_YouBoostedChannelText(peer.compactDisplayTitle).string : strings.ChannelBoost_YouBoostedOtherChannelText
|
alternateTitle = isCurrent ? strings.ChannelBoost_YouBoostedChannelText(peer.compactDisplayTitle).string : strings.ChannelBoost_YouBoostedOtherChannelText
|
||||||
|
if myBoostCount > 1 {
|
||||||
|
alternateBadge = "X\(myBoostCount)"
|
||||||
|
}
|
||||||
let storiesString = strings.ChannelBoost_StoriesPerDay(level + 1)
|
let storiesString = strings.ChannelBoost_StoriesPerDay(level + 1)
|
||||||
if let _ = remaining {
|
if let _ = remaining {
|
||||||
actionButtonText = "Boost Again"
|
actionButtonText = "Boost Again"
|
||||||
@ -1246,8 +1251,6 @@ private final class LimitSheetContent: CombinedComponent {
|
|||||||
} else {
|
} else {
|
||||||
string = strings.ChannelBoost_BoostedChannelReachedLevel("\(level + 1)", storiesString).string
|
string = strings.ChannelBoost_BoostedChannelReachedLevel("\(level + 1)", storiesString).string
|
||||||
}
|
}
|
||||||
|
|
||||||
string = "**\(prefixString)**\n\(string)"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let progress: CGFloat
|
let progress: CGFloat
|
||||||
@ -1299,15 +1302,42 @@ private final class LimitSheetContent: CombinedComponent {
|
|||||||
var alternateTextChild: _UpdatedChildComponent?
|
var alternateTextChild: _UpdatedChildComponent?
|
||||||
if useAlternateText {
|
if useAlternateText {
|
||||||
alternateTextChild = alternateText.update(
|
alternateTextChild = alternateText.update(
|
||||||
component: BalancedTextComponent(
|
component: List(
|
||||||
|
[
|
||||||
|
AnyComponentWithIdentity(
|
||||||
|
id: "title",
|
||||||
|
component: AnyComponent(
|
||||||
|
BoostedTitleContent(text: NSAttributedString(string: alternateTitle, font: Font.semibold(15.0), textColor: textColor), badge: alternateBadge)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
AnyComponentWithIdentity(
|
||||||
|
id: "text",
|
||||||
|
component: AnyComponent(
|
||||||
|
BalancedTextComponent(
|
||||||
text: .markdown(text: string, attributes: markdownAttributes),
|
text: .markdown(text: string, attributes: markdownAttributes),
|
||||||
horizontalAlignment: .center,
|
horizontalAlignment: .center,
|
||||||
maximumNumberOfLines: 0,
|
maximumNumberOfLines: 0,
|
||||||
lineSpacing: 0.1
|
lineSpacing: 0.1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
centerAlignment: true
|
||||||
),
|
),
|
||||||
availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),
|
availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),
|
||||||
transition: .immediate
|
transition: .immediate
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// alternateTextChild = alternateText.update(
|
||||||
|
// component: BalancedTextComponent(
|
||||||
|
// text: .markdown(text: string, attributes: markdownAttributes),
|
||||||
|
// horizontalAlignment: .center,
|
||||||
|
// maximumNumberOfLines: 0,
|
||||||
|
// lineSpacing: 0.1
|
||||||
|
// ),
|
||||||
|
// availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),
|
||||||
|
// transition: .immediate
|
||||||
|
// )
|
||||||
} else {
|
} else {
|
||||||
textChild = text.update(
|
textChild = text.update(
|
||||||
component: BalancedTextComponent(
|
component: BalancedTextComponent(
|
||||||
@ -1417,7 +1447,7 @@ private final class LimitSheetContent: CombinedComponent {
|
|||||||
)
|
)
|
||||||
buttonOffset += 66.0
|
buttonOffset += 66.0
|
||||||
|
|
||||||
let linkFrame = CGRect(origin: CGPoint(x: sideInset, y: textOffset + ceil((textChild?.size ?? .zero).height / 2.0) + 24.0), size: linkButton.size)
|
let linkFrame = CGRect(origin: CGPoint(x: sideInset, y: textOffset + (textChild?.size ?? .zero).height + 24.0), size: linkButton.size)
|
||||||
context.add(linkButton
|
context.add(linkButton
|
||||||
.position(CGPoint(x: linkFrame.midX, y: linkFrame.midY))
|
.position(CGPoint(x: linkFrame.midX, y: linkFrame.midY))
|
||||||
)
|
)
|
||||||
@ -1637,6 +1667,8 @@ private final class LimitSheetComponent: CombinedComponent {
|
|||||||
let sheet = Child(SheetComponent<EnvironmentType>.self)
|
let sheet = Child(SheetComponent<EnvironmentType>.self)
|
||||||
let animateOut = StoredActionSlot(Action<Void>.self)
|
let animateOut = StoredActionSlot(Action<Void>.self)
|
||||||
|
|
||||||
|
let sheetExternalState = SheetComponent<EnvironmentType>.ExternalState()
|
||||||
|
|
||||||
return { context in
|
return { context in
|
||||||
let environment = context.environment[EnvironmentType.self]
|
let environment = context.environment[EnvironmentType.self]
|
||||||
|
|
||||||
@ -1663,6 +1695,7 @@ private final class LimitSheetComponent: CombinedComponent {
|
|||||||
)),
|
)),
|
||||||
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
|
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
|
||||||
followContentSizeChanges: true,
|
followContentSizeChanges: true,
|
||||||
|
externalState: sheetExternalState,
|
||||||
animateOut: animateOut
|
animateOut: animateOut
|
||||||
),
|
),
|
||||||
environment: {
|
environment: {
|
||||||
@ -1695,6 +1728,22 @@ private final class LimitSheetComponent: CombinedComponent {
|
|||||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0))
|
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if let controller = controller(), !controller.automaticallyControlPresentationContextLayout {
|
||||||
|
let layout = ContainerViewLayout(
|
||||||
|
size: context.availableSize,
|
||||||
|
metrics: environment.metrics,
|
||||||
|
deviceMetrics: environment.deviceMetrics,
|
||||||
|
intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: max(environment.safeInsets.bottom, sheetExternalState.contentHeight), right: 0.0),
|
||||||
|
safeInsets: UIEdgeInsets(top: 0.0, left: environment.safeInsets.left, bottom: 0.0, right: environment.safeInsets.right),
|
||||||
|
additionalInsets: .zero,
|
||||||
|
statusBarHeight: environment.statusBarHeight,
|
||||||
|
inputHeight: nil,
|
||||||
|
inputHeightIsInteractivellyChanging: false,
|
||||||
|
inVoiceOver: false
|
||||||
|
)
|
||||||
|
controller.presentationContext.containerLayoutUpdated(layout, transition: context.transition.containedViewLayoutTransition)
|
||||||
|
}
|
||||||
|
|
||||||
return context.availableSize
|
return context.availableSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1734,6 +1783,9 @@ public class PremiumLimitScreen: ViewControllerComponentContainer {
|
|||||||
}, openPeer: openPeer, openStats: openStats, openGift: openGift), navigationBarAppearance: .none, statusBarStyle: .ignore, theme: forceDark ? .dark : .default)
|
}, openPeer: openPeer, openStats: openStats, openGift: openGift), navigationBarAppearance: .none, statusBarStyle: .ignore, theme: forceDark ? .dark : .default)
|
||||||
|
|
||||||
self.navigationPresentation = .flatModal
|
self.navigationPresentation = .flatModal
|
||||||
|
if case .storiesChannelBoost = subject {
|
||||||
|
self.automaticallyControlPresentationContextLayout = false
|
||||||
|
}
|
||||||
|
|
||||||
self.wasDismissed = cancel
|
self.wasDismissed = cancel
|
||||||
|
|
||||||
@ -1769,13 +1821,25 @@ public class PremiumLimitScreen: ViewControllerComponentContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func updateSubject(_ subject: Subject, count: Int32) {
|
public func updateSubject(_ subject: Subject, count: Int32) {
|
||||||
let component = LimitSheetComponent(context: self.context, subject: subject, count: count, cancel: {}, action: {
|
let component = LimitSheetComponent(
|
||||||
return true
|
context: self.context,
|
||||||
}, openPeer: self.openPeer, openStats: nil, openGift: nil)
|
subject: subject,
|
||||||
|
count: count,
|
||||||
|
cancel: {},
|
||||||
|
action: { [weak self] in
|
||||||
|
return self?.action?() ?? true
|
||||||
|
},
|
||||||
|
openPeer: self.openPeer,
|
||||||
|
openStats: nil,
|
||||||
|
openGift: nil
|
||||||
|
)
|
||||||
self.updateComponent(component: AnyComponent(component), transition: .easeInOut(duration: 0.2))
|
self.updateComponent(component: AnyComponent(component), transition: .easeInOut(duration: 0.2))
|
||||||
|
|
||||||
self.hapticFeedback.impact()
|
self.animateSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func animateSuccess() {
|
||||||
|
self.hapticFeedback.impact()
|
||||||
self.view.addSubview(ConfettiView(frame: self.view.bounds))
|
self.view.addSubview(ConfettiView(frame: self.view.bounds))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1814,8 +1878,6 @@ private final class PeerShortcutComponent: Component {
|
|||||||
private let avatarNode: AvatarNode
|
private let avatarNode: AvatarNode
|
||||||
private let text = ComponentView<Empty>()
|
private let text = ComponentView<Empty>()
|
||||||
|
|
||||||
private let badge = ComponentView<Empty>()
|
|
||||||
|
|
||||||
private var component: PeerShortcutComponent?
|
private var component: PeerShortcutComponent?
|
||||||
private weak var state: EmptyComponentState?
|
private weak var state: EmptyComponentState?
|
||||||
|
|
||||||
@ -1869,29 +1931,6 @@ private final class PeerShortcutComponent: Component {
|
|||||||
view.frame = textFrame
|
view.frame = textFrame
|
||||||
}
|
}
|
||||||
|
|
||||||
if let badge = component.badge {
|
|
||||||
let badgeSize = self.badge.update(
|
|
||||||
transition: .immediate,
|
|
||||||
component: AnyComponent(
|
|
||||||
BoostIconComponent(text: badge)
|
|
||||||
),
|
|
||||||
environment: {},
|
|
||||||
containerSize: availableSize
|
|
||||||
)
|
|
||||||
if let view = self.badge.view {
|
|
||||||
if view.superview == nil {
|
|
||||||
self.addSubview(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
let badgeFrame = CGRect(origin: CGPoint(x: floorToScreenPixels(size.width - badgeSize.width / 2.0), y: -5.0), size: badgeSize)
|
|
||||||
view.frame = badgeFrame
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if let view = self.badge.view {
|
|
||||||
view.removeFromSuperview()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.backgroundView.frame = CGRect(origin: .zero, size: size)
|
self.backgroundView.frame = CGRect(origin: .zero, size: size)
|
||||||
|
|
||||||
return size
|
return size
|
||||||
@ -1908,13 +1947,18 @@ private final class PeerShortcutComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class BoostIconComponent: Component {
|
public final class BoostIconComponent: Component {
|
||||||
|
let hasIcon: Bool
|
||||||
let text: String
|
let text: String
|
||||||
|
|
||||||
public init(text: String) {
|
public init(hasIcon: Bool, text: String) {
|
||||||
|
self.hasIcon = hasIcon
|
||||||
self.text = text
|
self.text = text
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: BoostIconComponent, rhs: BoostIconComponent) -> Bool {
|
public static func ==(lhs: BoostIconComponent, rhs: BoostIconComponent) -> Bool {
|
||||||
|
if lhs.hasIcon != rhs.hasIcon {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.text != rhs.text {
|
if lhs.text != rhs.text {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -1961,11 +2005,11 @@ public final class BoostIconComponent: Component {
|
|||||||
)
|
)
|
||||||
|
|
||||||
let spacing: CGFloat = 2.0
|
let spacing: CGFloat = 2.0
|
||||||
var totalWidth = textSize.width + spacing
|
var totalWidth = textSize.width
|
||||||
var iconSize = CGSize()
|
var iconSize = CGSize()
|
||||||
if let icon = self.badgeIcon.image {
|
if let icon = self.badgeIcon.image, component.hasIcon {
|
||||||
iconSize = CGSize(width: icon.size.width * 0.9, height: icon.size.height * 0.9)
|
iconSize = CGSize(width: icon.size.width * 0.9, height: icon.size.height * 0.9)
|
||||||
totalWidth += icon.size.width
|
totalWidth += spacing + icon.size.width
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = CGSize(width: totalWidth + 8.0, height: 19.0)
|
let size = CGSize(width: totalWidth + 8.0, height: 19.0)
|
||||||
@ -1973,7 +2017,7 @@ public final class BoostIconComponent: Component {
|
|||||||
let iconFrame = CGRect(x: floorToScreenPixels((size.width - totalWidth) / 2.0 + 1.0), y: 4.0 + UIScreenPixel, width: iconSize.width, height: iconSize.height)
|
let iconFrame = CGRect(x: floorToScreenPixels((size.width - totalWidth) / 2.0 + 1.0), y: 4.0 + UIScreenPixel, width: iconSize.width, height: iconSize.height)
|
||||||
self.badgeIcon.frame = iconFrame
|
self.badgeIcon.frame = iconFrame
|
||||||
|
|
||||||
let textFrame = CGRect(origin: CGPoint(x: iconFrame.maxX + spacing, y: 4.0), size: textSize)
|
let textFrame = CGRect(origin: CGPoint(x: component.hasIcon ? iconFrame.maxX + spacing : 5.0, y: 4.0), size: textSize)
|
||||||
|
|
||||||
if let view = self.badgeText.view {
|
if let view = self.badgeText.view {
|
||||||
if view.superview == nil {
|
if view.superview == nil {
|
||||||
@ -1997,3 +2041,64 @@ public final class BoostIconComponent: Component {
|
|||||||
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class BoostedTitleContent: CombinedComponent {
|
||||||
|
let text: NSAttributedString
|
||||||
|
let badge: String?
|
||||||
|
|
||||||
|
init(
|
||||||
|
text: NSAttributedString,
|
||||||
|
badge: String?
|
||||||
|
) {
|
||||||
|
self.text = text
|
||||||
|
self.badge = badge
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: BoostedTitleContent, rhs: BoostedTitleContent) -> Bool {
|
||||||
|
if lhs.text != rhs.text {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.badge != rhs.badge {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
static var body: Body {
|
||||||
|
let text = Child(MultilineTextComponent.self)
|
||||||
|
let badge = Child(BoostIconComponent.self)
|
||||||
|
|
||||||
|
return { context in
|
||||||
|
let component = context.component
|
||||||
|
|
||||||
|
let height: CGFloat = 24.0
|
||||||
|
var totalWidth: CGFloat = 0.0
|
||||||
|
let text = text.update(
|
||||||
|
component: MultilineTextComponent(
|
||||||
|
text: .plain(component.text),
|
||||||
|
horizontalAlignment: .center
|
||||||
|
),
|
||||||
|
availableSize: CGSize(width: context.availableSize.width - 40.0, height: context.availableSize.height),
|
||||||
|
transition: .immediate
|
||||||
|
)
|
||||||
|
totalWidth += text.size.width
|
||||||
|
context.add(text
|
||||||
|
.position(CGPoint(x: text.size.width / 2.0, y: height / 2.0))
|
||||||
|
)
|
||||||
|
|
||||||
|
if let badgeText = component.badge {
|
||||||
|
let badge = badge.update(
|
||||||
|
component: BoostIconComponent(hasIcon: false, text: badgeText),
|
||||||
|
availableSize: CGSize(width: 24.0, height: 24.0),
|
||||||
|
transition: .immediate
|
||||||
|
)
|
||||||
|
totalWidth += badge.size.width + 4.0
|
||||||
|
context.add(badge
|
||||||
|
.position(CGPoint(x: totalWidth - badge.size.width / 2.0, y: height / 2.0))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return CGSize(width: totalWidth, height: height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -349,7 +349,6 @@ public class ReplaceBoostScreen: ViewController {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.controller?.replaceBoosts?(self.selectedSlots)
|
self.controller?.replaceBoosts?(self.selectedSlots)
|
||||||
self.controller?.dismiss(animated: true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +368,7 @@ public class ReplaceBoostScreen: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
|
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||||
if case .ended = recognizer.state {
|
if case .ended = recognizer.state, !self.footerView.inProgress {
|
||||||
self.controller?.dismiss(animated: true)
|
self.controller?.dismiss(animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -950,10 +949,12 @@ private final class FooterView: UIView {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
private var currentLayout: (CGSize, UIEdgeInsets)?
|
fileprivate var inProgress = false
|
||||||
|
|
||||||
|
private var currentLayout: (CGSize, UIEdgeInsets, PresentationTheme, Int32)?
|
||||||
func update(size: CGSize, insets: UIEdgeInsets, theme: PresentationTheme, count: Int32) -> CGFloat {
|
func update(size: CGSize, insets: UIEdgeInsets, theme: PresentationTheme, count: Int32) -> CGFloat {
|
||||||
let hadLayout = self.currentLayout != nil
|
let hadLayout = self.currentLayout != nil
|
||||||
self.currentLayout = (size, insets)
|
self.currentLayout = (size, insets, theme, count)
|
||||||
|
|
||||||
self.backgroundNode.updateColor(color: theme.rootController.tabBar.backgroundColor, transition: .immediate)
|
self.backgroundNode.updateColor(color: theme.rootController.tabBar.backgroundColor, transition: .immediate)
|
||||||
self.separatorView.backgroundColor = theme.rootController.tabBar.separatorColor
|
self.separatorView.backgroundColor = theme.rootController.tabBar.separatorColor
|
||||||
@ -996,11 +997,15 @@ private final class FooterView: UIView {
|
|||||||
))
|
))
|
||||||
),
|
),
|
||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
displaysProgress: false,
|
displaysProgress: self.inProgress,
|
||||||
action: { [weak self] in
|
action: { [weak self] in
|
||||||
guard let self else {
|
guard let self, !self.inProgress else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
self.inProgress = true
|
||||||
|
if let (size, insets, theme, count) = self.currentLayout {
|
||||||
|
let _ = self.update(size: size, insets: insets, theme: theme, count: count)
|
||||||
|
}
|
||||||
self.action()
|
self.action()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -109,7 +109,7 @@ final class EmojiPickerItemNode: ListViewItemNode {
|
|||||||
let insets: UIEdgeInsets
|
let insets: UIEdgeInsets
|
||||||
let separatorHeight = UIScreenPixel
|
let separatorHeight = UIScreenPixel
|
||||||
|
|
||||||
let contentSize = CGSize(width: params.width, height: 200.0)
|
let contentSize = CGSize(width: params.width, height: params.availableHeight - 452.0)
|
||||||
insets = itemListNeighborsGroupedInsets(neighbors, params)
|
insets = itemListNeighborsGroupedInsets(neighbors, params)
|
||||||
|
|
||||||
let layout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: contentSize.height - 20.0), insets: insets)
|
let layout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: contentSize.height - 20.0), insets: insets)
|
||||||
|
@ -189,7 +189,7 @@ private func peerNameColorScreenEntries(
|
|||||||
state: PeerNameColorScreenState,
|
state: PeerNameColorScreenState,
|
||||||
peer: EnginePeer?,
|
peer: EnginePeer?,
|
||||||
isPremium: Bool,
|
isPremium: Bool,
|
||||||
emojiContent: EmojiPagerContentComponent
|
emojiContent: EmojiPagerContentComponent?
|
||||||
) -> [PeerNameColorScreenEntry] {
|
) -> [PeerNameColorScreenEntry] {
|
||||||
var entries: [PeerNameColorScreenEntry] = []
|
var entries: [PeerNameColorScreenEntry] = []
|
||||||
|
|
||||||
@ -255,9 +255,11 @@ private func peerNameColorScreenEntries(
|
|||||||
))
|
))
|
||||||
entries.append(.colorDescription(presentationData.strings.NameColor_ChatPreview_Description_Account))
|
entries.append(.colorDescription(presentationData.strings.NameColor_ChatPreview_Description_Account))
|
||||||
|
|
||||||
|
if let emojiContent {
|
||||||
entries.append(.backgroundEmojiHeader(presentationData.strings.NameColor_BackgroundEmoji_Title))
|
entries.append(.backgroundEmojiHeader(presentationData.strings.NameColor_BackgroundEmoji_Title))
|
||||||
entries.append(.backgroundEmoji(emojiContent, nameColor.color))
|
entries.append(.backgroundEmoji(emojiContent, nameColor.color))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
@ -316,7 +318,7 @@ public func PeerNameColorScreen(
|
|||||||
statePromise.get(),
|
statePromise.get(),
|
||||||
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||||
)
|
)
|
||||||
|> mapToSignal { state, peer in
|
|> mapToSignal { state, peer -> Signal<EmojiPagerContentComponent?, NoError> in
|
||||||
var selectedEmojiId: Int64?
|
var selectedEmojiId: Int64?
|
||||||
if let updatedBackgroundEmojiId = state.updatedBackgroundEmojiId {
|
if let updatedBackgroundEmojiId = state.updatedBackgroundEmojiId {
|
||||||
selectedEmojiId = updatedBackgroundEmojiId
|
selectedEmojiId = updatedBackgroundEmojiId
|
||||||
@ -351,6 +353,7 @@ public func PeerNameColorScreen(
|
|||||||
selectedItems: Set(selectedItems),
|
selectedItems: Set(selectedItems),
|
||||||
backgroundIconColor: nameColor
|
backgroundIconColor: nameColor
|
||||||
)
|
)
|
||||||
|
|> map(Optional.init)
|
||||||
}
|
}
|
||||||
|
|
||||||
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
|
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
|
||||||
@ -359,7 +362,7 @@ public func PeerNameColorScreen(
|
|||||||
statePromise.get(),
|
statePromise.get(),
|
||||||
context.engine.stickers.availableReactions(),
|
context.engine.stickers.availableReactions(),
|
||||||
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)),
|
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)),
|
||||||
emojiContent
|
.single(nil) |> then(emojiContent)
|
||||||
)
|
)
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> map { presentationData, state, availableReactions, peer, emojiContent -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
|> map { presentationData, state, availableReactions, peer, emojiContent -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||||
@ -475,7 +478,7 @@ public func PeerNameColorScreen(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
emojiContent.inputInteractionHolder.inputInteraction = EmojiPagerContentComponent.InputInteraction(
|
emojiContent?.inputInteractionHolder.inputInteraction = EmojiPagerContentComponent.InputInteraction(
|
||||||
performItemAction: { _, item, _, _, _, _ in
|
performItemAction: { _, item, _, _, _, _ in
|
||||||
var selectedFileId: Int64?
|
var selectedFileId: Int64?
|
||||||
if let fileId = item.itemFile?.fileId.id {
|
if let fileId = item.itemFile?.fileId.id {
|
||||||
@ -565,7 +568,7 @@ public func PeerNameColorScreen(
|
|||||||
entries: entries,
|
entries: entries,
|
||||||
style: .blocks,
|
style: .blocks,
|
||||||
footerItem: footerItem,
|
footerItem: footerItem,
|
||||||
animateChanges: true
|
animateChanges: false
|
||||||
)
|
)
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
return (controllerState, (listState, arguments))
|
||||||
|
12
submodules/TelegramUI/Images.xcassets/Premium/BoostReplaceIcon.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Premium/BoostReplaceIcon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "replacedboost_30.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
273
submodules/TelegramUI/Images.xcassets/Premium/BoostReplaceIcon.imageset/replacedboost_30.pdf
vendored
Normal file
273
submodules/TelegramUI/Images.xcassets/Premium/BoostReplaceIcon.imageset/replacedboost_30.pdf
vendored
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 4.877197 15.157974 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
5.552186 8.359201 m
|
||||||
|
5.243867 8.359201 5.008486 8.634665 5.056572 8.939211 c
|
||||||
|
5.727019 13.185373 l
|
||||||
|
5.810456 13.713807 5.119398 13.988482 4.817303 13.546960 c
|
||||||
|
0.088512 6.635651 l
|
||||||
|
-0.139333 6.302646 0.099122 5.850563 0.502614 5.850563 c
|
||||||
|
2.581887 5.850563 l
|
||||||
|
2.890206 5.850563 3.125587 5.575099 3.077501 5.270554 c
|
||||||
|
2.407054 1.024391 l
|
||||||
|
2.323617 0.495958 3.014675 0.221282 3.316770 0.662805 c
|
||||||
|
8.045561 7.574114 l
|
||||||
|
8.273406 7.907119 8.034951 8.359201 7.631459 8.359201 c
|
||||||
|
5.552186 8.359201 l
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 16.877197 1.157974 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
5.552186 8.359201 m
|
||||||
|
5.243867 8.359201 5.008486 8.634665 5.056572 8.939211 c
|
||||||
|
5.727019 13.185373 l
|
||||||
|
5.810456 13.713807 5.119398 13.988482 4.817303 13.546960 c
|
||||||
|
0.088512 6.635651 l
|
||||||
|
-0.139333 6.302646 0.099122 5.850563 0.502614 5.850563 c
|
||||||
|
2.581887 5.850563 l
|
||||||
|
2.890206 5.850563 3.125587 5.575099 3.077501 5.270554 c
|
||||||
|
2.407054 1.024391 l
|
||||||
|
2.323617 0.495958 3.014675 0.221282 3.316770 0.662805 c
|
||||||
|
8.045561 7.574114 l
|
||||||
|
8.273406 7.907119 8.034951 8.359201 7.631459 8.359201 c
|
||||||
|
5.552186 8.359201 l
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 20.000000 15.177917 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
6.586899 4.235184 m
|
||||||
|
6.911034 4.559319 6.911034 5.084846 6.586899 5.408981 c
|
||||||
|
6.262764 5.733116 5.737236 5.733116 5.413101 5.408981 c
|
||||||
|
6.586899 4.235184 l
|
||||||
|
h
|
||||||
|
3.000000 1.822083 m
|
||||||
|
2.413101 1.235184 l
|
||||||
|
2.737236 0.911049 3.262764 0.911049 3.586899 1.235184 c
|
||||||
|
3.000000 1.822083 l
|
||||||
|
h
|
||||||
|
0.586899 5.408981 m
|
||||||
|
0.262763 5.733116 -0.262763 5.733116 -0.586899 5.408981 c
|
||||||
|
-0.911034 5.084846 -0.911034 4.559319 -0.586899 4.235184 c
|
||||||
|
0.586899 5.408981 l
|
||||||
|
h
|
||||||
|
5.413101 5.408981 m
|
||||||
|
2.413101 2.408981 l
|
||||||
|
3.586899 1.235184 l
|
||||||
|
6.586899 4.235184 l
|
||||||
|
5.413101 5.408981 l
|
||||||
|
h
|
||||||
|
3.586899 2.408981 m
|
||||||
|
0.586899 5.408981 l
|
||||||
|
-0.586899 4.235184 l
|
||||||
|
2.413101 1.235184 l
|
||||||
|
3.586899 2.408981 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 16.000000 15.339355 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.000000 10.490644 m
|
||||||
|
-0.458396 10.490644 -0.830000 10.119040 -0.830000 9.660645 c
|
||||||
|
-0.830000 9.202249 -0.458396 8.830645 0.000000 8.830645 c
|
||||||
|
0.000000 10.490644 l
|
||||||
|
h
|
||||||
|
6.170000 1.660645 m
|
||||||
|
6.170000 1.202249 6.541604 0.830645 7.000000 0.830645 c
|
||||||
|
7.458396 0.830645 7.830000 1.202249 7.830000 1.660645 c
|
||||||
|
6.170000 1.660645 l
|
||||||
|
h
|
||||||
|
6.727516 8.295621 m
|
||||||
|
7.467052 8.672433 l
|
||||||
|
6.727516 8.295621 l
|
||||||
|
h
|
||||||
|
0.000000 8.830645 m
|
||||||
|
3.000000 8.830645 l
|
||||||
|
3.000000 10.490644 l
|
||||||
|
0.000000 10.490644 l
|
||||||
|
0.000000 8.830645 l
|
||||||
|
h
|
||||||
|
6.170000 5.660645 m
|
||||||
|
6.170000 1.660645 l
|
||||||
|
7.830000 1.660645 l
|
||||||
|
7.830000 5.660645 l
|
||||||
|
6.170000 5.660645 l
|
||||||
|
h
|
||||||
|
3.000000 8.830645 m
|
||||||
|
3.713761 8.830645 4.199165 8.829999 4.574407 8.799340 c
|
||||||
|
4.939959 8.769474 5.127283 8.715313 5.258164 8.648625 c
|
||||||
|
6.011788 10.127696 l
|
||||||
|
5.607891 10.333492 5.177792 10.415573 4.709584 10.453828 c
|
||||||
|
4.251065 10.491290 3.686370 10.490644 3.000000 10.490644 c
|
||||||
|
3.000000 8.830645 l
|
||||||
|
h
|
||||||
|
7.830000 5.660645 m
|
||||||
|
7.830000 6.347014 7.830646 6.911709 7.793183 7.370228 c
|
||||||
|
7.754929 7.838436 7.672848 8.268535 7.467052 8.672433 c
|
||||||
|
5.987981 7.918809 l
|
||||||
|
6.054668 7.787928 6.108829 7.600603 6.138696 7.235051 c
|
||||||
|
6.169354 6.859809 6.170000 6.374406 6.170000 5.660645 c
|
||||||
|
7.830000 5.660645 l
|
||||||
|
h
|
||||||
|
5.258164 8.648625 m
|
||||||
|
5.572395 8.488517 5.827872 8.233040 5.987981 7.918809 c
|
||||||
|
7.467052 8.672433 l
|
||||||
|
7.147793 9.299013 6.638368 9.808438 6.011788 10.127696 c
|
||||||
|
5.258164 8.648625 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
-1.000000 -0.000000 -0.000000 -1.000000 10.000000 14.822083 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
6.586899 4.235184 m
|
||||||
|
6.911034 4.559319 6.911034 5.084846 6.586899 5.408981 c
|
||||||
|
6.262764 5.733116 5.737236 5.733116 5.413101 5.408981 c
|
||||||
|
6.586899 4.235184 l
|
||||||
|
h
|
||||||
|
3.000000 1.822083 m
|
||||||
|
2.413101 1.235184 l
|
||||||
|
2.737236 0.911049 3.262764 0.911049 3.586899 1.235184 c
|
||||||
|
3.000000 1.822083 l
|
||||||
|
h
|
||||||
|
0.586899 5.408981 m
|
||||||
|
0.262763 5.733116 -0.262763 5.733116 -0.586899 5.408981 c
|
||||||
|
-0.911034 5.084846 -0.911034 4.559319 -0.586899 4.235184 c
|
||||||
|
0.586899 5.408981 l
|
||||||
|
h
|
||||||
|
5.413101 5.408981 m
|
||||||
|
2.413101 2.408981 l
|
||||||
|
3.586899 1.235184 l
|
||||||
|
6.586899 4.235184 l
|
||||||
|
5.413101 5.408981 l
|
||||||
|
h
|
||||||
|
3.586899 2.408981 m
|
||||||
|
0.586899 5.408981 l
|
||||||
|
-0.586899 4.235184 l
|
||||||
|
2.413101 1.235184 l
|
||||||
|
3.586899 2.408981 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
q
|
||||||
|
-1.000000 -0.000000 -0.000000 -1.000000 14.000000 13.660645 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
0.000000 9.490644 m
|
||||||
|
-0.458396 9.490644 -0.830000 9.119040 -0.830000 8.660645 c
|
||||||
|
-0.830000 8.202249 -0.458396 7.830645 0.000000 7.830645 c
|
||||||
|
0.000000 9.490644 l
|
||||||
|
h
|
||||||
|
6.170000 1.660645 m
|
||||||
|
6.170000 1.202248 6.541604 0.830645 7.000000 0.830645 c
|
||||||
|
7.458396 0.830645 7.830000 1.202248 7.830000 1.660645 c
|
||||||
|
6.170000 1.660645 l
|
||||||
|
h
|
||||||
|
6.727516 7.295621 m
|
||||||
|
7.467052 7.672433 l
|
||||||
|
6.727516 7.295621 l
|
||||||
|
h
|
||||||
|
0.000000 7.830645 m
|
||||||
|
3.000000 7.830645 l
|
||||||
|
3.000000 9.490644 l
|
||||||
|
0.000000 9.490644 l
|
||||||
|
0.000000 7.830645 l
|
||||||
|
h
|
||||||
|
6.170000 4.660645 m
|
||||||
|
6.170000 1.660645 l
|
||||||
|
7.830000 1.660645 l
|
||||||
|
7.830000 4.660645 l
|
||||||
|
6.170000 4.660645 l
|
||||||
|
h
|
||||||
|
3.000000 7.830645 m
|
||||||
|
3.713761 7.830645 4.199165 7.829999 4.574407 7.799341 c
|
||||||
|
4.939959 7.769474 5.127283 7.715313 5.258164 7.648625 c
|
||||||
|
6.011788 9.127696 l
|
||||||
|
5.607891 9.333492 5.177792 9.415573 4.709584 9.453828 c
|
||||||
|
4.251065 9.491290 3.686370 9.490644 3.000000 9.490644 c
|
||||||
|
3.000000 7.830645 l
|
||||||
|
h
|
||||||
|
7.830000 4.660645 m
|
||||||
|
7.830000 5.347014 7.830646 5.911709 7.793183 6.370228 c
|
||||||
|
7.754929 6.838436 7.672848 7.268535 7.467052 7.672433 c
|
||||||
|
5.987981 6.918809 l
|
||||||
|
6.054668 6.787928 6.108829 6.600603 6.138696 6.235051 c
|
||||||
|
6.169354 5.859809 6.170000 5.374406 6.170000 4.660645 c
|
||||||
|
7.830000 4.660645 l
|
||||||
|
h
|
||||||
|
5.258164 7.648625 m
|
||||||
|
5.572395 7.488517 5.827872 7.233039 5.987981 6.918809 c
|
||||||
|
7.467052 7.672433 l
|
||||||
|
7.147793 8.299013 6.638368 8.808438 6.011788 9.127696 c
|
||||||
|
5.258164 7.648625 l
|
||||||
|
h
|
||||||
|
f
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
5530
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Pages 5 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000005620 00000 n
|
||||||
|
0000005643 00000 n
|
||||||
|
0000005816 00000 n
|
||||||
|
0000005890 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
5949
|
||||||
|
%%EOF
|
@ -1374,7 +1374,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
|||||||
let undoButtonFrame = CGRect(origin: CGPoint(x: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - rightInset - buttonTextSize.width - 8.0 - leftMargin * 2.0, y: 0.0), size: CGSize(width: layout.safeInsets.right + rightInset + buttonTextSize.width + 8.0 + leftMargin, height: contentHeight))
|
let undoButtonFrame = CGRect(origin: CGPoint(x: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - rightInset - buttonTextSize.width - 8.0 - leftMargin * 2.0, y: 0.0), size: CGSize(width: layout.safeInsets.right + rightInset + buttonTextSize.width + 8.0 + leftMargin, height: contentHeight))
|
||||||
self.undoButtonNode.frame = undoButtonFrame
|
self.undoButtonNode.frame = undoButtonFrame
|
||||||
|
|
||||||
self.buttonNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: undoButtonFrame.minX, height: contentHeight))
|
self.buttonNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: self.undoButtonNode.supernode == nil ? panelFrame.width : undoButtonFrame.minX, height: contentHeight))
|
||||||
|
|
||||||
var textContentHeight = textSize.height
|
var textContentHeight = textSize.height
|
||||||
var textOffset: CGFloat = 0.0
|
var textOffset: CGFloat = 0.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user