Various improvements

This commit is contained in:
Ilya Laktyushin
2023-10-23 19:04:00 +04:00
parent 09d2d0d716
commit bbbe204597
5 changed files with 162 additions and 101 deletions

View File

@@ -114,7 +114,7 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
private let scrollView: ScrollView private let scrollView: ScrollView
private let backgroundView: UIView private let backgroundView: UIView
private var effectView: UIVisualEffectView? private var effectView: UIVisualEffectView?
private let contentView: ComponentHostView<ChildEnvironmentType> private let contentView: ComponentView<ChildEnvironmentType>
private var isAnimatingOut: Bool = false private var isAnimatingOut: Bool = false
private var previousIsDisplaying: Bool = false private var previousIsDisplaying: Bool = false
@@ -139,7 +139,7 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
self.backgroundView.layer.cornerRadius = 12.0 self.backgroundView.layer.cornerRadius = 12.0
self.backgroundView.layer.masksToBounds = true self.backgroundView.layer.masksToBounds = true
self.contentView = ComponentHostView<ChildEnvironmentType>() self.contentView = ComponentView<ChildEnvironmentType>()
super.init(frame: frame) super.init(frame: frame)
@@ -147,7 +147,6 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
self.addSubview(self.dimView) self.addSubview(self.dimView)
self.scrollView.addSubview(self.backgroundView) self.scrollView.addSubview(self.backgroundView)
self.scrollView.addSubview(self.contentView)
self.addSubview(self.scrollView) self.addSubview(self.scrollView)
self.dimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimViewTapGesture(_:)))) self.dimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimViewTapGesture(_:))))
@@ -251,18 +250,21 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
self.isUserInteractionEnabled = false self.isUserInteractionEnabled = false
self.dimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) self.dimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
guard let contentView = self.contentView.view else {
return
}
if let initialVelocity = initialVelocity { if let initialVelocity = initialVelocity {
let transition = ContainedViewLayoutTransition.animated(duration: 0.35, curve: .customSpring(damping: 124.0, initialVelocity: initialVelocity)) let transition = ContainedViewLayoutTransition.animated(duration: 0.35, curve: .customSpring(damping: 124.0, initialVelocity: initialVelocity))
let contentOffset = (self.scrollView.contentOffset.y + self.scrollView.contentInset.top - self.scrollView.contentSize.height) * -1.0 let contentOffset = (self.scrollView.contentOffset.y + self.scrollView.contentInset.top - self.scrollView.contentSize.height) * -1.0
let dismissalOffset = self.scrollView.contentSize.height + abs(self.contentView.frame.minY) let dismissalOffset = self.scrollView.contentSize.height + abs(contentView.frame.minY)
let delta = dismissalOffset - contentOffset let delta = dismissalOffset - contentOffset
transition.updatePosition(layer: self.scrollView.layer, position: CGPoint(x: self.scrollView.center.x, y: self.scrollView.center.y + delta), completion: { _ in transition.updatePosition(layer: self.scrollView.layer, position: CGPoint(x: self.scrollView.center.x, y: self.scrollView.center.y + delta), completion: { _ in
completion() completion()
}) })
} else { } else {
self.scrollView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: self.scrollView.contentSize.height + abs(self.contentView.frame.minY)), duration: 0.25, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true, completion: { _ in self.scrollView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: self.scrollView.contentSize.height + abs(contentView.frame.minY)), duration: 0.25, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true, completion: { _ in
completion() completion()
}) })
} }
@@ -316,6 +318,7 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
containerSize = CGSize(width: availableSize.width, height: .greatestFiniteMagnitude) containerSize = CGSize(width: availableSize.width, height: .greatestFiniteMagnitude)
} }
self.contentView.parentState = state
let contentSize = self.contentView.update( let contentSize = self.contentView.update(
transition: transition, transition: transition,
component: component.content, component: component.content,
@@ -326,21 +329,25 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
) )
self.ignoreScrolling = true self.ignoreScrolling = true
if let contentView = self.contentView.view {
if contentView.superview == nil {
self.scrollView.addSubview(contentView)
}
if sheetEnvironment.isCentered { if sheetEnvironment.isCentered {
let y: CGFloat = floorToScreenPixels((availableSize.height - contentSize.height) / 2.0) let y: CGFloat = floorToScreenPixels((availableSize.height - contentSize.height) / 2.0)
transition.setFrame(view: self.contentView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - contentSize.width) / 2.0), y: -y), size: contentSize), completion: nil) transition.setFrame(view: contentView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - contentSize.width) / 2.0), y: -y), size: contentSize), completion: nil)
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - contentSize.width) / 2.0), y: -y), size: contentSize), completion: nil) transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - contentSize.width) / 2.0), y: -y), size: contentSize), completion: nil)
if let effectView = self.effectView { if let effectView = self.effectView {
transition.setFrame(view: effectView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - contentSize.width) / 2.0), y: -y), size: contentSize), completion: nil) transition.setFrame(view: effectView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - contentSize.width) / 2.0), y: -y), size: contentSize), completion: nil)
} }
} else { } else {
transition.setFrame(view: self.contentView, frame: CGRect(origin: .zero, size: contentSize), completion: nil) transition.setFrame(view: contentView, frame: CGRect(origin: .zero, size: contentSize), completion: nil)
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: .zero, size: CGSize(width: contentSize.width, height: contentSize.height + 1000.0)), completion: nil) transition.setFrame(view: self.backgroundView, frame: CGRect(origin: .zero, size: CGSize(width: contentSize.width, height: contentSize.height + 1000.0)), completion: nil)
if let effectView = self.effectView { if let effectView = self.effectView {
transition.setFrame(view: effectView, frame: CGRect(origin: .zero, size: CGSize(width: contentSize.width, height: contentSize.height + 1000.0)), completion: nil) transition.setFrame(view: effectView, frame: CGRect(origin: .zero, size: CGSize(width: contentSize.width, height: contentSize.height + 1000.0)), completion: nil)
} }
} }
}
transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(), size: availableSize), completion: nil) transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(), size: availableSize), completion: nil)
let previousContentSize = self.scrollView.contentSize let previousContentSize = self.scrollView.contentSize

View File

@@ -23,12 +23,17 @@ public func PremiumBoostScreen(
pushController: @escaping (ViewController) -> Void, pushController: @escaping (ViewController) -> Void,
dismissed: @escaping () -> Void dismissed: @escaping () -> Void
) { ) {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) let _ = (context.engine.data.get(
|> deliverOnMainQueue).startStandalone(next: { peer in TelegramEngine.EngineData.Item.Peer.Peer(id: peerId),
guard let peer, let status else { TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)
)
|> deliverOnMainQueue).startStandalone(next: { peer, accountPeer in
guard let peer, let accountPeer, let status else {
return return
} }
let isPremium = accountPeer.isPremium
var myBoostCount: Int32 = 0 var myBoostCount: Int32 = 0
var availableBoosts: [MyBoostStatus.Boost] = [] var availableBoosts: [MyBoostStatus.Boost] = []
var occupiedBoosts: [MyBoostStatus.Boost] = [] var occupiedBoosts: [MyBoostStatus.Boost] = []
@@ -94,6 +99,19 @@ public func PremiumBoostScreen(
}) })
dismissImpl?() dismissImpl?()
pushController(replaceController) pushController(replaceController)
} else {
if isPremium {
let controller = textAlertController(
sharedContext: context.sharedContext,
updatedPresentationData: nil,
title: "More Boosts Needed",
text: "To boost **\(peer.compactDisplayTitle)**, get more boosts by gifting **Telegram Premium** to a friend.",
actions: [
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})
],
parseMarkdown: true
)
presentController(controller)
} else { } else {
let controller = textAlertController( let controller = textAlertController(
sharedContext: context.sharedContext, sharedContext: context.sharedContext,
@@ -101,7 +119,7 @@ public func PremiumBoostScreen(
title: presentationData.strings.ChannelBoost_Error_PremiumNeededTitle, title: presentationData.strings.ChannelBoost_Error_PremiumNeededTitle,
text: presentationData.strings.ChannelBoost_Error_PremiumNeededText, text: presentationData.strings.ChannelBoost_Error_PremiumNeededText,
actions: [ actions: [
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}),
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Yes, action: { TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Yes, action: {
dismissImpl?() dismissImpl?()
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .channelBoost(peerId), forceDark: forceDark, dismissed: nil) let controller = context.sharedContext.makePremiumIntroController(context: context, source: .channelBoost(peerId), forceDark: forceDark, dismissed: nil)
@@ -112,6 +130,7 @@ public func PremiumBoostScreen(
) )
presentController(controller) presentController(controller)
} }
}
} else { } else {
dismissImpl?() dismissImpl?()
} }

View File

@@ -1159,7 +1159,7 @@ private final class LimitSheetContent: CombinedComponent {
state.myBoostCount = myBoostCount state.myBoostCount = myBoostCount
boostUpdated = true boostUpdated = true
} }
useAlternateText = myBoostCount > 0 useAlternateText = (myBoostCount % 2) != 0
iconName = "Premium/Boost" iconName = "Premium/Boost"
badgeText = "\(component.count)" badgeText = "\(component.count)"
@@ -1390,7 +1390,7 @@ private final class LimitSheetContent: CombinedComponent {
) )
var buttonOffset: CGFloat = 0.0 var buttonOffset: CGFloat = 0.0
var textOffset: CGFloat = 228.0 + topOffset var textOffset: CGFloat = 184.0 + topOffset
if case let .storiesChannelBoost(_, _, _, _, _, link, _) = component.subject { if case let .storiesChannelBoost(_, _, _, _, _, link, _) = component.subject {
if let link { if let link {
@@ -1421,8 +1421,6 @@ private final class LimitSheetContent: CombinedComponent {
context.add(linkButton context.add(linkButton
.position(CGPoint(x: linkFrame.midX, y: linkFrame.midY)) .position(CGPoint(x: linkFrame.midX, y: linkFrame.midY))
) )
} else {
textOffset -= 26.0
} }
} }
if isPremiumDisabled { if isPremiumDisabled {
@@ -1436,6 +1434,9 @@ private final class LimitSheetContent: CombinedComponent {
var textSize: CGSize var textSize: CGSize
if let textChild { if let textChild {
textSize = textChild.size textSize = textChild.size
textOffset += textSize.height / 2.0
context.add(textChild context.add(textChild
.position(CGPoint(x: context.availableSize.width / 2.0, y: textOffset)) .position(CGPoint(x: context.availableSize.width / 2.0, y: textOffset))
.appear(Transition.Appear({ _, view, transition in .appear(Transition.Appear({ _, view, transition in
@@ -1451,8 +1452,10 @@ private final class LimitSheetContent: CombinedComponent {
})) }))
) )
} else if let alternateTextChild { } else if let alternateTextChild {
textOffset += 9.0
textSize = alternateTextChild.size textSize = alternateTextChild.size
textOffset += textSize.height / 2.0
context.add(alternateTextChild context.add(alternateTextChild
.position(CGPoint(x: context.availableSize.width / 2.0, y: textOffset)) .position(CGPoint(x: context.availableSize.width / 2.0, y: textOffset))
.appear(Transition.Appear({ _, view, transition in .appear(Transition.Appear({ _, view, transition in
@@ -1559,7 +1562,7 @@ private final class LimitSheetContent: CombinedComponent {
.position(CGPoint(x: context.availableSize.width / 2.0, y: buttonFrame.maxY + 50.0 + giftText.size.height / 2.0)) .position(CGPoint(x: context.availableSize.width / 2.0, y: buttonFrame.maxY + 50.0 + giftText.size.height / 2.0))
) )
additionalContentHeight += giftText.size.height + 30.0 additionalContentHeight += giftText.size.height + 50.0
} }
contentSize = CGSize(width: context.availableSize.width, height: buttonFrame.maxY + additionalContentHeight + 5.0 + environment.safeInsets.bottom) contentSize = CGSize(width: context.availableSize.width, height: buttonFrame.maxY + additionalContentHeight + 5.0 + environment.safeInsets.bottom)

View File

@@ -27,13 +27,15 @@ private final class ReplaceBoostScreenComponent: CombinedComponent {
let context: AccountContext let context: AccountContext
let peerId: EnginePeer.Id let peerId: EnginePeer.Id
let myBoostStatus: MyBoostStatus let myBoostStatus: MyBoostStatus
let initiallySelectedSlot: Int32?
let selectedSlotsUpdated: ([Int32]) -> Void let selectedSlotsUpdated: ([Int32]) -> Void
let presentController: (ViewController) -> Void let presentController: (ViewController) -> Void
init(context: AccountContext, peerId: EnginePeer.Id, myBoostStatus: MyBoostStatus, selectedSlotsUpdated: @escaping ([Int32]) -> Void, presentController: @escaping (ViewController) -> Void) { init(context: AccountContext, peerId: EnginePeer.Id, myBoostStatus: MyBoostStatus, initiallySelectedSlot: Int32?, selectedSlotsUpdated: @escaping ([Int32]) -> Void, presentController: @escaping (ViewController) -> Void) {
self.context = context self.context = context
self.peerId = peerId self.peerId = peerId
self.myBoostStatus = myBoostStatus self.myBoostStatus = myBoostStatus
self.initiallySelectedSlot = initiallySelectedSlot
self.selectedSlotsUpdated = selectedSlotsUpdated self.selectedSlotsUpdated = selectedSlotsUpdated
self.presentController = presentController self.presentController = presentController
} }
@@ -62,13 +64,17 @@ private final class ReplaceBoostScreenComponent: CombinedComponent {
var cachedCloseImage: (UIImage, PresentationTheme)? var cachedCloseImage: (UIImage, PresentationTheme)?
init(context: AccountContext, peerId: EnginePeer.Id) { init(context: AccountContext, peerId: EnginePeer.Id, initiallySelectedSlot: Int32?) {
self.context = context self.context = context
self.currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) self.currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
super.init() super.init()
if let initiallySelectedSlot {
self.selectedSlots.append(initiallySelectedSlot)
}
self.disposable.set((context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) self.disposable.set((context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> deliverOnMainQueue).startStrict(next: { [weak self] peer in |> deliverOnMainQueue).startStrict(next: { [weak self] peer in
guard let self else { guard let self else {
@@ -94,7 +100,7 @@ private final class ReplaceBoostScreenComponent: CombinedComponent {
} }
func makeState() -> State { func makeState() -> State {
return State(context: self.context, peerId: self.peerId) return State(context: self.context, peerId: self.peerId, initiallySelectedSlot: self.initiallySelectedSlot)
} }
static var body: Body { static var body: Body {
@@ -180,6 +186,8 @@ private final class ReplaceBoostScreenComponent: CombinedComponent {
.position(CGPoint(x: availableSize.width / 2.0, y: 172.0)) .position(CGPoint(x: availableSize.width / 2.0, y: 172.0))
) )
let hasSelection = occupiedBoosts.count > 1
let selectedSlotsUpdated = context.component.selectedSlotsUpdated let selectedSlotsUpdated = context.component.selectedSlotsUpdated
let presentController = context.component.presentController let presentController = context.component.presentController
for i in 0 ..< occupiedBoosts.count { for i in 0 ..< occupiedBoosts.count {
@@ -193,11 +201,11 @@ private final class ReplaceBoostScreenComponent: CombinedComponent {
if let cooldownUntil = boost.cooldownUntil, cooldownUntil > state.currentTime { if let cooldownUntil = boost.cooldownUntil, cooldownUntil > state.currentTime {
let duration = cooldownUntil - state.currentTime let duration = cooldownUntil - state.currentTime
let durationValue = stringForDuration(duration, position: nil) let durationValue = stringForDuration(duration, position: nil)
subtitle = "available in \(durationValue)" subtitle = "Available in \(durationValue)"
isEnabled = false isEnabled = false
} else { } else {
let expiresValue = stringForDate(timestamp: boost.expires, strings: strings) let expiresValue = stringForDate(timestamp: boost.expires, strings: strings)
subtitle = "boost expires on \(expiresValue)" subtitle = "Boost expires on \(expiresValue)"
} }
let accountContext = context.component.context let accountContext = context.component.context
@@ -216,12 +224,12 @@ private final class ReplaceBoostScreenComponent: CombinedComponent {
subtitle: subtitle, subtitle: subtitle,
subtitleAccessory: .none, subtitleAccessory: .none,
presence: nil, presence: nil,
selectionState: .editing(isSelected: state.selectedSlots.contains(boost.slot), isTinted: false), selectionState: hasSelection ? .editing(isSelected: state.selectedSlots.contains(boost.slot), isTinted: false) : .none,
selectionPosition: .right, selectionPosition: .right,
isEnabled: isEnabled, isEnabled: isEnabled,
hasNext: i != occupiedBoosts.count - 1, hasNext: i != occupiedBoosts.count - 1,
action: { [weak state] _ in action: { [weak state] _ in
guard let state else { guard let state, hasSelection else {
return return
} }
if isEnabled { if isEnabled {
@@ -433,6 +441,35 @@ public class ReplaceBoostScreen: ViewController {
effectiveExpanded = true effectiveExpanded = true
} }
let environment = ViewControllerComponentContainer.Environment(
statusBarHeight: 0.0,
navigationHeight: navigationHeight,
safeInsets: UIEdgeInsets(top: layout.intrinsicInsets.top + layout.safeInsets.top, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom + layout.safeInsets.bottom, right: layout.safeInsets.right),
inputHeight: layout.inputHeight ?? 0.0,
metrics: layout.metrics,
deviceMetrics: layout.deviceMetrics,
isVisible: self.currentIsVisible,
theme: self.presentationData.theme,
strings: self.presentationData.strings,
dateTimeFormat: self.presentationData.dateTimeFormat,
controller: { [weak self] in
return self?.controller
}
)
let contentSize = self.hostView.update(
transition: transition,
component: self.component,
environment: {
environment
},
forceUpdate: true,
containerSize: CGSize(width: layout.size.width, height: 10000.0)
)
// contentSize.height = max(layout.size.height - navigationHeight, contentSize.height)
transition.setFrame(view: self.hostView, frame: CGRect(origin: CGPoint(), size: contentSize), completion: nil)
self.scrollView.contentSize = contentSize
let isLandscape = layout.orientation == .landscape let isLandscape = layout.orientation == .landscape
let edgeTopInset = isLandscape ? 0.0 : self.defaultTopInset let edgeTopInset = isLandscape ? 0.0 : self.defaultTopInset
let topInset: CGFloat let topInset: CGFloat
@@ -500,35 +537,6 @@ public class ReplaceBoostScreen: ViewController {
transition.setFrame(view: self.containerView, frame: clipFrame) transition.setFrame(view: self.containerView, frame: clipFrame)
transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(), size: clipFrame.size), completion: nil) transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(), size: clipFrame.size), completion: nil)
let environment = ViewControllerComponentContainer.Environment(
statusBarHeight: 0.0,
navigationHeight: navigationHeight,
safeInsets: UIEdgeInsets(top: layout.intrinsicInsets.top + layout.safeInsets.top, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom + layout.safeInsets.bottom, right: layout.safeInsets.right),
inputHeight: layout.inputHeight ?? 0.0,
metrics: layout.metrics,
deviceMetrics: layout.deviceMetrics,
isVisible: self.currentIsVisible,
theme: self.presentationData.theme,
strings: self.presentationData.strings,
dateTimeFormat: self.presentationData.dateTimeFormat,
controller: { [weak self] in
return self?.controller
}
)
var contentSize = self.hostView.update(
transition: transition,
component: self.component,
environment: {
environment
},
forceUpdate: true,
containerSize: CGSize(width: clipFrame.size.width, height: 10000.0)
)
contentSize.height = max(layout.size.height - navigationHeight, contentSize.height)
transition.setFrame(view: self.hostView, frame: CGRect(origin: CGPoint(), size: contentSize), completion: nil)
self.scrollView.contentSize = contentSize
let footerInsets = UIEdgeInsets(top: 0.0, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.safeInsets.right) let footerInsets = UIEdgeInsets(top: 0.0, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.safeInsets.right)
transition.setFrame(view: self.footerView, frame: CGRect(origin: CGPoint(x: 0.0, y: -topInset), size: layout.size)) transition.setFrame(view: self.footerView, frame: CGRect(origin: CGPoint(x: 0.0, y: -topInset), size: layout.size))
@@ -564,7 +572,11 @@ public class ReplaceBoostScreen: ViewController {
if layout.size.width <= 320.0 { if layout.size.width <= 320.0 {
factor = 0.15 factor = 0.15
} }
if self.scrollView.contentSize.height > 0.0 && self.scrollView.contentSize.height < layout.size.height / 2.0 {
return layout.size.height - self.scrollView.contentSize.height - layout.intrinsicInsets.bottom - 154.0
} else {
return floor(max(layout.size.width, layout.size.height) * factor) return floor(max(layout.size.width, layout.size.height) * factor)
}
} else { } else {
return 210.0 return 210.0
} }
@@ -590,7 +602,7 @@ public class ReplaceBoostScreen: ViewController {
} }
let isLandscape = layout.orientation == .landscape let isLandscape = layout.orientation == .landscape
let edgeTopInset = isLandscape ? 0.0 : defaultTopInset let edgeTopInset = isLandscape ? 0.0 : self.defaultTopInset
switch recognizer.state { switch recognizer.state {
case .began: case .began:
@@ -783,15 +795,23 @@ public class ReplaceBoostScreen: ViewController {
public convenience init(context: AccountContext, peerId: EnginePeer.Id, myBoostStatus: MyBoostStatus, replaceBoosts: @escaping ([Int32]) -> Void) { public convenience init(context: AccountContext, peerId: EnginePeer.Id, myBoostStatus: MyBoostStatus, replaceBoosts: @escaping ([Int32]) -> Void) {
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var initiallySelectedSlot: Int32?
let occupiedBoosts = myBoostStatus.boosts.filter { $0.peer?.id != peerId && $0.peer != nil }.sorted { lhs, rhs in
return lhs.date < rhs.date
}
if occupiedBoosts.count == 1, let boost = occupiedBoosts.first {
initiallySelectedSlot = boost.slot
}
var selectedSlotsUpdatedImpl: (([Int32]) -> Void)? var selectedSlotsUpdatedImpl: (([Int32]) -> Void)?
var presentControllerImpl: ((ViewController) -> Void)? var presentControllerImpl: ((ViewController) -> Void)?
self.init(context: context, component: ReplaceBoostScreenComponent(context: context, peerId: peerId, myBoostStatus: myBoostStatus, selectedSlotsUpdated: { slots in self.init(context: context, component: ReplaceBoostScreenComponent(context: context, peerId: peerId, myBoostStatus: myBoostStatus, initiallySelectedSlot: initiallySelectedSlot, selectedSlotsUpdated: { slots in
selectedSlotsUpdatedImpl?(slots) selectedSlotsUpdatedImpl?(slots)
}, presentController: { c in }, presentController: { c in
presentControllerImpl?(c) presentControllerImpl?(c)
})) }))
self.title = "Reassign Boost" self.title = "Reassign Boosts"
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Close, style: .plain, target: self, action: #selector(self.cancelPressed)) self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Close, style: .plain, target: self, action: #selector(self.cancelPressed))
@@ -806,6 +826,10 @@ public class ReplaceBoostScreen: ViewController {
} }
self.replaceBoosts = replaceBoosts self.replaceBoosts = replaceBoosts
if let initiallySelectedSlot {
self.node.selectedSlots = [initiallySelectedSlot]
}
} }
private init<C: Component>(context: AccountContext, component: C, theme: PresentationTheme? = nil) where C.EnvironmentType == ViewControllerComponentContainer.Environment { private init<C: Component>(context: AccountContext, component: C, theme: PresentationTheme? = nil) where C.EnvironmentType == ViewControllerComponentContainer.Environment {
@@ -989,6 +1013,9 @@ private final class FooterView: UIView {
self.addSubview(view) self.addSubview(view)
} }
view.frame = CGRect(origin: CGPoint(x: insets.left + buttonInset, y: panelFrame.minY + inset), size: buttonSize) view.frame = CGRect(origin: CGPoint(x: insets.left + buttonInset, y: panelFrame.minY + inset), size: buttonSize)
buttonTransition.setAlpha(view: view, alpha: count > 0 ? 1.0 : 0.3)
view.isUserInteractionEnabled = count > 0
} }
self.backgroundNode.frame = panelFrame self.backgroundNode.frame = panelFrame

View File

@@ -978,13 +978,28 @@ public final class WebAppController: ViewController, AttachmentContainable {
} }
case "web_app_read_text_from_clipboard": case "web_app_read_text_from_clipboard":
if let json = json, let requestId = json["req_id"] as? String { if let json = json, let requestId = json["req_id"] as? String {
let botId = controller.botId
let isAttachMenu = controller.url == nil
let _ = (self.context.engine.messages.attachMenuBots()
|> take(1)
|> deliverOnMainQueue).startStandalone(next: { [weak self] attachMenuBots in
guard let self else {
return
}
let currentTimestamp = CACurrentMediaTime() let currentTimestamp = CACurrentMediaTime()
var fillData = false var fillData = false
if let lastTouchTimestamp = self.webView?.lastTouchTimestamp, currentTimestamp < lastTouchTimestamp + 10.0, self.controller?.url == nil {
let attachMenuBot = attachMenuBots.first(where: { $0.peer.id == botId && !$0.flags.contains(.notActivated) })
if isAttachMenu || attachMenuBot != nil {
if let lastTouchTimestamp = self.webView?.lastTouchTimestamp, currentTimestamp < lastTouchTimestamp + 10.0 {
self.webView?.lastTouchTimestamp = nil self.webView?.lastTouchTimestamp = nil
fillData = true fillData = true
} }
}
self.sendClipboardTextEvent(requestId: requestId, fillData: fillData) self.sendClipboardTextEvent(requestId: requestId, fillData: fillData)
})
} }
case "web_app_request_write_access": case "web_app_request_write_access":
self.requestWriteAccess() self.requestWriteAccess()
@@ -1499,16 +1514,6 @@ public final class WebAppController: ViewController, AttachmentContainable {
let attachMenuBot = attachMenuBots.first(where: { $0.peer.id == botId && !$0.flags.contains(.notActivated) }) let attachMenuBot = attachMenuBots.first(where: { $0.peer.id == botId && !$0.flags.contains(.notActivated) })
// if url == nil {
// if forceHasSettings {
// hasSettings = true
// } else {
// hasSettings = attachMenuBot?.flags.contains(.hasSettings) == true
// }
// } else {
// hasSettings = forceHasSettings
// }
if hasSettings { if hasSettings {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.WebApp_Settings, icon: { theme in items.append(.action(ContextMenuActionItem(text: presentationData.strings.WebApp_Settings, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Settings"), color: theme.contextMenu.primaryColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Settings"), color: theme.contextMenu.primaryColor)