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 backgroundView: UIView
private var effectView: UIVisualEffectView?
private let contentView: ComponentHostView<ChildEnvironmentType>
private let contentView: ComponentView<ChildEnvironmentType>
private var isAnimatingOut: 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.masksToBounds = true
self.contentView = ComponentHostView<ChildEnvironmentType>()
self.contentView = ComponentView<ChildEnvironmentType>()
super.init(frame: frame)
@@ -147,7 +147,6 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
self.addSubview(self.dimView)
self.scrollView.addSubview(self.backgroundView)
self.scrollView.addSubview(self.contentView)
self.addSubview(self.scrollView)
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.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 {
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 dismissalOffset = self.scrollView.contentSize.height + abs(self.contentView.frame.minY)
let dismissalOffset = self.scrollView.contentSize.height + abs(contentView.frame.minY)
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
completion()
})
} 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()
})
}
@@ -316,6 +318,7 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
containerSize = CGSize(width: availableSize.width, height: .greatestFiniteMagnitude)
}
self.contentView.parentState = state
let contentSize = self.contentView.update(
transition: transition,
component: component.content,
@@ -326,21 +329,25 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
)
self.ignoreScrolling = true
if let contentView = self.contentView.view {
if contentView.superview == nil {
self.scrollView.addSubview(contentView)
}
if sheetEnvironment.isCentered {
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)
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)
}
} 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)
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: self.scrollView, frame: CGRect(origin: CGPoint(), size: availableSize), completion: nil)
let previousContentSize = self.scrollView.contentSize

View File

@@ -23,12 +23,17 @@ public func PremiumBoostScreen(
pushController: @escaping (ViewController) -> Void,
dismissed: @escaping () -> Void
) {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> deliverOnMainQueue).startStandalone(next: { peer in
guard let peer, let status else {
let _ = (context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId),
TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)
)
|> deliverOnMainQueue).startStandalone(next: { peer, accountPeer in
guard let peer, let accountPeer, let status else {
return
}
let isPremium = accountPeer.isPremium
var myBoostCount: Int32 = 0
var availableBoosts: [MyBoostStatus.Boost] = []
var occupiedBoosts: [MyBoostStatus.Boost] = []
@@ -94,6 +99,19 @@ public func PremiumBoostScreen(
})
dismissImpl?()
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 {
let controller = textAlertController(
sharedContext: context.sharedContext,
@@ -101,7 +119,7 @@ public func PremiumBoostScreen(
title: presentationData.strings.ChannelBoost_Error_PremiumNeededTitle,
text: presentationData.strings.ChannelBoost_Error_PremiumNeededText,
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: {
dismissImpl?()
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .channelBoost(peerId), forceDark: forceDark, dismissed: nil)
@@ -112,6 +130,7 @@ public func PremiumBoostScreen(
)
presentController(controller)
}
}
} else {
dismissImpl?()
}

View File

@@ -1159,7 +1159,7 @@ private final class LimitSheetContent: CombinedComponent {
state.myBoostCount = myBoostCount
boostUpdated = true
}
useAlternateText = myBoostCount > 0
useAlternateText = (myBoostCount % 2) != 0
iconName = "Premium/Boost"
badgeText = "\(component.count)"
@@ -1390,7 +1390,7 @@ private final class LimitSheetContent: CombinedComponent {
)
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 let link {
@@ -1421,8 +1421,6 @@ private final class LimitSheetContent: CombinedComponent {
context.add(linkButton
.position(CGPoint(x: linkFrame.midX, y: linkFrame.midY))
)
} else {
textOffset -= 26.0
}
}
if isPremiumDisabled {
@@ -1436,6 +1434,9 @@ private final class LimitSheetContent: CombinedComponent {
var textSize: CGSize
if let textChild {
textSize = textChild.size
textOffset += textSize.height / 2.0
context.add(textChild
.position(CGPoint(x: context.availableSize.width / 2.0, y: textOffset))
.appear(Transition.Appear({ _, view, transition in
@@ -1451,8 +1452,10 @@ private final class LimitSheetContent: CombinedComponent {
}))
)
} else if let alternateTextChild {
textOffset += 9.0
textSize = alternateTextChild.size
textOffset += textSize.height / 2.0
context.add(alternateTextChild
.position(CGPoint(x: context.availableSize.width / 2.0, y: textOffset))
.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))
)
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)

View File

@@ -27,13 +27,15 @@ private final class ReplaceBoostScreenComponent: CombinedComponent {
let context: AccountContext
let peerId: EnginePeer.Id
let myBoostStatus: MyBoostStatus
let initiallySelectedSlot: Int32?
let selectedSlotsUpdated: ([Int32]) -> 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.peerId = peerId
self.myBoostStatus = myBoostStatus
self.initiallySelectedSlot = initiallySelectedSlot
self.selectedSlotsUpdated = selectedSlotsUpdated
self.presentController = presentController
}
@@ -62,13 +64,17 @@ private final class ReplaceBoostScreenComponent: CombinedComponent {
var cachedCloseImage: (UIImage, PresentationTheme)?
init(context: AccountContext, peerId: EnginePeer.Id) {
init(context: AccountContext, peerId: EnginePeer.Id, initiallySelectedSlot: Int32?) {
self.context = context
self.currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
super.init()
if let initiallySelectedSlot {
self.selectedSlots.append(initiallySelectedSlot)
}
self.disposable.set((context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|> deliverOnMainQueue).startStrict(next: { [weak self] peer in
guard let self else {
@@ -94,7 +100,7 @@ private final class ReplaceBoostScreenComponent: CombinedComponent {
}
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 {
@@ -180,6 +186,8 @@ private final class ReplaceBoostScreenComponent: CombinedComponent {
.position(CGPoint(x: availableSize.width / 2.0, y: 172.0))
)
let hasSelection = occupiedBoosts.count > 1
let selectedSlotsUpdated = context.component.selectedSlotsUpdated
let presentController = context.component.presentController
for i in 0 ..< occupiedBoosts.count {
@@ -193,11 +201,11 @@ private final class ReplaceBoostScreenComponent: CombinedComponent {
if let cooldownUntil = boost.cooldownUntil, cooldownUntil > state.currentTime {
let duration = cooldownUntil - state.currentTime
let durationValue = stringForDuration(duration, position: nil)
subtitle = "available in \(durationValue)"
subtitle = "Available in \(durationValue)"
isEnabled = false
} else {
let expiresValue = stringForDate(timestamp: boost.expires, strings: strings)
subtitle = "boost expires on \(expiresValue)"
subtitle = "Boost expires on \(expiresValue)"
}
let accountContext = context.component.context
@@ -216,12 +224,12 @@ private final class ReplaceBoostScreenComponent: CombinedComponent {
subtitle: subtitle,
subtitleAccessory: .none,
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,
isEnabled: isEnabled,
hasNext: i != occupiedBoosts.count - 1,
action: { [weak state] _ in
guard let state else {
guard let state, hasSelection else {
return
}
if isEnabled {
@@ -433,6 +441,35 @@ public class ReplaceBoostScreen: ViewController {
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 edgeTopInset = isLandscape ? 0.0 : self.defaultTopInset
let topInset: CGFloat
@@ -500,35 +537,6 @@ public class ReplaceBoostScreen: ViewController {
transition.setFrame(view: self.containerView, frame: clipFrame)
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)
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 {
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)
}
} else {
return 210.0
}
@@ -590,7 +602,7 @@ public class ReplaceBoostScreen: ViewController {
}
let isLandscape = layout.orientation == .landscape
let edgeTopInset = isLandscape ? 0.0 : defaultTopInset
let edgeTopInset = isLandscape ? 0.0 : self.defaultTopInset
switch recognizer.state {
case .began:
@@ -783,15 +795,23 @@ public class ReplaceBoostScreen: ViewController {
public convenience init(context: AccountContext, peerId: EnginePeer.Id, myBoostStatus: MyBoostStatus, replaceBoosts: @escaping ([Int32]) -> Void) {
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 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)
}, presentController: { c in
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))
@@ -806,6 +826,10 @@ public class ReplaceBoostScreen: ViewController {
}
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 {
@@ -989,6 +1013,9 @@ private final class FooterView: UIView {
self.addSubview(view)
}
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

View File

@@ -978,13 +978,28 @@ public final class WebAppController: ViewController, AttachmentContainable {
}
case "web_app_read_text_from_clipboard":
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()
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
fillData = true
}
}
self.sendClipboardTextEvent(requestId: requestId, fillData: fillData)
})
}
case "web_app_request_write_access":
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) })
// if url == nil {
// if forceHasSettings {
// hasSettings = true
// } else {
// hasSettings = attachMenuBot?.flags.contains(.hasSettings) == true
// }
// } else {
// hasSettings = forceHasSettings
// }
if hasSettings {
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)