mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Various improvements
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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?()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user