mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Channel story upload UI
This commit is contained in:
parent
f4ed424c7e
commit
520ba51f15
@ -867,15 +867,18 @@ public final class AvatarNode: ASDisplayNode {
|
|||||||
public var totalCount: Int
|
public var totalCount: Int
|
||||||
public var unseenCount: Int
|
public var unseenCount: Int
|
||||||
public var hasUnseenCloseFriendsItems: Bool
|
public var hasUnseenCloseFriendsItems: Bool
|
||||||
|
public var progress: Float?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
totalCount: Int,
|
totalCount: Int,
|
||||||
unseenCount: Int,
|
unseenCount: Int,
|
||||||
hasUnseenCloseFriendsItems: Bool
|
hasUnseenCloseFriendsItems: Bool,
|
||||||
|
progress: Float? = nil
|
||||||
) {
|
) {
|
||||||
self.totalCount = totalCount
|
self.totalCount = totalCount
|
||||||
self.unseenCount = unseenCount
|
self.unseenCount = unseenCount
|
||||||
self.hasUnseenCloseFriendsItems = hasUnseenCloseFriendsItems
|
self.hasUnseenCloseFriendsItems = hasUnseenCloseFriendsItems
|
||||||
|
self.progress = progress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1135,6 +1138,12 @@ public final class AvatarNode: ASDisplayNode {
|
|||||||
storyIndicator = ComponentView()
|
storyIndicator = ComponentView()
|
||||||
self.storyIndicator = storyIndicator
|
self.storyIndicator = storyIndicator
|
||||||
}
|
}
|
||||||
|
var mappedProgress: AvatarStoryIndicatorComponent.Progress?
|
||||||
|
if let value = storyStats.progress {
|
||||||
|
mappedProgress = .definite(value)
|
||||||
|
} else if !self.loadingStatuses.isEmpty {
|
||||||
|
mappedProgress = .indefinite
|
||||||
|
}
|
||||||
let _ = storyIndicator.update(
|
let _ = storyIndicator.update(
|
||||||
transition: indicatorTransition,
|
transition: indicatorTransition,
|
||||||
component: AnyComponent(AvatarStoryIndicatorComponent(
|
component: AnyComponent(AvatarStoryIndicatorComponent(
|
||||||
@ -1151,7 +1160,7 @@ public final class AvatarNode: ASDisplayNode {
|
|||||||
totalCount: storyStats.totalCount,
|
totalCount: storyStats.totalCount,
|
||||||
unseenCount: storyStats.unseenCount
|
unseenCount: storyStats.unseenCount
|
||||||
),
|
),
|
||||||
displayProgress: !self.loadingStatuses.isEmpty
|
progress: mappedProgress
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: indicatorSize
|
containerSize: indicatorSize
|
||||||
|
@ -2724,6 +2724,34 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
}
|
}
|
||||||
destinationView.isHidden = true
|
destinationView.isHidden = true
|
||||||
|
|
||||||
|
if let destinationTransitionView {
|
||||||
|
destinationTransitionView.layer.anchorPoint = CGPoint(x: 0.0, y: 0.5)
|
||||||
|
let snapshotScale = self.previewContainerView.bounds.width / destinationTransitionView.frame.width
|
||||||
|
destinationTransitionView.center = CGPoint(x: 0.0, y: self.previewContainerView.bounds.height / 2.0)
|
||||||
|
destinationTransitionView.layer.transform = CATransform3DMakeScale(snapshotScale, snapshotScale, 1.0)
|
||||||
|
|
||||||
|
destinationTransitionView.alpha = 0.0
|
||||||
|
Queue.mainQueue().after(0.15) {
|
||||||
|
destinationTransitionView.alpha = 1.0
|
||||||
|
destinationTransitionView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.previewContainerView.addSubview(destinationTransitionView)
|
||||||
|
destinationSnapshotView = destinationTransitionView
|
||||||
|
}
|
||||||
|
} else if let destinationNode = destinationView.asyncdisplaykit_node as? AvatarNode.ContentNode {
|
||||||
|
let destinationTransitionView: UIView?
|
||||||
|
if let image = destinationNode.unroundedImage {
|
||||||
|
destinationTransitionView = UIImageView(image: image)
|
||||||
|
destinationTransitionView?.bounds = destinationNode.bounds
|
||||||
|
destinationTransitionView?.layer.cornerRadius = destinationNode.bounds.width / 2.0
|
||||||
|
} else if let snapshotView = destinationView.snapshotView(afterScreenUpdates: false) {
|
||||||
|
destinationTransitionView = snapshotView
|
||||||
|
} else {
|
||||||
|
destinationTransitionView = nil
|
||||||
|
}
|
||||||
|
destinationView.isHidden = true
|
||||||
|
|
||||||
if let destinationTransitionView {
|
if let destinationTransitionView {
|
||||||
destinationTransitionView.layer.anchorPoint = CGPoint(x: 0.0, y: 0.5)
|
destinationTransitionView.layer.anchorPoint = CGPoint(x: 0.0, y: 0.5)
|
||||||
let snapshotScale = self.previewContainerView.bounds.width / destinationTransitionView.frame.width
|
let snapshotScale = self.previewContainerView.bounds.width / destinationTransitionView.frame.width
|
||||||
|
@ -38,13 +38,18 @@ public final class AvatarStoryIndicatorComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Progress: Equatable {
|
||||||
|
case indefinite
|
||||||
|
case definite(Float)
|
||||||
|
}
|
||||||
|
|
||||||
public let hasUnseen: Bool
|
public let hasUnseen: Bool
|
||||||
public let hasUnseenCloseFriendsItems: Bool
|
public let hasUnseenCloseFriendsItems: Bool
|
||||||
public let colors: Colors
|
public let colors: Colors
|
||||||
public let activeLineWidth: CGFloat
|
public let activeLineWidth: CGFloat
|
||||||
public let inactiveLineWidth: CGFloat
|
public let inactiveLineWidth: CGFloat
|
||||||
public let counters: Counters?
|
public let counters: Counters?
|
||||||
public let displayProgress: Bool
|
public let progress: Progress?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
hasUnseen: Bool,
|
hasUnseen: Bool,
|
||||||
@ -53,7 +58,7 @@ public final class AvatarStoryIndicatorComponent: Component {
|
|||||||
activeLineWidth: CGFloat,
|
activeLineWidth: CGFloat,
|
||||||
inactiveLineWidth: CGFloat,
|
inactiveLineWidth: CGFloat,
|
||||||
counters: Counters?,
|
counters: Counters?,
|
||||||
displayProgress: Bool = false
|
progress: Progress? = nil
|
||||||
) {
|
) {
|
||||||
self.hasUnseen = hasUnseen
|
self.hasUnseen = hasUnseen
|
||||||
self.hasUnseenCloseFriendsItems = hasUnseenCloseFriendsItems
|
self.hasUnseenCloseFriendsItems = hasUnseenCloseFriendsItems
|
||||||
@ -61,7 +66,7 @@ public final class AvatarStoryIndicatorComponent: Component {
|
|||||||
self.activeLineWidth = activeLineWidth
|
self.activeLineWidth = activeLineWidth
|
||||||
self.inactiveLineWidth = inactiveLineWidth
|
self.inactiveLineWidth = inactiveLineWidth
|
||||||
self.counters = counters
|
self.counters = counters
|
||||||
self.displayProgress = displayProgress
|
self.progress = progress
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: AvatarStoryIndicatorComponent, rhs: AvatarStoryIndicatorComponent) -> Bool {
|
public static func ==(lhs: AvatarStoryIndicatorComponent, rhs: AvatarStoryIndicatorComponent) -> Bool {
|
||||||
@ -83,7 +88,7 @@ public final class AvatarStoryIndicatorComponent: Component {
|
|||||||
if lhs.counters != rhs.counters {
|
if lhs.counters != rhs.counters {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if lhs.displayProgress != rhs.displayProgress {
|
if lhs.progress != rhs.progress {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -364,7 +369,7 @@ public final class AvatarStoryIndicatorComponent: Component {
|
|||||||
transition.setFrame(view: self.indicatorView, frame: indicatorFrame)
|
transition.setFrame(view: self.indicatorView, frame: indicatorFrame)
|
||||||
|
|
||||||
let progressTransition = Transition(animation: .curve(duration: 0.3, curve: .easeInOut))
|
let progressTransition = Transition(animation: .curve(duration: 0.3, curve: .easeInOut))
|
||||||
if component.displayProgress {
|
if let progress = component.progress {
|
||||||
let colorLayer: SimpleGradientLayer
|
let colorLayer: SimpleGradientLayer
|
||||||
if let current = self.colorLayer {
|
if let current = self.colorLayer {
|
||||||
colorLayer = current
|
colorLayer = current
|
||||||
@ -379,13 +384,12 @@ public final class AvatarStoryIndicatorComponent: Component {
|
|||||||
progressTransition.setAlpha(layer: colorLayer, alpha: 1.0)
|
progressTransition.setAlpha(layer: colorLayer, alpha: 1.0)
|
||||||
|
|
||||||
let colors: [CGColor] = activeColors
|
let colors: [CGColor] = activeColors
|
||||||
/*if component.hasUnseen {
|
let lineWidth: CGFloat
|
||||||
colors = activeColors
|
if case .definite = progress {
|
||||||
|
lineWidth = component.activeLineWidth
|
||||||
} else {
|
} else {
|
||||||
colors = inactiveColors
|
lineWidth = component.hasUnseen ? component.activeLineWidth : component.inactiveLineWidth
|
||||||
}*/
|
}
|
||||||
|
|
||||||
let lineWidth: CGFloat = component.hasUnseen ? component.activeLineWidth : component.inactiveLineWidth
|
|
||||||
|
|
||||||
colorLayer.colors = colors
|
colorLayer.colors = colors
|
||||||
colorLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
|
colorLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
|
||||||
@ -402,7 +406,16 @@ public final class AvatarStoryIndicatorComponent: Component {
|
|||||||
|
|
||||||
colorLayer.frame = indicatorFrame
|
colorLayer.frame = indicatorFrame
|
||||||
progressLayer.frame = CGRect(origin: CGPoint(), size: indicatorFrame.size)
|
progressLayer.frame = CGRect(origin: CGPoint(), size: indicatorFrame.size)
|
||||||
progressLayer.update(size: indicatorFrame.size, radius: radius, lineWidth: lineWidth, value: .indefinite, transition: .immediate)
|
|
||||||
|
let mappedProgress: ProgressLayer.Value
|
||||||
|
switch progress {
|
||||||
|
case .indefinite:
|
||||||
|
mappedProgress = .indefinite
|
||||||
|
case let .definite(value):
|
||||||
|
mappedProgress = .progress(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
progressLayer.update(size: indicatorFrame.size, radius: radius, lineWidth: lineWidth, value: mappedProgress, transition: .immediate)
|
||||||
} else {
|
} else {
|
||||||
progressTransition.setAlpha(view: self.indicatorView, alpha: 1.0)
|
progressTransition.setAlpha(view: self.indicatorView, alpha: 1.0)
|
||||||
|
|
||||||
|
@ -424,6 +424,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
private let playbackStartDisposable = MetaDisposable()
|
private let playbackStartDisposable = MetaDisposable()
|
||||||
|
|
||||||
var storyData: (totalCount: Int, unseenCount: Int, hasUnseenCloseFriends: Bool)?
|
var storyData: (totalCount: Int, unseenCount: Int, hasUnseenCloseFriends: Bool)?
|
||||||
|
var storyProgress: Float?
|
||||||
|
|
||||||
init(context: AccountContext) {
|
init(context: AccountContext) {
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -462,13 +463,23 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
|
|||||||
theme.list.controlSecondaryColor,
|
theme.list.controlSecondaryColor,
|
||||||
theme.list.controlSecondaryColor
|
theme.list.controlSecondaryColor
|
||||||
]
|
]
|
||||||
self.avatarNode.setStoryStats(storyStats: self.storyData.flatMap { storyData in
|
var storyStats: AvatarNode.StoryStats?
|
||||||
return AvatarNode.StoryStats(
|
if let storyData = self.storyData {
|
||||||
|
storyStats = AvatarNode.StoryStats(
|
||||||
totalCount: storyData.totalCount,
|
totalCount: storyData.totalCount,
|
||||||
unseenCount: storyData.unseenCount,
|
unseenCount: storyData.unseenCount,
|
||||||
hasUnseenCloseFriendsItems: storyData.hasUnseenCloseFriends
|
hasUnseenCloseFriendsItems: storyData.hasUnseenCloseFriends,
|
||||||
|
progress: self.storyProgress
|
||||||
)
|
)
|
||||||
}, presentationParams: AvatarNode.StoryPresentationParams(
|
} else if let storyProgress = self.storyProgress {
|
||||||
|
storyStats = AvatarNode.StoryStats(
|
||||||
|
totalCount: 1,
|
||||||
|
unseenCount: 1,
|
||||||
|
hasUnseenCloseFriendsItems: false,
|
||||||
|
progress: storyProgress
|
||||||
|
)
|
||||||
|
}
|
||||||
|
self.avatarNode.setStoryStats(storyStats: storyStats, presentationParams: AvatarNode.StoryPresentationParams(
|
||||||
colors: colors,
|
colors: colors,
|
||||||
lineWidth: 3.0,
|
lineWidth: 3.0,
|
||||||
inactiveLineWidth: 1.5
|
inactiveLineWidth: 1.5
|
||||||
|
@ -2169,6 +2169,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
private var expiringStoryList: PeerExpiringStoryListContext?
|
private var expiringStoryList: PeerExpiringStoryListContext?
|
||||||
private var expiringStoryListState: PeerExpiringStoryListContext.State?
|
private var expiringStoryListState: PeerExpiringStoryListContext.State?
|
||||||
private var expiringStoryListDisposable: Disposable?
|
private var expiringStoryListDisposable: Disposable?
|
||||||
|
private var storyUploadProgressDisposable: Disposable?
|
||||||
private var postingAvailabilityDisposable: Disposable?
|
private var postingAvailabilityDisposable: Disposable?
|
||||||
|
|
||||||
private let storiesReady = ValuePromise<Bool>(true, ignoreRepeated: true)
|
private let storiesReady = ValuePromise<Bool>(true, ignoreRepeated: true)
|
||||||
@ -3936,6 +3937,24 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
self.storiesReady.set(false)
|
self.storiesReady.set(false)
|
||||||
let expiringStoryList = PeerExpiringStoryListContext(account: context.account, peerId: peerId)
|
let expiringStoryList = PeerExpiringStoryListContext(account: context.account, peerId: peerId)
|
||||||
self.expiringStoryList = expiringStoryList
|
self.expiringStoryList = expiringStoryList
|
||||||
|
self.storyUploadProgressDisposable = (context.engine.messages.allStoriesUploadProgress()
|
||||||
|
|> map { value -> Float? in
|
||||||
|
return value[peerId]
|
||||||
|
}
|
||||||
|
|> distinctUntilChanged).start(next: { [weak self] value in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var mappedValue = value
|
||||||
|
if let value {
|
||||||
|
mappedValue = max(0.027, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.headerNode.avatarListNode.avatarContainerNode.storyProgress != mappedValue {
|
||||||
|
self.headerNode.avatarListNode.avatarContainerNode.storyProgress = mappedValue
|
||||||
|
self.headerNode.avatarListNode.avatarContainerNode.updateStoryView(transition: .immediate, theme: self.presentationData.theme)
|
||||||
|
}
|
||||||
|
})
|
||||||
self.expiringStoryListDisposable = (combineLatest(queue: .mainQueue(),
|
self.expiringStoryListDisposable = (combineLatest(queue: .mainQueue(),
|
||||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)),
|
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)),
|
||||||
expiringStoryList.state
|
expiringStoryList.state
|
||||||
@ -8269,7 +8288,14 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
private func openPostStory() {
|
private func openPostStory() {
|
||||||
self.postingAvailabilityDisposable?.dispose()
|
self.postingAvailabilityDisposable?.dispose()
|
||||||
|
|
||||||
self.postingAvailabilityDisposable = (self.context.engine.messages.checkStoriesUploadAvailability(target: .peer(self.peerId))
|
let canPostStatus: Signal<StoriesUploadAvailability, NoError>
|
||||||
|
#if DEBUG
|
||||||
|
canPostStatus = .single(.available)
|
||||||
|
#else
|
||||||
|
canPostStatus = self.context.engine.messages.checkStoriesUploadAvailability(target: .peer(self.peerId))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
self.postingAvailabilityDisposable = (canPostStatus
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
@ -8338,15 +8364,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
let _ = self
|
|
||||||
|
|
||||||
/*if let transitionView = self.headerNode.navigationButtonContainer.rightButtonNodes[.postStory]?.view {
|
if !self.headerNode.isAvatarExpanded {
|
||||||
|
let transitionView = self.headerNode.avatarListNode.avatarContainerNode.avatarNode.contentNode.view
|
||||||
return StoryCameraTransitionOut(
|
return StoryCameraTransitionOut(
|
||||||
destinationView: transitionView,
|
destinationView: transitionView,
|
||||||
destinationRect: transitionView.bounds,
|
destinationRect: transitionView.bounds,
|
||||||
destinationCornerRadius: transitionView.bounds.height * 0.5
|
destinationCornerRadius: transitionView.bounds.height * 0.5
|
||||||
)
|
)
|
||||||
}*/
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user