diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift index a38b0204c9..1467a13e6b 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift @@ -593,8 +593,16 @@ public final class StoryItemSetContainerComponent: Component { } func activateInput() { - if let inputPanelView = self.inputPanel.view as? MessageInputPanelComponent.View { - inputPanelView.activateInput() + guard let component = self.component else { + return + } + if component.slice.peer.id == component.context.account.peerId { + self.displayViewList = true + self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring))) + } else { + if let inputPanelView = self.inputPanel.view as? MessageInputPanelComponent.View { + inputPanelView.activateInput() + } } } @@ -621,6 +629,16 @@ public final class StoryItemSetContainerComponent: Component { ) footerPanelView.layer.animateAlpha(from: 0.0, to: footerPanelView.alpha, duration: 0.28) } + if let viewListView = self.viewList?.view.view { + viewListView.layer.animatePosition( + from: CGPoint(x: 0.0, y: self.bounds.height - self.contentContainerView.frame.maxY), + to: CGPoint(), + duration: 0.3, + timingFunction: kCAMediaTimingFunctionSpring, + additive: true + ) + viewListView.layer.animateAlpha(from: 0.0, to: viewListView.alpha, duration: 0.28) + } if let captionItemView = self.captionItem?.view.view { captionItemView.layer.animatePosition( from: CGPoint(x: 0.0, y: self.bounds.height - captionItemView.frame.minY), @@ -704,6 +722,16 @@ public final class StoryItemSetContainerComponent: Component { ) footerPanelView.layer.animateAlpha(from: footerPanelView.alpha, to: 0.0, duration: 0.3, removeOnCompletion: false) } + if let viewListView = self.viewList?.view.view { + viewListView.layer.animatePosition( + from: CGPoint(), + to: CGPoint(x: 0.0, y: self.bounds.height - self.contentContainerView.frame.maxY), + duration: 0.3, + timingFunction: kCAMediaTimingFunctionSpring, + additive: true + ) + viewListView.layer.animateAlpha(from: 0.0, to: viewListView.alpha, duration: 0.28) + } if let captionItemView = self.captionItem?.view.view { captionItemView.layer.animatePosition( from: CGPoint(), @@ -1270,6 +1298,13 @@ public final class StoryItemSetContainerComponent: Component { self.viewList = viewList } + let outerExpansionFraction: CGFloat + if self.displayViewList { + outerExpansionFraction = 1.0 + } else { + outerExpansionFraction = component.verticalPanFraction + } + viewList.view.parentState = state let viewListSize = viewList.view.update( transition: viewListTransition, @@ -1280,13 +1315,235 @@ public final class StoryItemSetContainerComponent: Component { strings: component.strings, safeInsets: component.safeInsets, storyItem: component.slice.item.storyItem, - outerExpansionFraction: component.verticalPanFraction, + outerExpansionFraction: outerExpansionFraction, close: { [weak self] in guard let self else { return } self.displayViewList = false self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring))) + }, + expandViewStats: { [weak self] in + guard let self else { + return + } + + if !self.displayViewList { + self.displayViewList = true + self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring))) + } + }, + deleteAction: { [weak self] in + guard let self, let component = self.component else { + return + } + + let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme) + let actionSheet = ActionSheetController(presentationData: presentationData) + + actionSheet.setItemGroups([ + ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: "Delete", color: .destructive, action: { [weak self, weak actionSheet] in + actionSheet?.dismissAnimated() + + guard let self, let component = self.component else { + return + } + component.delete() + + /*if let currentSlice = self.currentSlice, let index = currentSlice.items.firstIndex(where: { $0.id == focusedItemId }) { + let item = currentSlice.items[index] + + if currentSlice.items.count == 1 { + component.navigateToItemSet(.next) + } else { + var nextIndex: Int = index + 1 + if nextIndex >= currentSlice.items.count { + nextIndex = currentSlice.items.count - 1 + } + self.focusedItemId = currentSlice.items[nextIndex].id + + currentSlice.items[nextIndex].markAsSeen?() + + self.state?.updated(transition: .immediate) + } + + item.delete?() + }*/ + }) + ]), + ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + }) + ]) + ]) + + actionSheet.dismissed = { [weak self] _ in + guard let self else { + return + } + self.actionSheet = nil + self.updateIsProgressPaused() + } + self.actionSheet = actionSheet + self.updateIsProgressPaused() + + component.presentController(actionSheet) + }, + moreAction: { [weak self] sourceView, gesture in + guard let self, let component = self.component, let controller = component.controller() else { + return + } + + var items: [ContextMenuItem] = [] + + let additionalCount = component.slice.item.storyItem.privacy?.additionallyIncludePeers.count ?? 0 + + let privacyText: String + switch component.slice.item.storyItem.privacy?.base { + case .closeFriends: + if additionalCount != 0 { + privacyText = "Close Friends (+\(additionalCount)" + } else { + privacyText = "Close Friends" + } + case .contacts: + if additionalCount != 0 { + privacyText = "Contacts (+\(additionalCount)" + } else { + privacyText = "Contacts" + } + case .nobody: + if additionalCount != 0 { + if additionalCount == 1 { + privacyText = "\(additionalCount) Person" + } else { + privacyText = "\(additionalCount) People" + } + } else { + privacyText = "Only Me" + } + default: + privacyText = "Everyone" + } + + items.append(.action(ContextMenuActionItem(text: "Who can see", textLayout: .secondLineWithValue(privacyText), icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Channels"), color: theme.contextMenu.primaryColor) + }, action: { [weak self] _, a in + a(.default) + + guard let self else { + return + } + self.openItemPrivacySettings() + }))) + + items.append(.action(ContextMenuActionItem(text: "Edit Story", icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) + }, action: { [weak self] _, a in + a(.default) + + guard let self else { + return + } + self.openStoryEditing() + }))) + + items.append(.separator) + + component.controller()?.forEachController { c in + if let c = c as? UndoOverlayController { + c.dismiss() + } + return true + } + + items.append(.action(ContextMenuActionItem(text: component.slice.item.storyItem.isPinned ? "Remove from profile" : "Save to profile", icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: component.slice.item.storyItem.isPinned ? "Chat/Context Menu/Check" : "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) + }, action: { [weak self] _, a in + a(.default) + + guard let self, let component = self.component else { + return + } + + let _ = component.context.engine.messages.updateStoriesArePinned(ids: [component.slice.item.storyItem.id: component.slice.item.storyItem], isPinned: !component.slice.item.storyItem.isPinned).start() + + if component.slice.item.storyItem.isPinned { + let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme) + self.component?.presentController(UndoOverlayController( + presentationData: presentationData, + content: .info(title: nil, text: "Story removed from your profile", timeout: nil), + elevatedLayout: false, + animateInAsReplacement: false, + action: { _ in return false } + )) + } else { + let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme) + self.component?.presentController(UndoOverlayController( + presentationData: presentationData, + content: .info(title: "Story saved to your profile", text: "Saved stories can be viewed by others on your profile until you remove them.", timeout: nil), + elevatedLayout: false, + animateInAsReplacement: false, + action: { _ in return false } + )) + } + }))) + items.append(.action(ContextMenuActionItem(text: "Save image", icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.contextMenu.primaryColor) + }, action: { _, a in + a(.default) + }))) + + if component.slice.item.storyItem.isPublic { + items.append(.action(ContextMenuActionItem(text: "Copy link", icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor) + }, action: { [weak self] _, a in + a(.default) + + guard let self, let component = self.component else { + return + } + + let _ = (component.context.engine.messages.exportStoryLink(peerId: component.slice.peer.id, id: component.slice.item.storyItem.id) + |> deliverOnMainQueue).start(next: { [weak self] link in + guard let self, let component = self.component else { + return + } + if let link { + UIPasteboard.general.string = link + + let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme) + component.presentController(UndoOverlayController( + presentationData: presentationData, + content: .linkCopied(text: "Link copied."), + elevatedLayout: false, + animateInAsReplacement: false, + action: { _ in return false } + )) + } + }) + }))) + items.append(.action(ContextMenuActionItem(text: "Share", icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) + }, action: { _, a in + a(.default) + }))) + } + + let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme) + let contextController = ContextController(account: component.context.account, presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: controller, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture) + contextController.dismissed = { [weak self] in + guard let self else { + return + } + self.contextController = nil + self.updateIsProgressPaused() + } + self.contextController = contextController + self.updateIsProgressPaused() + controller.present(contextController, in: .window(.root)) } )), environment: {}, diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetViewListComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetViewListComponent.swift index 5775368689..0e953b1cfb 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetViewListComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetViewListComponent.swift @@ -29,6 +29,9 @@ final class StoryItemSetViewListComponent: Component { let storyItem: EngineStoryItem let outerExpansionFraction: CGFloat let close: () -> Void + let expandViewStats: () -> Void + let deleteAction: () -> Void + let moreAction: (UIView, ContextGesture?) -> Void init( externalState: ExternalState, @@ -38,7 +41,10 @@ final class StoryItemSetViewListComponent: Component { safeInsets: UIEdgeInsets, storyItem: EngineStoryItem, outerExpansionFraction: CGFloat, - close: @escaping () -> Void + close: @escaping () -> Void, + expandViewStats: @escaping () -> Void, + deleteAction: @escaping () -> Void, + moreAction: @escaping (UIView, ContextGesture?) -> Void ) { self.externalState = externalState self.context = context @@ -48,6 +54,9 @@ final class StoryItemSetViewListComponent: Component { self.storyItem = storyItem self.outerExpansionFraction = outerExpansionFraction self.close = close + self.expandViewStats = expandViewStats + self.deleteAction = deleteAction + self.moreAction = moreAction } static func ==(lhs: StoryItemSetViewListComponent, rhs: StoryItemSetViewListComponent) -> Bool { @@ -284,6 +293,11 @@ final class StoryItemSetViewListComponent: Component { } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if let navigationPanelView = self.navigationPanel.view { + if let result = navigationPanelView.hitTest(self.convert(point, to: navigationPanelView), with: event) { + return result + } + } if !self.backgroundView.frame.contains(point) { return nil } @@ -478,7 +492,7 @@ final class StoryItemSetViewListComponent: Component { self.component = component self.state = state - let minimizedHeight = min(availableSize.height, 488.0) + let minimizedHeight = min(availableSize.height, 500.0) if themeUpdated { self.backgroundView.backgroundColor = component.theme.rootController.navigationBar.blurredBackgroundColor @@ -512,7 +526,7 @@ final class StoryItemSetViewListComponent: Component { let sideInset: CGFloat = 16.0 let navigationHeight: CGFloat = 56.0 - let navigationBarFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - minimizedHeight), size: CGSize(width: availableSize.width, height: navigationHeight)) + let navigationBarFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - minimizedHeight + 12.0), size: CGSize(width: availableSize.width, height: navigationHeight)) transition.setFrame(view: self.navigationBarBackground, frame: navigationBarFrame) self.navigationBarBackground.update(size: navigationBarFrame.size, cornerRadius: 10.0, maskedCorners: [.layerMinXMinYCorner, .layerMaxXMinYCorner], transition: transition.containedViewLayoutTransition) @@ -540,29 +554,41 @@ final class StoryItemSetViewListComponent: Component { transition.setFrame(view: navigationLeftButtonView, frame: navigationLeftButtonFrame) } + let expansionOffset = availableSize.height - self.navigationBarBackground.frame.minY + + var dismissOffsetY: CGFloat = 0.0 + if let dismissPanState = self.dismissPanState { + dismissOffsetY = -dismissPanState.accumulatedOffset + } + + dismissOffsetY -= (1.0 - component.outerExpansionFraction) * expansionOffset + + let dismissFraction: CGFloat = 1.0 - max(0.0, min(1.0, -dismissOffsetY / expansionOffset)) + let navigationPanelSize = self.navigationPanel.update( transition: transition, component: AnyComponent(StoryFooterPanelComponent( context: component.context, storyItem: component.storyItem, + expandFraction: dismissFraction, expandViewStats: { [weak self] in - guard let self else { + guard let self, let component = self.component else { return } - let _ = self + component.expandViewStats() }, deleteAction: { [weak self] in guard let self, let component = self.component else { return } - let _ = component + component.deleteAction() }, moreAction: { [weak self] sourceView, gesture in guard let self, let component = self.component else { return } - let _ = component + component.moreAction(sourceView, gesture) } )), environment: {}, @@ -573,21 +599,12 @@ final class StoryItemSetViewListComponent: Component { self.addSubview(navigationPanelView) } - let expandedNavigationPanelFrame = CGRect(origin: navigationBarFrame.origin, size: navigationPanelSize) - let collapsedNavigationPanelFrame = CGRect(origin: CGPoint(x: navigationBarFrame.minX, y: availableSize.height - navigationPanelSize.height), size: navigationPanelSize) + let expandedNavigationPanelFrame = CGRect(origin: CGPoint(x: navigationBarFrame.minX, y: navigationBarFrame.minY + 4.0), size: navigationPanelSize) + let collapsedNavigationPanelFrame = CGRect(origin: CGPoint(x: navigationBarFrame.minX, y: navigationBarFrame.minY - navigationPanelSize.height - component.safeInsets.bottom - 1.0), size: navigationPanelSize) - transition.setFrame(view: navigationPanelView, frame: collapsedNavigationPanelFrame.interpolate(to: expandedNavigationPanelFrame, amount: component.outerExpansionFraction)) + transition.setFrame(view: navigationPanelView, frame: collapsedNavigationPanelFrame.interpolate(to: expandedNavigationPanelFrame, amount: dismissFraction)) } - /*let navigationTitleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - navigationTitleSize.width) * 0.5), y: navigationBarFrame.minY + floor((navigationBarFrame.height - navigationTitleSize.height) * 0.5)), size: navigationTitleSize) - if let navigationTitleView = self.navigationTitle.view { - if navigationTitleView.superview == nil { - self.addSubview(navigationTitleView) - } - transition.setPosition(view: navigationTitleView, position: navigationTitleFrame.center) - transition.setBounds(view: navigationTitleView, bounds: CGRect(origin: CGPoint(), size: navigationTitleFrame.size)) - }*/ - transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarFrame.maxY), size: CGSize(width: availableSize.width, height: availableSize.height))) let measureItemSize = self.measureItem.update( @@ -662,19 +679,13 @@ final class StoryItemSetViewListComponent: Component { self.ignoreScrolling = false self.updateScrolling(transition: transition) - - var dismissOffsetY: CGFloat = 0.0 - if let dismissPanState = self.dismissPanState { - dismissOffsetY = -dismissPanState.accumulatedOffset - } - - let expansionOffset = availableSize.height - self.navigationBarBackground.frame.minY - dismissOffsetY -= (1.0 - component.outerExpansionFraction) * expansionOffset transition.setBoundsOrigin(view: self, origin: CGPoint(x: 0.0, y: dismissOffsetY)) component.externalState.minimizedHeight = minimizedHeight - component.externalState.effectiveHeight = min(minimizedHeight, max(0.0, minimizedHeight + dismissOffsetY)) + + let effectiveHeight: CGFloat = minimizedHeight * dismissFraction + (1.0 - dismissFraction) * (60.0 + component.safeInsets.bottom + 1.0) + component.externalState.effectiveHeight = min(minimizedHeight, max(0.0, effectiveHeight)) return availableSize } diff --git a/submodules/TelegramUI/Components/Stories/StoryFooterPanelComponent/Sources/StoryFooterPanelComponent.swift b/submodules/TelegramUI/Components/Stories/StoryFooterPanelComponent/Sources/StoryFooterPanelComponent.swift index 7d9a7e1fa6..4754c71da0 100644 --- a/submodules/TelegramUI/Components/Stories/StoryFooterPanelComponent/Sources/StoryFooterPanelComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryFooterPanelComponent/Sources/StoryFooterPanelComponent.swift @@ -12,6 +12,7 @@ import MoreHeaderButton public final class StoryFooterPanelComponent: Component { public let context: AccountContext public let storyItem: EngineStoryItem? + public let expandFraction: CGFloat public let expandViewStats: () -> Void public let deleteAction: () -> Void public let moreAction: (UIView, ContextGesture?) -> Void @@ -19,6 +20,7 @@ public final class StoryFooterPanelComponent: Component { public init( context: AccountContext, storyItem: EngineStoryItem?, + expandFraction: CGFloat, expandViewStats: @escaping () -> Void, deleteAction: @escaping () -> Void, moreAction: @escaping (UIView, ContextGesture?) -> Void @@ -26,6 +28,7 @@ public final class StoryFooterPanelComponent: Component { self.context = context self.storyItem = storyItem self.expandViewStats = expandViewStats + self.expandFraction = expandFraction self.deleteAction = deleteAction self.moreAction = moreAction } @@ -37,12 +40,16 @@ public final class StoryFooterPanelComponent: Component { if lhs.storyItem != rhs.storyItem { return false } + if lhs.expandFraction != rhs.expandFraction { + return false + } return true } public final class View: UIView { private let viewStatsButton: HighlightableButton private let viewStatsText = ComponentView() + private let viewStatsExpandedText = ComponentView() private let deleteButton = ComponentView() private var moreButton: MoreHeaderButton? @@ -98,6 +105,8 @@ public final class StoryFooterPanelComponent: Component { let avatarsNodeFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - avatarsSize.height) * 0.5)), size: avatarsSize) self.avatarsNode.frame = avatarsNodeFrame + //transition.setScale(view: self.avatarsNode.view, scale: CGFloat(1.0).interpolate(to: 0.001, amount: component.expandFraction)) + transition.setAlpha(view: self.avatarsNode.view, alpha: pow(1.0 - component.expandFraction, 1.0)) if !avatarsSize.width.isZero { leftOffset = avatarsNodeFrame.maxX + avatarSpacing } @@ -124,18 +133,45 @@ public final class StoryFooterPanelComponent: Component { environment: {}, containerSize: CGSize(width: availableSize.width, height: size.height) ) - let viewStatsTextFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - viewStatsTextSize.height) * 0.5)), size: viewStatsTextSize) + let viewStatsExpandedTextSize = self.viewStatsExpandedText.update( + transition: .immediate, + component: AnyComponent(Text(text: viewsText, font: Font.semibold(17.0), color: .white)), + environment: {}, + containerSize: CGSize(width: availableSize.width, height: size.height) + ) + + let viewStatsCollapsedFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - viewStatsTextSize.height) * 0.5)), size: viewStatsTextSize) + let viewStatsExpandedFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - viewStatsExpandedTextSize.width) * 0.5), y: floor((size.height - viewStatsExpandedTextSize.height) * 0.5)), size: viewStatsExpandedTextSize) + let viewStatsCurrentFrame = viewStatsCollapsedFrame.interpolate(to: viewStatsExpandedFrame, amount: component.expandFraction) + + let viewStatsTextCenter = viewStatsCollapsedFrame.center.interpolate(to: viewStatsExpandedFrame.center, amount: component.expandFraction) + + let viewStatsTextFrame = viewStatsCollapsedFrame.size.centered(around: viewStatsTextCenter) if let viewStatsTextView = self.viewStatsText.view { if viewStatsTextView.superview == nil { - viewStatsTextView.layer.anchorPoint = CGPoint() viewStatsTextView.isUserInteractionEnabled = false self.viewStatsButton.addSubview(viewStatsTextView) } - transition.setPosition(view: viewStatsTextView, position: viewStatsTextFrame.origin) + transition.setPosition(view: viewStatsTextView, position: viewStatsTextFrame.center) transition.setBounds(view: viewStatsTextView, bounds: CGRect(origin: CGPoint(), size: viewStatsTextFrame.size)) + transition.setAlpha(view: viewStatsTextView, alpha: pow(1.0 - component.expandFraction, 1.2)) + transition.setScale(view: viewStatsTextView, scale: viewStatsCurrentFrame.width / viewStatsTextFrame.width) + } + + let viewStatsExpandedTextFrame = viewStatsExpandedFrame.size.centered(around: viewStatsTextCenter) + if let viewStatsExpandedTextView = self.viewStatsExpandedText.view { + if viewStatsExpandedTextView.superview == nil { + viewStatsExpandedTextView.isUserInteractionEnabled = false + self.viewStatsButton.addSubview(viewStatsExpandedTextView) + } + transition.setPosition(view: viewStatsExpandedTextView, position: viewStatsExpandedTextFrame.center) + transition.setBounds(view: viewStatsExpandedTextView, bounds: CGRect(origin: CGPoint(), size: viewStatsExpandedTextFrame.size)) + transition.setAlpha(view: viewStatsExpandedTextView, alpha: pow(component.expandFraction, 1.2)) + transition.setScale(view: viewStatsExpandedTextView, scale: viewStatsCurrentFrame.width / viewStatsExpandedTextFrame.width) } transition.setFrame(view: self.viewStatsButton, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: viewStatsTextFrame.maxX, height: viewStatsTextFrame.maxY + 8.0))) + self.viewStatsButton.isUserInteractionEnabled = component.expandFraction == 0.0 var rightContentOffset: CGFloat = availableSize.width - 12.0 @@ -162,6 +198,8 @@ public final class StoryFooterPanelComponent: Component { } transition.setFrame(view: deleteButtonView, frame: CGRect(origin: CGPoint(x: rightContentOffset - deleteButtonSize.width, y: floor((size.height - deleteButtonSize.height) * 0.5)), size: deleteButtonSize)) rightContentOffset -= deleteButtonSize.width + 8.0 + + transition.setAlpha(view: deleteButtonView, alpha: pow(1.0 - component.expandFraction, 1.0)) } let moreButton: MoreHeaderButton @@ -197,6 +235,7 @@ public final class StoryFooterPanelComponent: Component { let buttonSize = CGSize(width: 32.0, height: 44.0) moreButton.setContent(.more(MoreHeaderButton.optionsCircleImage(color: .white))) transition.setFrame(view: moreButton.view, frame: CGRect(origin: CGPoint(x: rightContentOffset - buttonSize.width, y: floor((size.height - buttonSize.height) / 2.0)), size: buttonSize)) + transition.setAlpha(view: moreButton.view, alpha: pow(1.0 - component.expandFraction, 1.0)) return size }