Move limits page to horizontal scroll

This commit is contained in:
Ilya Laktyushin 2022-10-25 19:56:38 +03:00
parent 0ffcbf0b06
commit f8c5bf2a6b
7 changed files with 878 additions and 291 deletions

View File

@ -17,7 +17,7 @@ import SolidRoundedButtonComponent
import Markdown
import TelegramUIPreferences
private final class GradientBackgroundComponent: Component {
final class GradientBackgroundComponent: Component {
public let colors: [UIColor]
public init(
@ -153,7 +153,7 @@ final class DemoPageEnvironment: Equatable {
}
}
private final class PageComponent<ChildEnvironment: Equatable>: CombinedComponent {
final class PageComponent<ChildEnvironment: Equatable>: CombinedComponent {
typealias EnvironmentType = ChildEnvironment
private let content: AnyComponent<ChildEnvironment>
@ -263,7 +263,7 @@ private final class PageComponent<ChildEnvironment: Equatable>: CombinedComponen
}
}
private final class DemoPagerComponent: Component {
final class DemoPagerComponent: Component {
public final class Item: Equatable {
public let content: AnyComponentWithIdentity<DemoPageEnvironment>
@ -282,40 +282,29 @@ private final class DemoPagerComponent: Component {
let items: [Item]
let index: Int
let activeColor: UIColor
let inactiveColor: UIColor
let updated: (CGFloat, Int) -> Void
public init(
items: [Item],
index: Int = 0,
activeColor: UIColor,
inactiveColor: UIColor
updated: @escaping (CGFloat, Int) -> Void
) {
self.items = items
self.index = index
self.activeColor = activeColor
self.inactiveColor = inactiveColor
self.updated = updated
}
public static func ==(lhs: DemoPagerComponent, rhs: DemoPagerComponent) -> Bool {
if lhs.items != rhs.items {
return false
}
if !lhs.activeColor.isEqual(rhs.activeColor) {
return false
}
if !lhs.inactiveColor.isEqual(rhs.inactiveColor) {
return false
}
return true
}
fileprivate final class View: UIView, UIScrollViewDelegate {
final class View: UIView, UIScrollViewDelegate {
private let scrollView: UIScrollView
private var itemViews: [AnyHashable: ComponentHostView<DemoPageEnvironment>] = [:]
private let pageIndicatorView: ComponentHostView<Empty>
private var component: DemoPagerComponent?
override init(frame: CGRect) {
@ -327,15 +316,11 @@ private final class DemoPagerComponent: Component {
self.scrollView.bounces = false
self.scrollView.layer.cornerRadius = 10.0
self.pageIndicatorView = ComponentHostView<Empty>()
self.pageIndicatorView.isUserInteractionEnabled = false
super.init(frame: frame)
self.scrollView.delegate = self
self.addSubview(self.scrollView)
self.addSubview(self.pageIndicatorView)
}
required init?(coder: NSCoder) {
@ -350,6 +335,7 @@ private final class DemoPagerComponent: Component {
self.ignoreContentOffsetChange = true
let _ = self.update(component: component, availableSize: self.bounds.size, transition: .immediate)
component.updated(self.scrollView.contentOffset.x / (self.scrollView.contentSize.width - self.scrollView.frame.width), component.items.count)
self.ignoreContentOffsetChange = false
}
@ -369,6 +355,7 @@ private final class DemoPagerComponent: Component {
if firstTime {
self.scrollView.contentOffset = CGPoint(x: CGFloat(component.index) * availableSize.width, y: 0.0)
component.updated(self.scrollView.contentOffset.x / (self.scrollView.contentSize.width - self.scrollView.frame.width), component.items.count)
}
let viewportCenter = self.scrollView.contentOffset.x + availableSize.width * 0.5
@ -398,7 +385,6 @@ private final class DemoPagerComponent: Component {
itemView = ComponentHostView<DemoPageEnvironment>()
self.itemViews[item.content.id] = itemView
if item.content.id == (PremiumDemoScreen.Subject.fasterDownload as AnyHashable) {
self.scrollView.insertSubview(itemView, at: 0)
} else {
@ -430,33 +416,15 @@ private final class DemoPagerComponent: Component {
self.component = component
if component.items.count > 1 {
let pageIndicatorComponent = PageIndicatorComponent(
pageCount: component.items.count,
position: self.scrollView.contentOffset.x / (self.scrollView.contentSize.width - availableSize.width),
inactiveColor: component.inactiveColor,
activeColor: component.activeColor
)
let indicatorSize = self.pageIndicatorView.update(
transition: .immediate,
component: AnyComponent(
pageIndicatorComponent
),
environment: {},
containerSize: availableSize
)
self.pageIndicatorView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - indicatorSize.width) / 2.0), y: availableSize.height - indicatorSize.height - 11.0), size: indicatorSize)
}
return availableSize
}
}
public func makeView() -> View {
func makeView() -> View {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}
@ -949,8 +917,7 @@ private final class DemoSheetContent: CombinedComponent {
component: DemoPagerComponent(
items: items,
index: index,
activeColor: UIColor(rgb: 0x7169ff),
inactiveColor: theme.list.disclosureArrowColor
updated: { _, _ in }
),
availableSize: CGSize(width: context.availableSize.width, height: context.availableSize.width + 154.0),
transition: context.transition
@ -1177,6 +1144,7 @@ private final class DemoSheetComponent: CombinedComponent {
public class PremiumDemoScreen: ViewControllerComponentContainer {
public enum Subject {
case doubleLimits
case moreUpload
case fasterDownload
case voiceToText

View File

@ -361,21 +361,7 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
var demoSubject: PremiumDemoScreen.Subject
switch perk {
case .doubleLimits:
var dismissImpl: (() -> Void)?
let controller = PremimLimitsListScreen(context: accountContext, buttonText: strings.Premium_Gift_GiftSubscription(state?.price ?? "").string, isPremium: false)
controller.action = {
dismissImpl?()
buy()
}
controller.disposed = {
// updateIsFocused(false)
}
present(controller)
dismissImpl = { [weak controller] in
controller?.dismiss(animated: true, completion: nil)
}
// updateIsFocused(true)
return
demoSubject = .doubleLimits
case .moreUpload:
demoSubject = .moreUpload
case .fasterDownload:
@ -402,20 +388,34 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
demoSubject = .emojiStatus
}
let controller = PremiumDemoScreen(
context: accountContext,
subject: demoSubject,
source: .gift(state?.price),
order: state?.configuration.perks,
action: {
var dismissImpl: (() -> Void)?
let controller = PremiumLimitsListScreen(context: accountContext, subject: demoSubject, source: .gift(state?.price), order: state?.configuration.perks, buttonText: strings.Premium_Gift_GiftSubscription(state?.price ?? "").string, isPremium: false)
controller.action = {
dismissImpl?()
buy()
}
)
controller.disposed = {
// updateIsFocused(false)
}
present(controller)
// updateIsFocused(true)
dismissImpl = { [weak controller] in
controller?.dismiss(animated: true, completion: nil)
}
// let controller = PremiumDemoScreen(
// context: accountContext,
// subject: demoSubject,
// source: .gift(state?.price),
// order: state?.configuration.perks,
// action: {
// buy()
// }
// )
// controller.disposed = {
//// updateIsFocused(false)
// }
// present(controller)
//// updateIsFocused(true)
addAppLogEvent(postbox: accountContext.account.postbox, type: "premium.promo_screen_tap", data: ["item": perk.identifier])
}

View File

@ -1556,25 +1556,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
var demoSubject: PremiumDemoScreen.Subject
switch perk {
case .doubleLimits:
let isPremium = state?.isPremium == true
var dismissImpl: (() -> Void)?
let controller = PremimLimitsListScreen(context: accountContext, buttonText: isPremium ? strings.Common_OK : (state?.isAnnual == true ? strings.Premium_SubscribeForAnnual(state?.price ?? "").string : strings.Premium_SubscribeFor(state?.price ?? "").string), isPremium: isPremium)
controller.action = { [weak state] in
dismissImpl?()
if state?.isPremium == false {
buy()
}
}
controller.disposed = {
updateIsFocused(false)
}
present(controller)
dismissImpl = { [weak controller] in
controller?.dismiss(animated: true, completion: nil)
}
updateIsFocused(true)
return
demoSubject = .doubleLimits
case .moreUpload:
demoSubject = .moreUpload
case .fasterDownload:
@ -1601,23 +1583,42 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
demoSubject = .emojiStatus
}
let controller = PremiumDemoScreen(
context: accountContext,
subject: demoSubject,
source: .intro(state?.price),
order: state?.configuration.perks,
action: {
let isPremium = state?.isPremium == true
var dismissImpl: (() -> Void)?
let controller = PremiumLimitsListScreen(context: accountContext, subject: demoSubject, source: .intro(state?.price), order: state?.configuration.perks, buttonText: isPremium ? strings.Common_OK : (state?.isAnnual == true ? strings.Premium_SubscribeForAnnual(state?.price ?? "").string : strings.Premium_SubscribeFor(state?.price ?? "").string), isPremium: isPremium)
controller.action = { [weak state] in
dismissImpl?()
if state?.isPremium == false {
buy()
}
}
)
controller.disposed = {
updateIsFocused(false)
}
present(controller)
dismissImpl = { [weak controller] in
controller?.dismiss(animated: true, completion: nil)
}
updateIsFocused(true)
// let controller = PremiumDemoScreen(
// context: accountContext,
// subject: demoSubject,
// source: .intro(state?.price),
// order: state?.configuration.perks,
// action: {
// if state?.isPremium == false {
// buy()
// }
// }
// )
// controller.disposed = {
// updateIsFocused(false)
// }
// present(controller)
// updateIsFocused(true)
addAppLogEvent(postbox: accountContext.account.postbox, type: "premium.promo_screen_tap", data: ["item": perk.identifier])
}
))

File diff suppressed because it is too large Load Diff

View File

@ -20,23 +20,26 @@ final class ScrollChildEnvironment: Equatable {
}
final class ScrollComponent<ChildEnvironment: Equatable>: Component {
public typealias EnvironmentType = ChildEnvironment
typealias EnvironmentType = ChildEnvironment
public let content: AnyComponent<(ChildEnvironment, ScrollChildEnvironment)>
public let contentInsets: UIEdgeInsets
public let contentOffsetUpdated: (_ top: CGFloat, _ bottom: CGFloat) -> Void
public let contentOffsetWillCommit: (UnsafeMutablePointer<CGPoint>) -> Void
let content: AnyComponent<(ChildEnvironment, ScrollChildEnvironment)>
let contentInsets: UIEdgeInsets
let contentOffsetUpdated: (_ top: CGFloat, _ bottom: CGFloat) -> Void
let contentOffsetWillCommit: (UnsafeMutablePointer<CGPoint>) -> Void
let resetScroll: ActionSlot<Void>
public init(
content: AnyComponent<(ChildEnvironment, ScrollChildEnvironment)>,
contentInsets: UIEdgeInsets,
contentOffsetUpdated: @escaping (_ top: CGFloat, _ bottom: CGFloat) -> Void,
contentOffsetWillCommit: @escaping (UnsafeMutablePointer<CGPoint>) -> Void
contentOffsetWillCommit: @escaping (UnsafeMutablePointer<CGPoint>) -> Void,
resetScroll: ActionSlot<Void> = ActionSlot()
) {
self.content = content
self.contentInsets = contentInsets
self.contentOffsetUpdated = contentOffsetUpdated
self.contentOffsetWillCommit = contentOffsetWillCommit
self.resetScroll = resetScroll
}
public static func ==(lhs: ScrollComponent, rhs: ScrollComponent) -> Bool {
@ -46,7 +49,6 @@ final class ScrollComponent<ChildEnvironment: Equatable>: Component {
if lhs.contentInsets != rhs.contentInsets {
return false
}
return true
}
@ -107,6 +109,10 @@ final class ScrollComponent<ChildEnvironment: Equatable>: Component {
)
transition.setFrame(view: self.contentView, frame: CGRect(origin: .zero, size: contentSize), completion: nil)
component.resetScroll.connect { [weak self] _ in
self?.setContentOffset(.zero, animated: false)
}
if self.contentSize != contentSize {
self.ignoreDidScroll = true
self.contentSize = contentSize

View File

@ -8,7 +8,8 @@ private let whitelistedHosts: Set<String> = Set([
"t.me",
"telegram.me",
"telegra.ph",
"telesco.pe"
"telesco.pe",
"fragment.com"
])
private let dataDetector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType([.link]).rawValue)

View File

@ -4,7 +4,8 @@ private let whitelistedHosts: Set<String> = Set([
"t.me",
"telegram.me",
"telegra.ph",
"telesco.pe"
"telesco.pe",
"fragment.com"
])
public func isConcealedUrlWhitelisted(_ url: URL) -> Bool {