mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
4cc2eb7850
@ -1737,7 +1737,7 @@ public final class EngineStoryViewListContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init(account: Account, storyId: Int32, views: EngineStoryItem.Views) {
|
init(account: Account, storyId: Int32, views: EngineStoryItem.Views) {
|
||||||
let queue = Queue()
|
let queue = Queue.mainQueue()
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||||
return Impl(queue: queue, account: account, storyId: storyId, views: views)
|
return Impl(queue: queue, account: account, storyId: storyId, views: views)
|
||||||
|
@ -861,7 +861,7 @@ public extension TelegramEngine {
|
|||||||
let _ = accountPeer
|
let _ = accountPeer
|
||||||
let _ = storiesStateView
|
let _ = storiesStateView
|
||||||
|
|
||||||
var sortedItems: [(peer: Peer, item: Stories.Item)] = []
|
var sortedItems: [(peer: Peer, item: Stories.Item, hasUnseen: Bool, lastTimestamp: Int32)] = []
|
||||||
|
|
||||||
for peerId in storySubscriptionsView.peerIds {
|
for peerId in storySubscriptionsView.peerIds {
|
||||||
guard let peerView = views.views[PostboxViewKey.basicPeer(peerId)] as? BasicPeerView else {
|
guard let peerView = views.views[PostboxViewKey.basicPeer(peerId)] as? BasicPeerView else {
|
||||||
@ -878,21 +878,48 @@ public extension TelegramEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var nextItem: Stories.StoredItem? = itemsView.items.first?.value.get(Stories.StoredItem.self)
|
var nextItem: Stories.StoredItem? = itemsView.items.first?.value.get(Stories.StoredItem.self)
|
||||||
|
let lastTimestamp = itemsView.items.last?.value.get(Stories.StoredItem.self)?.timestamp
|
||||||
|
|
||||||
let peerState: Stories.PeerState? = stateView.value?.get(Stories.PeerState.self)
|
let peerState: Stories.PeerState? = stateView.value?.get(Stories.PeerState.self)
|
||||||
|
var hasUnseen = false
|
||||||
if let peerState = peerState {
|
if let peerState = peerState {
|
||||||
if let item = itemsView.items.first(where: { $0.id > peerState.maxReadId }) {
|
if let item = itemsView.items.first(where: { $0.id > peerState.maxReadId }) {
|
||||||
|
hasUnseen = true
|
||||||
nextItem = item.value.get(Stories.StoredItem.self)
|
nextItem = item.value.get(Stories.StoredItem.self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let nextItem = nextItem, case let .item(item) = nextItem {
|
if let nextItem = nextItem, case let .item(item) = nextItem, let lastTimestamp {
|
||||||
sortedItems.append((peer, item))
|
sortedItems.append((peer, item, hasUnseen, lastTimestamp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sortedItems.sort(by: { lhs, rhs in
|
sortedItems.sort(by: { lhs, rhs in
|
||||||
return lhs.item.timestamp > rhs.item.timestamp
|
if lhs.hasUnseen != rhs.hasUnseen {
|
||||||
|
if lhs.hasUnseen {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if EnginePeer(lhs.peer).isService != EnginePeer(rhs.peer).isService {
|
||||||
|
if EnginePeer(lhs.peer).isService {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lhs.peer.isPremium != rhs.peer.isPremium {
|
||||||
|
if lhs.peer.isPremium {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lhs.lastTimestamp != rhs.lastTimestamp {
|
||||||
|
return lhs.lastTimestamp > rhs.lastTimestamp
|
||||||
|
}
|
||||||
|
return lhs.peer.id < rhs.peer.id
|
||||||
})
|
})
|
||||||
|
|
||||||
var nextPriority: Int = 0
|
var nextPriority: Int = 0
|
||||||
|
@ -337,7 +337,7 @@ public final class ChatListNavigationBar: Component {
|
|||||||
if allowAvatarsExpansion && transition.animation.isImmediate {
|
if allowAvatarsExpansion && transition.animation.isImmediate {
|
||||||
if self.storiesUnlocked != storiesUnlocked {
|
if self.storiesUnlocked != storiesUnlocked {
|
||||||
if storiesUnlocked {
|
if storiesUnlocked {
|
||||||
HapticFeedback().impact(.veryLight)
|
HapticFeedback().tap()
|
||||||
} else {
|
} else {
|
||||||
HapticFeedback().impact(.veryLight)
|
HapticFeedback().impact(.veryLight)
|
||||||
}
|
}
|
||||||
|
@ -183,6 +183,8 @@ private final class StoryContainerScreenComponent: Component {
|
|||||||
|
|
||||||
private var availableReactions: StoryAvailableReactions?
|
private var availableReactions: StoryAvailableReactions?
|
||||||
|
|
||||||
|
private let sharedViewListsContext = StoryItemSetViewListComponent.SharedListsContext()
|
||||||
|
|
||||||
private var isAnimatingOut: Bool = false
|
private var isAnimatingOut: Bool = false
|
||||||
private var didAnimateOut: Bool = false
|
private var didAnimateOut: Bool = false
|
||||||
|
|
||||||
@ -448,10 +450,10 @@ private final class StoryContainerScreenComponent: Component {
|
|||||||
self.verticalPanState = nil
|
self.verticalPanState = nil
|
||||||
var updateState = true
|
var updateState = true
|
||||||
|
|
||||||
if translation.y > 100.0 || velocity.y > 10.0 {
|
if translation.y > 200.0 || (translation.y > 100.0 && velocity.y > 200.0) {
|
||||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
|
self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
|
||||||
self.environment?.controller()?.dismiss()
|
self.environment?.controller()?.dismiss()
|
||||||
} else if translation.y < -100.0 || velocity.y < -40.0 {
|
} else if translation.y < -200.0 || (translation.y < -100.0 && velocity.y < -100.0) {
|
||||||
if let component = self.component, let stateValue = component.content.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id] {
|
if let component = self.component, let stateValue = component.content.stateValue, let slice = stateValue.slice, let itemSetView = self.visibleItemSetViews[slice.peer.id] {
|
||||||
if let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
|
if let itemSetComponentView = itemSetView.view.view as? StoryItemSetContainerComponent.View {
|
||||||
if itemSetComponentView.activateInput() {
|
if itemSetComponentView.activateInput() {
|
||||||
@ -980,7 +982,8 @@ private final class StoryContainerScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
keyboardInputData: self.inputMediaNodeDataPromise.get()
|
keyboardInputData: self.inputMediaNodeDataPromise.get(),
|
||||||
|
sharedViewListsContext: self.sharedViewListsContext
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: itemSetContainerSize
|
containerSize: itemSetContainerSize
|
||||||
|
@ -98,8 +98,9 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
public let controller: () -> ViewController?
|
public let controller: () -> ViewController?
|
||||||
public let toggleAmbientMode: () -> Void
|
public let toggleAmbientMode: () -> Void
|
||||||
public let keyboardInputData: Signal<ChatEntityKeyboardInputNode.InputData, NoError>
|
public let keyboardInputData: Signal<ChatEntityKeyboardInputNode.InputData, NoError>
|
||||||
|
let sharedViewListsContext: StoryItemSetViewListComponent.SharedListsContext
|
||||||
|
|
||||||
public init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
externalState: ExternalState,
|
externalState: ExternalState,
|
||||||
storyItemSharedState: StoryContentItem.SharedState,
|
storyItemSharedState: StoryContentItem.SharedState,
|
||||||
@ -125,7 +126,8 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
markAsSeen: @escaping (StoryId) -> Void,
|
markAsSeen: @escaping (StoryId) -> Void,
|
||||||
controller: @escaping () -> ViewController?,
|
controller: @escaping () -> ViewController?,
|
||||||
toggleAmbientMode: @escaping () -> Void,
|
toggleAmbientMode: @escaping () -> Void,
|
||||||
keyboardInputData: Signal<ChatEntityKeyboardInputNode.InputData, NoError>
|
keyboardInputData: Signal<ChatEntityKeyboardInputNode.InputData, NoError>,
|
||||||
|
sharedViewListsContext: StoryItemSetViewListComponent.SharedListsContext
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.externalState = externalState
|
self.externalState = externalState
|
||||||
@ -153,6 +155,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.toggleAmbientMode = toggleAmbientMode
|
self.toggleAmbientMode = toggleAmbientMode
|
||||||
self.keyboardInputData = keyboardInputData
|
self.keyboardInputData = keyboardInputData
|
||||||
|
self.sharedViewListsContext = sharedViewListsContext
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: StoryItemSetContainerComponent, rhs: StoryItemSetContainerComponent) -> Bool {
|
public static func ==(lhs: StoryItemSetContainerComponent, rhs: StoryItemSetContainerComponent) -> Bool {
|
||||||
@ -1705,12 +1708,16 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
let viewListSize = viewList.view.update(
|
let viewListSize = viewList.view.update(
|
||||||
transition: viewListTransition.withUserData(PeerListItemComponent.TransitionHint(
|
transition: viewListTransition.withUserData(PeerListItemComponent.TransitionHint(
|
||||||
synchronousLoad: false
|
synchronousLoad: false
|
||||||
|
)).withUserData(StoryItemSetViewListComponent.AnimationHint(
|
||||||
|
synchronous: false
|
||||||
)),
|
)),
|
||||||
component: AnyComponent(StoryItemSetViewListComponent(
|
component: AnyComponent(StoryItemSetViewListComponent(
|
||||||
externalState: viewList.externalState,
|
externalState: viewList.externalState,
|
||||||
context: component.context,
|
context: component.context,
|
||||||
theme: component.theme,
|
theme: component.theme,
|
||||||
strings: component.strings,
|
strings: component.strings,
|
||||||
|
sharedListsContext: component.sharedViewListsContext,
|
||||||
|
peerId: component.slice.peer.id,
|
||||||
safeInsets: component.safeInsets,
|
safeInsets: component.safeInsets,
|
||||||
storyItem: component.slice.item.storyItem,
|
storyItem: component.slice.item.storyItem,
|
||||||
outerExpansionFraction: outerExpansionFraction,
|
outerExpansionFraction: outerExpansionFraction,
|
||||||
|
@ -4,6 +4,7 @@ import Display
|
|||||||
import ComponentFlow
|
import ComponentFlow
|
||||||
import MultilineTextComponent
|
import MultilineTextComponent
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
|
import Postbox
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import ComponentDisplayAdapters
|
import ComponentDisplayAdapters
|
||||||
import AccountContext
|
import AccountContext
|
||||||
@ -14,6 +15,14 @@ import StoryFooterPanelComponent
|
|||||||
import PeerListItemComponent
|
import PeerListItemComponent
|
||||||
|
|
||||||
final class StoryItemSetViewListComponent: Component {
|
final class StoryItemSetViewListComponent: Component {
|
||||||
|
final class AnimationHint {
|
||||||
|
let synchronous: Bool
|
||||||
|
|
||||||
|
init(synchronous: Bool) {
|
||||||
|
self.synchronous = synchronous
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final class ExternalState {
|
final class ExternalState {
|
||||||
fileprivate(set) var minimizedHeight: CGFloat = 0.0
|
fileprivate(set) var minimizedHeight: CGFloat = 0.0
|
||||||
fileprivate(set) var effectiveHeight: CGFloat = 0.0
|
fileprivate(set) var effectiveHeight: CGFloat = 0.0
|
||||||
@ -22,10 +31,19 @@ final class StoryItemSetViewListComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final class SharedListsContext {
|
||||||
|
var viewLists: [StoryId: EngineStoryViewListContext] = [:]
|
||||||
|
|
||||||
|
init() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let externalState: ExternalState
|
let externalState: ExternalState
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let strings: PresentationStrings
|
let strings: PresentationStrings
|
||||||
|
let sharedListsContext: SharedListsContext
|
||||||
|
let peerId: EnginePeer.Id
|
||||||
let safeInsets: UIEdgeInsets
|
let safeInsets: UIEdgeInsets
|
||||||
let storyItem: EngineStoryItem
|
let storyItem: EngineStoryItem
|
||||||
let outerExpansionFraction: CGFloat
|
let outerExpansionFraction: CGFloat
|
||||||
@ -40,6 +58,8 @@ final class StoryItemSetViewListComponent: Component {
|
|||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
theme: PresentationTheme,
|
theme: PresentationTheme,
|
||||||
strings: PresentationStrings,
|
strings: PresentationStrings,
|
||||||
|
sharedListsContext: SharedListsContext,
|
||||||
|
peerId: EnginePeer.Id,
|
||||||
safeInsets: UIEdgeInsets,
|
safeInsets: UIEdgeInsets,
|
||||||
storyItem: EngineStoryItem,
|
storyItem: EngineStoryItem,
|
||||||
outerExpansionFraction: CGFloat,
|
outerExpansionFraction: CGFloat,
|
||||||
@ -53,6 +73,8 @@ final class StoryItemSetViewListComponent: Component {
|
|||||||
self.context = context
|
self.context = context
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
|
self.sharedListsContext = sharedListsContext
|
||||||
|
self.peerId = peerId
|
||||||
self.safeInsets = safeInsets
|
self.safeInsets = safeInsets
|
||||||
self.storyItem = storyItem
|
self.storyItem = storyItem
|
||||||
self.outerExpansionFraction = outerExpansionFraction
|
self.outerExpansionFraction = outerExpansionFraction
|
||||||
@ -70,6 +92,9 @@ final class StoryItemSetViewListComponent: Component {
|
|||||||
if lhs.strings !== rhs.strings {
|
if lhs.strings !== rhs.strings {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.peerId != rhs.peerId {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.safeInsets != rhs.safeInsets {
|
if lhs.safeInsets != rhs.safeInsets {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -175,7 +200,6 @@ final class StoryItemSetViewListComponent: Component {
|
|||||||
|
|
||||||
private var ignoreScrolling: Bool = false
|
private var ignoreScrolling: Bool = false
|
||||||
|
|
||||||
private var viewList: EngineStoryViewListContext?
|
|
||||||
private var viewListDisposable: Disposable?
|
private var viewListDisposable: Disposable?
|
||||||
private var viewListState: EngineStoryViewListContext.State?
|
private var viewListState: EngineStoryViewListContext.State?
|
||||||
private var requestedLoadMoreToken: EngineStoryViewListContext.LoadMoreToken?
|
private var requestedLoadMoreToken: EngineStoryViewListContext.LoadMoreToken?
|
||||||
@ -495,7 +519,7 @@ final class StoryItemSetViewListComponent: Component {
|
|||||||
self.visiblePlaceholderViews.removeValue(forKey: id)
|
self.visiblePlaceholderViews.removeValue(forKey: id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let viewList = self.viewList, let viewListState = self.viewListState, viewListState.loadMoreToken != nil, visibleBounds.maxY >= self.scrollView.contentSize.height - 200.0 {
|
if let viewList = component.sharedListsContext.viewLists[StoryId(peerId: component.peerId, id: component.storyItem.id)], let viewListState = self.viewListState, viewListState.loadMoreToken != nil, visibleBounds.maxY >= self.scrollView.contentSize.height - 200.0 {
|
||||||
if self.requestedLoadMoreToken != viewListState.loadMoreToken {
|
if self.requestedLoadMoreToken != viewListState.loadMoreToken {
|
||||||
self.requestedLoadMoreToken = viewListState.loadMoreToken
|
self.requestedLoadMoreToken = viewListState.loadMoreToken
|
||||||
viewList.loadMore()
|
viewList.loadMore()
|
||||||
@ -510,6 +534,11 @@ final class StoryItemSetViewListComponent: Component {
|
|||||||
self.component = component
|
self.component = component
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
|
var synchronous = false
|
||||||
|
if let animationHint = transition.userData(AnimationHint.self) {
|
||||||
|
synchronous = animationHint.synchronous
|
||||||
|
}
|
||||||
|
|
||||||
let minimizedHeight = min(availableSize.height, 500.0)
|
let minimizedHeight = min(availableSize.height, 500.0)
|
||||||
|
|
||||||
if themeUpdated {
|
if themeUpdated {
|
||||||
@ -520,24 +549,37 @@ final class StoryItemSetViewListComponent: Component {
|
|||||||
|
|
||||||
if itemUpdated {
|
if itemUpdated {
|
||||||
self.viewListState = nil
|
self.viewListState = nil
|
||||||
self.viewList = nil
|
|
||||||
self.viewListDisposable?.dispose()
|
self.viewListDisposable?.dispose()
|
||||||
|
|
||||||
if let views = component.storyItem.views {
|
if let views = component.storyItem.views {
|
||||||
let viewList = component.context.engine.messages.storyViewList(id: component.storyItem.id, views: views)
|
let viewList: EngineStoryViewListContext
|
||||||
self.viewList = viewList
|
if let current = component.sharedListsContext.viewLists[StoryId(peerId: component.peerId, id: component.storyItem.id)] {
|
||||||
|
viewList = current
|
||||||
|
} else {
|
||||||
|
viewList = component.context.engine.messages.storyViewList(id: component.storyItem.id, views: views)
|
||||||
|
component.sharedListsContext.viewLists[StoryId(peerId: component.peerId, id: component.storyItem.id)] = viewList
|
||||||
|
}
|
||||||
|
|
||||||
var applyState = false
|
var applyState = false
|
||||||
|
var firstTime = true
|
||||||
self.viewListDisposable = (viewList.state
|
self.viewListDisposable = (viewList.state
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] listState in
|
|> deliverOnMainQueue).start(next: { [weak self] listState in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if firstTime {
|
||||||
|
firstTime = false
|
||||||
|
self.ignoreScrolling = true
|
||||||
|
self.scrollView.setContentOffset(CGPoint(), animated: false)
|
||||||
|
self.ignoreScrolling = false
|
||||||
|
}
|
||||||
self.viewListState = listState
|
self.viewListState = listState
|
||||||
if applyState {
|
if applyState {
|
||||||
self.state?.updated(transition: Transition.immediate.withUserData(PeerListItemComponent.TransitionHint(synchronousLoad: true)))
|
self.state?.updated(transition: Transition.immediate.withUserData(PeerListItemComponent.TransitionHint(synchronousLoad: false)))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
applyState = true
|
applyState = true
|
||||||
|
let _ = synchronous
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -611,15 +653,17 @@ final class StoryItemSetViewListComponent: Component {
|
|||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: availableSize.width, height: 200.0)
|
containerSize: CGSize(width: availableSize.width, height: 200.0)
|
||||||
)
|
)
|
||||||
if let navigationPanelView = self.navigationPanel.view {
|
if let navigationPanelView = self.navigationPanel.view as? StoryFooterPanelComponent.View {
|
||||||
if navigationPanelView.superview == nil {
|
if navigationPanelView.superview == nil {
|
||||||
self.addSubview(navigationPanelView)
|
self.addSubview(navigationPanelView)
|
||||||
|
self.insertSubview(navigationPanelView.externalContainerView, belowSubview: self.navigationBarBackground)
|
||||||
}
|
}
|
||||||
|
|
||||||
let expandedNavigationPanelFrame = CGRect(origin: CGPoint(x: navigationBarFrame.minX, y: navigationBarFrame.minY + 4.0), 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)
|
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: dismissFraction))
|
transition.setFrame(view: navigationPanelView, frame: collapsedNavigationPanelFrame.interpolate(to: expandedNavigationPanelFrame, amount: dismissFraction))
|
||||||
|
transition.setFrame(view: navigationPanelView.externalContainerView, frame: collapsedNavigationPanelFrame.interpolate(to: expandedNavigationPanelFrame, amount: dismissFraction))
|
||||||
}
|
}
|
||||||
|
|
||||||
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarFrame.maxY), size: CGSize(width: availableSize.width, height: availableSize.height)))
|
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarFrame.maxY), size: CGSize(width: availableSize.width, height: availableSize.height)))
|
||||||
|
@ -49,7 +49,7 @@ public final class StoryFooterPanelComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class View: UIView {
|
public final class View: UIView {
|
||||||
private let viewStatsButton: HighlightableButton
|
private let viewStatsButton: HighlightTrackingButton
|
||||||
private let viewStatsText = ComponentView<Empty>()
|
private let viewStatsText = ComponentView<Empty>()
|
||||||
private let viewStatsExpandedText = ComponentView<Empty>()
|
private let viewStatsExpandedText = ComponentView<Empty>()
|
||||||
private let deleteButton = ComponentView<Empty>()
|
private let deleteButton = ComponentView<Empty>()
|
||||||
@ -67,18 +67,34 @@ public final class StoryFooterPanelComponent: Component {
|
|||||||
private var uploadProgress: Float = 0.0
|
private var uploadProgress: Float = 0.0
|
||||||
private var uploadProgressDisposable: Disposable?
|
private var uploadProgressDisposable: Disposable?
|
||||||
|
|
||||||
|
public let externalContainerView: UIView
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
self.viewStatsButton = HighlightableButton()
|
self.viewStatsButton = HighlightTrackingButton()
|
||||||
|
|
||||||
self.avatarsContext = AnimatedAvatarSetContext()
|
self.avatarsContext = AnimatedAvatarSetContext()
|
||||||
self.avatarsNode = AnimatedAvatarSetNode()
|
self.avatarsNode = AnimatedAvatarSetNode()
|
||||||
|
|
||||||
|
self.externalContainerView = UIView()
|
||||||
|
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|
||||||
self.avatarsNode.view.isUserInteractionEnabled = false
|
self.avatarsNode.view.isUserInteractionEnabled = false
|
||||||
self.viewStatsButton.addSubview(self.avatarsNode.view)
|
self.externalContainerView.addSubview(self.avatarsNode.view)
|
||||||
self.addSubview(self.viewStatsButton)
|
self.addSubview(self.viewStatsButton)
|
||||||
|
|
||||||
|
self.viewStatsButton.highligthedChanged = { [weak self] highlighted in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if highlighted {
|
||||||
|
self.avatarsNode.view.alpha = 0.7
|
||||||
|
self.viewStatsText.view?.alpha = 0.7
|
||||||
|
} else {
|
||||||
|
self.avatarsNode.layer.animateAlpha(from: 0.7, to: 1.0, duration: 0.2)
|
||||||
|
self.viewStatsText.view?.layer.animateAlpha(from: 0.7, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
self.viewStatsButton.addTarget(self, action: #selector(self.viewStatsPressed), for: .touchUpInside)
|
self.viewStatsButton.addTarget(self, action: #selector(self.viewStatsPressed), for: .touchUpInside)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +240,8 @@ public final class StoryFooterPanelComponent: Component {
|
|||||||
let avatarsSize = self.avatarsNode.update(context: component.context, content: avatarsContent, itemSize: CGSize(width: 30.0, height: 30.0), animated: false, synchronousLoad: true)
|
let avatarsSize = self.avatarsNode.update(context: component.context, content: avatarsContent, itemSize: CGSize(width: 30.0, height: 30.0), animated: false, synchronousLoad: true)
|
||||||
|
|
||||||
let avatarsNodeFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - avatarsSize.height) * 0.5)), size: avatarsSize)
|
let avatarsNodeFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - avatarsSize.height) * 0.5)), size: avatarsSize)
|
||||||
self.avatarsNode.frame = avatarsNodeFrame
|
self.avatarsNode.position = avatarsNodeFrame.center
|
||||||
|
self.avatarsNode.bounds = CGRect(origin: CGPoint(), size: avatarsNodeFrame.size)
|
||||||
transition.setAlpha(view: self.avatarsNode.view, alpha: avatarsAlpha)
|
transition.setAlpha(view: self.avatarsNode.view, alpha: avatarsAlpha)
|
||||||
if !avatarsSize.width.isZero {
|
if !avatarsSize.width.isZero {
|
||||||
leftOffset = avatarsNodeFrame.maxX + avatarSpacing
|
leftOffset = avatarsNodeFrame.maxX + avatarSpacing
|
||||||
@ -269,7 +286,7 @@ public final class StoryFooterPanelComponent: Component {
|
|||||||
if let viewStatsTextView = self.viewStatsText.view {
|
if let viewStatsTextView = self.viewStatsText.view {
|
||||||
if viewStatsTextView.superview == nil {
|
if viewStatsTextView.superview == nil {
|
||||||
viewStatsTextView.isUserInteractionEnabled = false
|
viewStatsTextView.isUserInteractionEnabled = false
|
||||||
self.viewStatsButton.addSubview(viewStatsTextView)
|
self.externalContainerView.addSubview(viewStatsTextView)
|
||||||
}
|
}
|
||||||
transition.setPosition(view: viewStatsTextView, position: viewStatsTextFrame.center)
|
transition.setPosition(view: viewStatsTextView, position: viewStatsTextFrame.center)
|
||||||
transition.setBounds(view: viewStatsTextView, bounds: CGRect(origin: CGPoint(), size: viewStatsTextFrame.size))
|
transition.setBounds(view: viewStatsTextView, bounds: CGRect(origin: CGPoint(), size: viewStatsTextFrame.size))
|
||||||
@ -281,7 +298,7 @@ public final class StoryFooterPanelComponent: Component {
|
|||||||
if let viewStatsExpandedTextView = self.viewStatsExpandedText.view {
|
if let viewStatsExpandedTextView = self.viewStatsExpandedText.view {
|
||||||
if viewStatsExpandedTextView.superview == nil {
|
if viewStatsExpandedTextView.superview == nil {
|
||||||
viewStatsExpandedTextView.isUserInteractionEnabled = false
|
viewStatsExpandedTextView.isUserInteractionEnabled = false
|
||||||
self.viewStatsButton.addSubview(viewStatsExpandedTextView)
|
self.addSubview(viewStatsExpandedTextView)
|
||||||
}
|
}
|
||||||
transition.setPosition(view: viewStatsExpandedTextView, position: viewStatsExpandedTextFrame.center)
|
transition.setPosition(view: viewStatsExpandedTextView, position: viewStatsExpandedTextFrame.center)
|
||||||
transition.setBounds(view: viewStatsExpandedTextView, bounds: CGRect(origin: CGPoint(), size: viewStatsExpandedTextFrame.size))
|
transition.setBounds(view: viewStatsExpandedTextView, bounds: CGRect(origin: CGPoint(), size: viewStatsExpandedTextFrame.size))
|
||||||
@ -313,7 +330,7 @@ public final class StoryFooterPanelComponent: Component {
|
|||||||
)
|
)
|
||||||
if let deleteButtonView = self.deleteButton.view {
|
if let deleteButtonView = self.deleteButton.view {
|
||||||
if deleteButtonView.superview == nil {
|
if deleteButtonView.superview == nil {
|
||||||
self.addSubview(deleteButtonView)
|
self.externalContainerView.addSubview(deleteButtonView)
|
||||||
}
|
}
|
||||||
transition.setFrame(view: deleteButtonView, frame: CGRect(origin: CGPoint(x: rightContentOffset - deleteButtonSize.width, y: floor((size.height - deleteButtonSize.height) * 0.5)), size: deleteButtonSize))
|
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
|
rightContentOffset -= deleteButtonSize.width + 8.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user