diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index ea2f5d4539..8a404ee8de 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -10222,6 +10222,10 @@ Sorry for the inconvenience."; "ReassignBoost.Boosts_any" = "%@ boosts are reassigned"; "ReassignBoost.OtherChannels_1" = "%@ other channel"; "ReassignBoost.OtherChannels_any" = "%@ other channels"; +"ReassignBoost.OtherGroups_1" = "%@ other group"; +"ReassignBoost.OtherGroups_any" = "%@ other groups"; +"ReassignBoost.OtherGroupsAndChannels_1" = "%@ other group and channel"; +"ReassignBoost.OtherGroupsAndChannels_any" = "%@ other groups and channels"; "ChannelBoost.MoreBoosts.Title" = "More Boosts Needed"; "ChannelBoost.MoreBoosts.Text" = "To boost **%1$@** again, gift **Telegram Premium** to a friend and get **%2$@** additional boosts."; @@ -11247,7 +11251,7 @@ Sorry for the inconvenience."; "Chat.Giveaway.Message.Group.Participants" = "All members of this group:"; "Chat.Giveaway.Message.Group.ParticipantsNew" = "All users who join this group after this date:"; -"Chat.Giveaway.Message.Group.ParticipantsMany" = "All subscribers of the channels below:"; +"Chat.Giveaway.Message.Group.ParticipantsMany" = "All members of the groups below:"; "Chat.Giveaway.Message.Group.ParticipantsNewMany" = "All users who join the groups below after this date:"; "Story.Privacy.KeepOnGroupPage" = "Post to Group Page"; @@ -11260,3 +11264,15 @@ Sorry for the inconvenience."; "BoostGift.Members.MaximumReached" = "You can select maximum %@ members."; "Chat.ErrorCantBoost" = "Sorry, you can't boost this group or channel."; + +"ChannelBoost.Boost" = "Boost"; +"ChannelBoost.Copy" = "Copy"; + +"Chat.Giveaway.Info.OtherGroups_1" = "**%@** other listed group"; +"Chat.Giveaway.Info.OtherGroups_any" = "**%@** other listed groups"; + +"Chat.Giveaway.Info.OtherGroupsAndChannels_1" = "**%@** other listed group and channel"; +"Chat.Giveaway.Info.OtherGroupsAndChannels_any" = "**%@** other listed groups and channels"; + +"Chat.Giveaway.Info.OtherChannelsAndGroups_1" = "**%@** other listed channel and group"; +"Chat.Giveaway.Info.OtherChannelsAndGroups_any" = "**%@** other listed channels and groups"; diff --git a/submodules/PremiumUI/Sources/BadgeLabelView.swift b/submodules/PremiumUI/Sources/BadgeLabelView.swift index 315551c5f0..3d7be34fdb 100644 --- a/submodules/PremiumUI/Sources/BadgeLabelView.swift +++ b/submodules/PremiumUI/Sources/BadgeLabelView.swift @@ -134,6 +134,7 @@ final class BadgeLabelView: UIView { } else { itemTransition = transition.withAnimation(.none) itemView = StackView() + itemView.color = self.color self.itemViews[i] = itemView self.addSubview(itemView) } diff --git a/submodules/PremiumUI/Sources/GiveawayInfoController.swift b/submodules/PremiumUI/Sources/GiveawayInfoController.swift index 3cc7f0ea2b..a3015ba633 100644 --- a/submodules/PremiumUI/Sources/GiveawayInfoController.swift +++ b/submodules/PremiumUI/Sources/GiveawayInfoController.swift @@ -70,21 +70,38 @@ public func presentGiveawayInfoController( onlyNewSubscribers = true } - var channelsCount: Int32 = 1 - if let giveaway { - channelsCount = Int32(giveaway.channelPeerIds.count) - } else if let giveawayResults { - channelsCount = 1 + giveawayResults.additionalChannelsCount - } - - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let author = message.forwardInfo?.author ?? message.author?._asPeer() var isGroup = false if let channel = author as? TelegramChannel, case .group = channel.info { isGroup = true } + var groupsAndChannels = false + var channelsCount: Int32 = 1 + if let giveaway { + channelsCount = Int32(giveaway.channelPeerIds.count) + + var channelCount = 0 + var groupCount = 0 + for peerId in giveaway.channelPeerIds { + if let peer = message.peers[peerId] as? TelegramChannel { + switch peer.info { + case .broadcast: + channelCount += 1 + case .group: + groupCount += 1 + } + } + } + if groupCount > 0 && channelCount > 0 { + groupsAndChannels = true + } + } else if let giveawayResults { + channelsCount = 1 + giveawayResults.additionalChannelsCount + } + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + var peerName = "" if let channel = author as? TelegramChannel { peerName = EnginePeer(channel).compactDisplayTitle @@ -132,18 +149,43 @@ public func presentGiveawayInfoController( } } + var otherText: String = "" + if channelsCount > 1 { + if isGroup { + if groupsAndChannels { + if channelsCount == 2 { + otherText = presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(channelsCount - 1)) + } else { + otherText = presentationData.strings.Chat_Giveaway_Info_OtherGroupsAndChannels(Int32(channelsCount - 1)) + } + } else { + otherText = presentationData.strings.Chat_Giveaway_Info_OtherGroups(Int32(channelsCount - 1)) + } + } else { + if groupsAndChannels { + if channelsCount == 2 { + otherText = presentationData.strings.Chat_Giveaway_Info_OtherGroups(Int32(channelsCount - 1)) + } else { + otherText = presentationData.strings.Chat_Giveaway_Info_OtherChannelsAndGroups(Int32(channelsCount - 1)) + } + } else { + otherText = presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(channelsCount - 1)) + } + } + } + let ending: String if onlyNewSubscribers { let randomUsers = presentationData.strings.Chat_Giveaway_Info_RandomUsers(quantity) if channelsCount > 1 { - ending = presentationData.strings.Chat_Giveaway_Info_OngoingNewMany(untilDate, randomUsers, peerName, presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(channelsCount - 1)), startDate).string + ending = presentationData.strings.Chat_Giveaway_Info_OngoingNewMany(untilDate, randomUsers, peerName, otherText, startDate).string } else { ending = presentationData.strings.Chat_Giveaway_Info_OngoingNew(untilDate, randomUsers, peerName, startDate).string } } else { let randomSubscribers = isGroup ? presentationData.strings.Chat_Giveaway_Info_Group_RandomMembers(quantity) : presentationData.strings.Chat_Giveaway_Info_RandomSubscribers(quantity) if channelsCount > 1 { - ending = presentationData.strings.Chat_Giveaway_Info_OngoingMany(untilDate, randomSubscribers, peerName, presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(channelsCount - 1))).string + ending = presentationData.strings.Chat_Giveaway_Info_OngoingMany(untilDate, randomSubscribers, peerName, otherText).string } else { ending = presentationData.strings.Chat_Giveaway_Info_Ongoing(untilDate, randomSubscribers, peerName).string } @@ -153,7 +195,7 @@ public func presentGiveawayInfoController( switch status { case .notQualified: if channelsCount > 1 { - participation = presentationData.strings.Chat_Giveaway_Info_NotQualifiedMany(peerName, presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(channelsCount - 1)), untilDate).string + participation = presentationData.strings.Chat_Giveaway_Info_NotQualifiedMany(peerName, otherText, untilDate).string } else { participation = presentationData.strings.Chat_Giveaway_Info_NotQualified(peerName, untilDate).string } @@ -177,7 +219,7 @@ public func presentGiveawayInfoController( } case .participating: if channelsCount > 1 { - participation = presentationData.strings.Chat_Giveaway_Info_ParticipatingMany(peerName, presentationData.strings.Chat_Giveaway_Info_OtherChannels(Int32(channelsCount - 1))).string + participation = presentationData.strings.Chat_Giveaway_Info_ParticipatingMany(peerName, otherText).string } else { participation = presentationData.strings.Chat_Giveaway_Info_Participating(peerName).string } diff --git a/submodules/PremiumUI/Sources/PremiumBoostLevelsScreen.swift b/submodules/PremiumUI/Sources/PremiumBoostLevelsScreen.swift index 555fd9fcd6..0f6d306bbf 100644 --- a/submodules/PremiumUI/Sources/PremiumBoostLevelsScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumBoostLevelsScreen.swift @@ -918,10 +918,9 @@ private final class SheetContent: CombinedComponent { ) contentSize.height += linkButton.size.height + 16.0 - //TODO:localize let boostButton = boostButton.update( component: SolidRoundedButtonComponent( - title: "Boost", + title: strings.ChannelBoost_Boost, theme: SolidRoundedButtonComponent.Theme( backgroundColor: .black, backgroundColors: buttonGradientColors, @@ -945,7 +944,7 @@ private final class SheetContent: CombinedComponent { let copyButton = copyButton.update( component: SolidRoundedButtonComponent( - title: "Copy", + title: strings.ChannelBoost_Copy, theme: SolidRoundedButtonComponent.Theme( backgroundColor: .black, backgroundColors: buttonGradientColors, @@ -1185,6 +1184,7 @@ private final class SheetContent: CombinedComponent { private final class BoostLevelsContainerComponent: CombinedComponent { class ExternalState { var isGroup: Bool = false + var contentHeight: CGFloat = 0.0 } let context: AccountContext @@ -1201,6 +1201,7 @@ private final class BoostLevelsContainerComponent: CombinedComponent { let openStats: (() -> Void)? let openGift: (() -> Void)? let openPeer: ((EnginePeer) -> Void)? + let updated: () -> Void init( context: AccountContext, @@ -1216,7 +1217,8 @@ private final class BoostLevelsContainerComponent: CombinedComponent { dismiss: @escaping () -> Void, openStats: (() -> Void)?, openGift: (() -> Void)?, - openPeer: ((EnginePeer) -> Void)? + openPeer: ((EnginePeer) -> Void)?, + updated: @escaping () -> Void ) { self.context = context self.theme = theme @@ -1232,6 +1234,7 @@ private final class BoostLevelsContainerComponent: CombinedComponent { self.openStats = openStats self.openGift = openGift self.openPeer = openPeer + self.updated = updated } static func ==(lhs: BoostLevelsContainerComponent, rhs: BoostLevelsContainerComponent) -> Bool { @@ -1264,7 +1267,7 @@ private final class BoostLevelsContainerComponent: CombinedComponent { private var disposable: Disposable? private(set) var peer: EnginePeer? - init(context: AccountContext, peerId: EnginePeer.Id) { + init(context: AccountContext, peerId: EnginePeer.Id, updated: @escaping () -> Void) { super.init() self.disposable = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) @@ -1274,6 +1277,7 @@ private final class BoostLevelsContainerComponent: CombinedComponent { } self.peer = peer self.updated() + updated() }) } @@ -1283,7 +1287,7 @@ private final class BoostLevelsContainerComponent: CombinedComponent { } func makeState() -> State { - return State(context: self.context, peerId: self.peerId) + return State(context: self.context, peerId: self.peerId, updated: self.updated) } static var body: Body { @@ -1295,6 +1299,8 @@ private final class BoostLevelsContainerComponent: CombinedComponent { let statsButton = Child(Button.self) let closeButton = Child(Button.self) + let externalScrollState = ScrollComponent.ExternalState() + return { context in let state = context.state @@ -1337,6 +1343,7 @@ private final class BoostLevelsContainerComponent: CombinedComponent { openPeer: component.openPeer ) ), + externalState: externalScrollState, contentInsets: UIEdgeInsets(top: topInset, left: 0.0, bottom: 0.0, right: 0.0), contentOffsetUpdated: { [weak state] topContentOffset, _ in state?.topContentOffset = topContentOffset @@ -1349,6 +1356,7 @@ private final class BoostLevelsContainerComponent: CombinedComponent { availableSize: context.availableSize, transition: context.transition ) + component.externalState.contentHeight = externalScrollState.contentHeight let background = background.update( component: Rectangle(color: theme.overallDarkAppearance ? theme.list.blocksBackgroundColor : theme.list.plainBackgroundColor), @@ -1563,11 +1571,11 @@ public class PremiumBoostLevelsScreen: ViewController { let footerContainerView: UIView let footerView: ComponentHostView - private let externalState = BoostLevelsContainerComponent.ExternalState() + private let containerExternalState = BoostLevelsContainerComponent.ExternalState() private(set) var isExpanded = false private var panGestureRecognizer: UIPanGestureRecognizer? - private var panGestureArguments: (topInset: CGFloat, offset: CGFloat, scrollView: UIScrollView?, listNode: ListView?)? + private var panGestureArguments: (topInset: CGFloat, offset: CGFloat, scrollView: UIScrollView?)? private let hapticFeedback = HapticFeedback() @@ -1633,7 +1641,7 @@ public class PremiumBoostLevelsScreen: ViewController { self.updatedState.set(.single(InternalBoostState(level: Int32(status.level), currentLevelBoosts: Int32(status.currentLevelBoosts), nextLevelBoosts: status.nextLevelBoosts.flatMap(Int32.init), boosts: boosts + 1))) - if let (replacedBoosts, inChannels) = controller.replacedBoosts { + if let (replacedBoosts, sourcePeers) = controller.replacedBoosts { currentMyBoostCount += 1 self.boostState = initialState.displayData(myBoostCount: myBoostCount, currentMyBoostCount: 1) @@ -1643,7 +1651,29 @@ public class PremiumBoostLevelsScreen: ViewController { Queue.mainQueue().after(0.3) { let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let undoController = UndoOverlayController(presentationData: presentationData, content: .image(image: generateTintedImage(image: UIImage(bundleImageName: "Premium/BoostReplaceIcon"), color: .white)!, title: nil, text: presentationData.strings.ReassignBoost_Success(presentationData.strings.ReassignBoost_Boosts(replacedBoosts), presentationData.strings.ReassignBoost_OtherChannels(inChannels)).string, round: false, undoText: nil), elevatedLayout: false, position: .top, action: { _ in return true }) + + var groupCount: Int32 = 0 + var channelCount: Int32 = 0 + for peer in sourcePeers { + if case let .channel(channel) = peer { + switch channel.info { + case .broadcast: + channelCount += 1 + case .group: + groupCount += 1 + } + } + } + let otherText: String + if channelCount > 0 && groupCount == 0 { + otherText = presentationData.strings.ReassignBoost_OtherChannels(channelCount) + } else if groupCount > 0 && channelCount == 0 { + otherText = presentationData.strings.ReassignBoost_OtherGroups(groupCount) + } else { + otherText = presentationData.strings.ReassignBoost_OtherGroupsAndChannels(Int32(sourcePeers.count)) + } + let text = presentationData.strings.ReassignBoost_Success(presentationData.strings.ReassignBoost_Boosts(replacedBoosts), otherText).string + let undoController = UndoOverlayController(presentationData: presentationData, content: .image(image: generateTintedImage(image: UIImage(bundleImageName: "Premium/BoostReplaceIcon"), color: .white)!, title: nil, text: text, round: false, undoText: nil), elevatedLayout: false, position: .top, action: { _ in return true }) controller.present(undoController, in: .current) } } @@ -1732,31 +1762,10 @@ public class PremiumBoostLevelsScreen: ViewController { self.currentLayout = layout self.dim.frame = CGRect(origin: CGPoint(x: 0.0, y: -layout.size.height), size: CGSize(width: layout.size.width, height: layout.size.height * 3.0)) - - var effectiveExpanded = self.isExpanded - if case .regular = layout.metrics.widthClass { - effectiveExpanded = true - } - + let isLandscape = layout.orientation == .landscape - let edgeTopInset = isLandscape ? 0.0 : self.defaultTopInset - let topInset: CGFloat - if let (panInitialTopInset, panOffset, _, _) = self.panGestureArguments { - if effectiveExpanded { - topInset = min(edgeTopInset, panInitialTopInset + max(0.0, panOffset)) - } else { - topInset = max(0.0, panInitialTopInset + min(0.0, panOffset)) - } - } else if let dismissOffset = self.dismissOffset, !dismissOffset.isZero { - topInset = edgeTopInset * dismissOffset - } else { - topInset = effectiveExpanded ? 0.0 : edgeTopInset - } - transition.setFrame(view: self.wrappingView, frame: CGRect(origin: CGPoint(x: 0.0, y: topInset), size: layout.size), completion: nil) - - let modalProgress = isLandscape ? 0.0 : (1.0 - topInset / self.defaultTopInset) - self.controller?.updateModalStyleOverlayTransitionFactor(modalProgress, transition: transition.containedViewLayoutTransition) + var containerTopInset: CGFloat = 0.0 let clipFrame: CGRect if layout.metrics.widthClass == .compact { self.dim.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.25) @@ -1778,7 +1787,7 @@ public class PremiumBoostLevelsScreen: ViewController { clipFrame = CGRect(origin: CGPoint(), size: layout.size) } else { let coveredByModalTransition: CGFloat = 0.0 - var containerTopInset: CGFloat = 10.0 + containerTopInset = 10.0 if let statusBarHeight = layout.statusBarHeight { containerTopInset += statusBarHeight } @@ -1806,19 +1815,45 @@ public class PremiumBoostLevelsScreen: ViewController { transition.setFrame(view: self.containerView, frame: clipFrame) + var effectiveExpanded = self.isExpanded + if case .regular = layout.metrics.widthClass { + effectiveExpanded = true + } + + self.updated(transition: transition) + + let contentHeight = self.containerExternalState.contentHeight + if contentHeight > 0.0 && contentHeight < 400.0, let view = self.footerView.componentView as? FooterComponent.View { + view.backgroundView.alpha = 0.0 + view.separator.opacity = 0.0 + } + let edgeTopInset = isLandscape ? 0.0 : self.defaultTopInset + + let topInset: CGFloat + if let (panInitialTopInset, panOffset, _) = self.panGestureArguments { + if effectiveExpanded { + topInset = min(edgeTopInset, panInitialTopInset + max(0.0, panOffset)) + } else { + topInset = max(0.0, panInitialTopInset + min(0.0, panOffset)) + } + } else if let dismissOffset = self.dismissOffset, !dismissOffset.isZero { + topInset = edgeTopInset * dismissOffset + } else { + topInset = effectiveExpanded ? 0.0 : edgeTopInset + } + transition.setFrame(view: self.wrappingView, frame: CGRect(origin: CGPoint(x: 0.0, y: topInset), size: layout.size), completion: nil) - var footerHeight: CGFloat = 8.0 + 50.0 - footerHeight += layout.intrinsicInsets.bottom > 0.0 ? layout.intrinsicInsets.bottom + 5.0 : 8.0 + let modalProgress = isLandscape ? 0.0 : (1.0 - topInset / self.defaultTopInset) + self.controller?.updateModalStyleOverlayTransitionFactor(modalProgress, transition: transition.containedViewLayoutTransition) + let footerHeight = self.footerHeight let convertedFooterFrame = self.view.convert(CGRect(origin: CGPoint(x: clipFrame.minX, y: clipFrame.maxY - footerHeight), size: CGSize(width: clipFrame.width, height: footerHeight)), to: self.containerView) transition.setFrame(view: self.footerContainerView, frame: convertedFooterFrame) - - self.updated(transition: transition) } private var boostState: InternalBoostState.DisplayData? func updated(transition: Transition) { - guard let controller = self.controller, let layout = self.currentLayout else { + guard let controller = self.controller else { return } let contentSize = self.contentView.update( @@ -1828,7 +1863,7 @@ public class PremiumBoostLevelsScreen: ViewController { context: controller.context, theme: self.presentationData.theme, strings: self.presentationData.strings, - externalState: self.externalState, + externalState: self.containerExternalState, peerId: controller.peerId, mode: controller.mode, status: controller.status, @@ -1867,7 +1902,10 @@ public class PremiumBoostLevelsScreen: ViewController { }, openStats: controller.openStats, openGift: controller.openGift, - openPeer: controller.openPeer + openPeer: controller.openPeer, + updated: { [weak self] in + self?.controller?.requestLayout(transition: .immediate) + } ) ), environment: {}, @@ -1875,14 +1913,13 @@ public class PremiumBoostLevelsScreen: ViewController { ) self.contentView.frame = CGRect(origin: .zero, size: contentSize) - var footerHeight: CGFloat = 8.0 + 50.0 - footerHeight += layout.intrinsicInsets.bottom > 0.0 ? layout.intrinsicInsets.bottom + 5.0 : 8.0 + let footerHeight = self.footerHeight let actionTitle: String if self.currentMyBoostCount > 0 { actionTitle = self.presentationData.strings.ChannelBoost_BoostAgain } else { - actionTitle = self.externalState.isGroup ? self.presentationData.strings.GroupBoost_BoostGroup : self.presentationData.strings.ChannelBoost_BoostChannel + actionTitle = self.containerExternalState.isGroup ? self.presentationData.strings.GroupBoost_BoostGroup : self.presentationData.strings.ChannelBoost_BoostChannel } let footerSize = self.footerView.update( @@ -1924,6 +1961,15 @@ public class PremiumBoostLevelsScreen: ViewController { } } + private var footerHeight: CGFloat { + guard let layout = self.currentLayout else { + return 58.0 + } + var footerHeight: CGFloat = 8.0 + 50.0 + footerHeight += layout.intrinsicInsets.bottom > 0.0 ? layout.intrinsicInsets.bottom + 5.0 : 8.0 + return footerHeight + } + private var defaultTopInset: CGFloat { guard let layout = self.currentLayout else { return 210.0 @@ -1933,16 +1979,27 @@ public class PremiumBoostLevelsScreen: ViewController { let bottomInset: CGFloat = layout.intrinsicInsets.bottom > 0.0 ? layout.intrinsicInsets.bottom + 5.0 : bottomPanelPadding let panelHeight: CGFloat = bottomPanelPadding + 50.0 + bottomInset + 28.0 - return layout.size.height - layout.size.width - 128.0 - panelHeight + var defaultTopInset = layout.size.height - layout.size.width - 128.0 - panelHeight + + let containerTopInset = 10.0 + (layout.statusBarHeight ?? 0.0) + let contentHeight = self.containerExternalState.contentHeight + let footerHeight = self.footerHeight + if contentHeight > 0.0 { + let delta = (layout.size.height - defaultTopInset - containerTopInset) - contentHeight - footerHeight - 16.0 + if delta > 0.0 { + defaultTopInset += delta + } + } + return defaultTopInset } else { return 210.0 } } - private func findVerticalScrollView(view: UIView?) -> (UIScrollView, ListView?)? { + private func findVerticalScrollView(view: UIView?) -> UIScrollView? { if let view = view { if let view = view as? UIScrollView, view.contentSize.height > view.contentSize.width { - return (view, nil) + return view } return findVerticalScrollView(view: view.superview) } else { @@ -1963,12 +2020,13 @@ public class PremiumBoostLevelsScreen: ViewController { let point = recognizer.location(in: self.view) let currentHitView = self.hitTest(point, with: nil) - var scrollViewAndListNode = self.findVerticalScrollView(view: currentHitView) - if scrollViewAndListNode?.0.frame.height == self.frame.width { - scrollViewAndListNode = nil + var scrollView = self.findVerticalScrollView(view: currentHitView) + if scrollView?.frame.height == self.frame.width { + scrollView = nil + } + if scrollView?.isDescendant(of: self.view) == false { + scrollView = nil } - let scrollView = scrollViewAndListNode?.0 - let listNode = scrollViewAndListNode?.1 let topInset: CGFloat if self.isExpanded { @@ -1977,25 +2035,19 @@ public class PremiumBoostLevelsScreen: ViewController { topInset = edgeTopInset } - self.panGestureArguments = (topInset, 0.0, scrollView, listNode) + self.panGestureArguments = (topInset, 0.0, scrollView) case .changed: - guard let (topInset, panOffset, scrollView, listNode) = self.panGestureArguments else { + guard let (topInset, panOffset, scrollView) = self.panGestureArguments else { return } - let visibleContentOffset = listNode?.visibleContentOffset() let contentOffset = scrollView?.contentOffset.y ?? 0.0 - + var translation = recognizer.translation(in: self.view).y var currentOffset = topInset + translation let epsilon = 1.0 - if case let .known(value) = visibleContentOffset, value <= epsilon { - if let scrollView = scrollView { - scrollView.bounces = false - scrollView.setContentOffset(CGPoint(x: 0.0, y: 0.0), animated: false) - } - } else if let scrollView = scrollView, contentOffset <= -scrollView.contentInset.top + epsilon { + if let scrollView = scrollView, contentOffset <= -scrollView.contentInset.top + epsilon { scrollView.bounces = false scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false) } else if let scrollView = scrollView { @@ -2012,7 +2064,7 @@ public class PremiumBoostLevelsScreen: ViewController { translation = max(0.0, translation) } - self.panGestureArguments = (topInset, translation, scrollView, listNode) + self.panGestureArguments = (topInset, translation, scrollView) if !self.isExpanded { if currentOffset > 0.0, let scrollView = scrollView { @@ -2031,23 +2083,18 @@ public class PremiumBoostLevelsScreen: ViewController { self.containerLayoutUpdated(layout: layout, transition: .immediate) case .ended: - guard let (currentTopInset, panOffset, scrollView, listNode) = self.panGestureArguments else { + guard let (currentTopInset, panOffset, scrollView) = self.panGestureArguments else { return } self.panGestureArguments = nil - let visibleContentOffset = listNode?.visibleContentOffset() let contentOffset = scrollView?.contentOffset.y ?? 0.0 let translation = recognizer.translation(in: self.view).y var velocity = recognizer.velocity(in: self.view) if self.isExpanded { - if case let .known(value) = visibleContentOffset, value > 0.1 { - velocity = CGPoint() - } else if case .unknown = visibleContentOffset { - velocity = CGPoint() - } else if contentOffset > 0.1 { + if contentOffset > 0.1 { velocity = CGPoint() } } @@ -2072,9 +2119,7 @@ public class PremiumBoostLevelsScreen: ViewController { } else if self.isExpanded { if velocity.y > 300.0 || offset > topInset / 2.0 { self.isExpanded = false - if let listNode = listNode { - listNode.scroller.setContentOffset(CGPoint(), animated: false) - } else if let scrollView = scrollView { + if let scrollView = scrollView { scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false) } @@ -2089,21 +2134,13 @@ public class PremiumBoostLevelsScreen: ViewController { self.containerLayoutUpdated(layout: layout, transition: Transition(.animated(duration: 0.3, curve: .easeInOut))) } } else if scrollView != nil, (velocity.y < -300.0 || offset < topInset / 2.0) { - if velocity.y > -2200.0 && velocity.y < -300.0, let listNode = listNode { - DispatchQueue.main.async { - listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) - } - } - let initialVelocity: CGFloat = offset.isZero ? 0.0 : abs(velocity.y / offset) let transition = ContainedViewLayoutTransition.animated(duration: 0.45, curve: .customSpring(damping: 124.0, initialVelocity: initialVelocity)) self.isExpanded = true self.containerLayoutUpdated(layout: layout, transition: Transition(transition)) } else { - if let listNode = listNode { - listNode.scroller.setContentOffset(CGPoint(), animated: false) - } else if let scrollView = scrollView { + if let scrollView = scrollView { scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false) } @@ -2205,11 +2242,15 @@ public class PremiumBoostLevelsScreen: ViewController { var dismissReplaceImpl: (() -> Void)? let replaceController = ReplaceBoostScreen(context: context, peerId: peerId, myBoostStatus: myBoostStatus, replaceBoosts: { slots in - var channelIds = Set() + var sourcePeerIds = Set() + var sourcePeers: [EnginePeer] = [] for boost in myBoostStatus.boosts { if slots.contains(boost.slot) { if let peer = boost.peer { - channelIds.insert(peer.id) + if !sourcePeerIds.contains(peer.id) { + sourcePeerIds.insert(peer.id) + sourcePeers.append(peer) + } } } } @@ -2228,7 +2269,7 @@ public class PremiumBoostLevelsScreen: ViewController { mode: mode, status: status, myBoostStatus: myBoostStatus, - replacedBoosts: (Int32(slots.count), Int32(channelIds.count)), + replacedBoosts: (Int32(slots.count), sourcePeers), openStats: nil, openGift: nil, openPeer: openPeer, forceDark: forceDark ) if let navigationController { @@ -2379,7 +2420,7 @@ public class PremiumBoostLevelsScreen: ViewController { private let mode: Mode private let status: ChannelBoostStatus? private let myBoostStatus: MyBoostStatus? - private let replacedBoosts: (Int32, Int32)? + private let replacedBoosts: (Int32, [EnginePeer])? private let openStats: (() -> Void)? private let openGift: (() -> Void)? private let openPeer: ((EnginePeer) -> Void)? @@ -2395,7 +2436,7 @@ public class PremiumBoostLevelsScreen: ViewController { mode: Mode, status: ChannelBoostStatus?, myBoostStatus: MyBoostStatus? = nil, - replacedBoosts: (Int32, Int32)? = nil, + replacedBoosts: (Int32, [EnginePeer])? = nil, openStats: (() -> Void)? = nil, openGift: (() -> Void)? = nil, openPeer: ((EnginePeer) -> Void)? = nil, @@ -2495,8 +2536,8 @@ private final class FooterComponent: Component { } final class View: UIView { - private let backgroundView: BlurredBackgroundView - private let separator = SimpleLayer() + let backgroundView: BlurredBackgroundView + let separator = SimpleLayer() private let button = ComponentView() diff --git a/submodules/PremiumUI/Sources/ScrollComponent.swift b/submodules/PremiumUI/Sources/ScrollComponent.swift index 127cacb3c9..554396c193 100644 --- a/submodules/PremiumUI/Sources/ScrollComponent.swift +++ b/submodules/PremiumUI/Sources/ScrollComponent.swift @@ -22,7 +22,12 @@ final class ScrollChildEnvironment: Equatable { final class ScrollComponent: Component { typealias EnvironmentType = ChildEnvironment + class ExternalState { + var contentHeight: CGFloat = 0.0 + } + let content: AnyComponent<(ChildEnvironment, ScrollChildEnvironment)> + let externalState: ExternalState? let contentInsets: UIEdgeInsets let contentOffsetUpdated: (_ top: CGFloat, _ bottom: CGFloat) -> Void let contentOffsetWillCommit: (UnsafeMutablePointer) -> Void @@ -30,12 +35,14 @@ final class ScrollComponent: Component { public init( content: AnyComponent<(ChildEnvironment, ScrollChildEnvironment)>, + externalState: ExternalState? = nil, contentInsets: UIEdgeInsets, contentOffsetUpdated: @escaping (_ top: CGFloat, _ bottom: CGFloat) -> Void, contentOffsetWillCommit: @escaping (UnsafeMutablePointer) -> Void, resetScroll: ActionSlot = ActionSlot() ) { self.content = content + self.externalState = externalState self.contentInsets = contentInsets self.contentOffsetUpdated = contentOffsetUpdated self.contentOffsetWillCommit = contentOffsetWillCommit @@ -121,6 +128,7 @@ final class ScrollComponent: Component { if self.scrollIndicatorInsets != component.contentInsets { self.scrollIndicatorInsets = component.contentInsets } + component.externalState?.contentHeight = contentSize.height self.component = component diff --git a/submodules/TelegramCallsUI/Sources/GroupCallNavigationAccessoryPanel.swift b/submodules/TelegramCallsUI/Sources/GroupCallNavigationAccessoryPanel.swift index 60e738a176..326d8dd904 100644 --- a/submodules/TelegramCallsUI/Sources/GroupCallNavigationAccessoryPanel.swift +++ b/submodules/TelegramCallsUI/Sources/GroupCallNavigationAccessoryPanel.swift @@ -752,7 +752,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode { self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(13.0), textColor: self.theme.chat.inputPanel.secondaryTextColor) - var constrainedWidth = size.width / 2.0 - 56.0 + var constrainedWidth = size.width - leftInset - rightInset - 32.0 - joinButtonSize.width - 60.0 if isScheduled { constrainedWidth = size.width - 100.0 }