Merge commit 'c3f2fa5bc36d073853033b870b53f4460ba852eb'

This commit is contained in:
Ali 2020-04-18 16:52:15 +04:00
commit 38b71bbc08
6 changed files with 169 additions and 149 deletions

View File

@ -379,11 +379,11 @@ static const CGFloat outerCircleMinScale = innerCircleRadius / outerCircleRadius
_innerCircleView.alpha = 0.0f; _innerCircleView.alpha = 0.0f;
[[_presentation view] addSubview:_innerCircleView]; [[_presentation view] addSubview:_innerCircleView];
if ([_delegate respondsToSelector:@selector(micButtonDecoration)]) { // if ([_delegate respondsToSelector:@selector(micButtonDecoration)]) {
UIView<TGModernConversationInputMicButtonDecoration> *decoration = [_delegate micButtonDecoration]; // UIView<TGModernConversationInputMicButtonDecoration> *decoration = [_delegate micButtonDecoration];
_decoration = decoration; // _decoration = decoration;
[[_presentation view] addSubview:_decoration]; // [[_presentation view] addSubview:_decoration];
} // }
_outerCircleView = [[UIImageView alloc] initWithImage:[self outerCircleImage:self.pallete != nil ? self.pallete.buttonColor : TGAccentColor()]]; _outerCircleView = [[UIImageView alloc] initWithImage:[self outerCircleImage:self.pallete != nil ? self.pallete.buttonColor : TGAccentColor()]];
_outerCircleView.alpha = 0.0f; _outerCircleView.alpha = 0.0f;

View File

@ -59,14 +59,14 @@ public final class ManagedAnimationState {
} }
} }
public struct ManagedAnimationFrameRange: Equatable { public enum ManagedAnimationFramePosition {
var startFrame: Int case start
var endFrame: Int case end
}
public init(startFrame: Int, endFrame: Int) { public enum ManagedAnimationFrameRange: Equatable {
self.startFrame = startFrame case range(startFrame: Int, endFrame: Int)
self.endFrame = endFrame case still(ManagedAnimationFramePosition)
}
} }
public enum ManagedAnimationSource: Equatable { public enum ManagedAnimationSource: Equatable {
@ -111,11 +111,11 @@ public enum ManagedAnimationSource: Equatable {
public struct ManagedAnimationItem: Equatable { public struct ManagedAnimationItem: Equatable {
public let source: ManagedAnimationSource public let source: ManagedAnimationSource
var frames: ManagedAnimationFrameRange var frames: ManagedAnimationFrameRange?
var duration: Double var duration: Double?
var loop: Bool var loop: Bool
public init(source: ManagedAnimationSource, frames: ManagedAnimationFrameRange, duration: Double, loop: Bool = false) { public init(source: ManagedAnimationSource, frames: ManagedAnimationFrameRange? = nil, duration: Double? = nil, loop: Bool = false) {
self.source = source self.source = source
self.frames = frames self.frames = frames
self.duration = duration self.duration = duration
@ -195,17 +195,42 @@ open class ManagedAnimationNode: ASDisplayNode {
guard let state = self.state else { guard let state = self.state else {
return return
} }
let timestamp = CACurrentMediaTime()
let fps = state.fps let startFrame: Int
let frameRange = state.item.frames let endFrame: Int
let duration: Double
if let frames = state.item.frames {
switch frames {
case let .range(start, end):
startFrame = start
endFrame = end
case let .still(position):
switch position {
case .start:
startFrame = 0
endFrame = 0
case .end:
startFrame = state.frameCount
endFrame = state.frameCount
}
}
} else {
startFrame = 0
endFrame = state.frameCount
}
if let durationValue = state.item.duration {
duration = durationValue
} else {
let fps: Double = state.fps > 0 ? state.fps : 60
duration = Double(state.frameCount) / fps
}
let duration: Double = state.item.duration
var t = state.relativeTime / duration var t = state.relativeTime / duration
t = max(0.0, t) t = max(0.0, t)
t = min(1.0, t) t = min(1.0, t)
//print("\(t) \(state.item.name)") //print("\(t) \(state.item.name)")
let frameOffset = Int(Double(frameRange.startFrame) * (1.0 - t) + Double(frameRange.endFrame) * t) let frameOffset = Int(Double(startFrame) * (1.0 - t) + Double(endFrame) * t)
let lowerBound: Int = 0 let lowerBound: Int = 0
let upperBound = state.frameCount - 1 let upperBound = state.frameCount - 1
let frameIndex = max(lowerBound, min(upperBound, frameOffset)) let frameIndex = max(lowerBound, min(upperBound, frameOffset))

View File

@ -28,7 +28,7 @@ final class ManagedMonkeyAnimationNode: ManagedAnimationNode {
init() { init() {
super.init(size: CGSize(width: 136.0, height: 136.0)) super.init(size: CGSize(width: 136.0, height: 136.0))
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 0), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle"), frames: .range(startFrame: 0, endFrame: 0), duration: 0.3))
} }
deinit { deinit {
@ -68,12 +68,12 @@ final class ManagedMonkeyAnimationNode: ManagedAnimationNode {
private func enqueueIdle(_ idle: ManagedMonkeyAnimationIdle) { private func enqueueIdle(_ idle: ManagedMonkeyAnimationIdle) {
switch idle { switch idle {
case .still: case .still:
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 0), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle"), frames: .range(startFrame: 0, endFrame: 0), duration: 0.3))
case .blink: case .blink:
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle1"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 30), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle1"), frames: .range(startFrame: 0, endFrame: 30), duration: 0.3))
case .ear: case .ear:
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle2"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 30), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle2"), frames: .range(startFrame: 0, endFrame: 30), duration: 0.3))
//self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 179), duration: 3.0)) //self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle"), frames: .range(startFrame: 0, endFrame: 179), duration: 3.0))
} }
} }
@ -89,7 +89,7 @@ final class ManagedMonkeyAnimationNode: ManagedAnimationNode {
let upperBound = 160 let upperBound = 160
let frameIndex = lowerBound + Int(value * CGFloat(upperBound - lowerBound)) let frameIndex = lowerBound + Int(value * CGFloat(upperBound - lowerBound))
if let state = self.state, state.item.source == .local("TwoFactorSetupMonkeyTracking") { if let state = self.state, state.item.source == .local("TwoFactorSetupMonkeyTracking") {
let item = ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyTracking"), frames: ManagedAnimationFrameRange(startFrame: state.frameIndex ?? 0, endFrame: frameIndex), duration: 0.3) let item = ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyTracking"), frames: .range(startFrame: state.frameIndex ?? 0, endFrame: frameIndex), duration: 0.3)
self.state = ManagedAnimationState(displaySize: self.intrinsicSize, item: item, current: state) self.state = ManagedAnimationState(displaySize: self.intrinsicSize, item: item, current: state)
self.didTryAdvancingState = false self.didTryAdvancingState = false
self.updateAnimation() self.updateAnimation()
@ -97,13 +97,13 @@ final class ManagedMonkeyAnimationNode: ManagedAnimationNode {
self.trackStack = self.trackStack.filter { self.trackStack = self.trackStack.filter {
$0.source != .local("TwoFactorSetupMonkeyTracking") $0.source != .local("TwoFactorSetupMonkeyTracking")
} }
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyTracking"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: frameIndex), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyTracking"), frames: .range(startFrame: 0, endFrame: frameIndex), duration: 0.3))
} }
} }
func enqueueClearTracking() { func enqueueClearTracking() {
if let state = self.state, state.item.source == .local("TwoFactorSetupMonkeyTracking") { if let state = self.state, state.item.source == .local("TwoFactorSetupMonkeyTracking") {
let item = ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyTracking"), frames: ManagedAnimationFrameRange(startFrame: state.frameIndex ?? 0, endFrame: 0), duration: 0.3) let item = ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyTracking"), frames: .range(startFrame: state.frameIndex ?? 0, endFrame: 0), duration: 0.3)
self.state = ManagedAnimationState(displaySize: self.intrinsicSize, item: item, current: state) self.state = ManagedAnimationState(displaySize: self.intrinsicSize, item: item, current: state)
self.didTryAdvancingState = false self.didTryAdvancingState = false
self.updateAnimation() self.updateAnimation()
@ -116,50 +116,50 @@ final class ManagedMonkeyAnimationNode: ManagedAnimationNode {
case let .idle(idle): case let .idle(idle):
self.enqueueIdle(idle) self.enqueueIdle(idle)
case .eyesClosed: case .eyesClosed:
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyClose"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 41), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyClose"), frames: .range(startFrame: 0, endFrame: 41), duration: 0.3))
case .peeking: case .peeking:
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyCloseAndPeek"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 41), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyCloseAndPeek"), frames: .range(startFrame: 0, endFrame: 41), duration: 0.3))
case let .tracking(value): case let .tracking(value):
enqueueTracking(value) enqueueTracking(value)
} }
case .eyesClosed: case .eyesClosed:
switch monkeyState { switch monkeyState {
case let .idle(idle): case let .idle(idle):
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyClose"), frames: ManagedAnimationFrameRange(startFrame: 41, endFrame: 0), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyClose"), frames: .range(startFrame: 41, endFrame: 0), duration: 0.3))
self.enqueueIdle(idle) self.enqueueIdle(idle)
case .eyesClosed: case .eyesClosed:
break break
case .peeking: case .peeking:
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyPeek"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 14), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyPeek"), frames: .range(startFrame: 0, endFrame: 14), duration: 0.3))
case let .tracking(value): case let .tracking(value):
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyClose"), frames: ManagedAnimationFrameRange(startFrame: 41, endFrame: 0), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyClose"), frames: .range(startFrame: 41, endFrame: 0), duration: 0.3))
enqueueTracking(value) enqueueTracking(value)
} }
case .peeking: case .peeking:
switch monkeyState { switch monkeyState {
case let .idle(idle): case let .idle(idle):
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyCloseAndPeek"), frames: ManagedAnimationFrameRange(startFrame: 41, endFrame: 0), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyCloseAndPeek"), frames: .range(startFrame: 41, endFrame: 0), duration: 0.3))
self.enqueueIdle(idle) self.enqueueIdle(idle)
case .eyesClosed: case .eyesClosed:
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyPeek"), frames: ManagedAnimationFrameRange(startFrame: 14, endFrame: 0), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyPeek"), frames: .range(startFrame: 14, endFrame: 0), duration: 0.3))
case .peeking: case .peeking:
break break
case let .tracking(value): case let .tracking(value):
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyCloseAndPeek"), frames: ManagedAnimationFrameRange(startFrame: 41, endFrame: 0), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyCloseAndPeek"), frames: .range(startFrame: 41, endFrame: 0), duration: 0.3))
enqueueTracking(value) enqueueTracking(value)
} }
case let .tracking(currentValue): case let .tracking(currentValue):
switch monkeyState { switch monkeyState {
case let .idle(idle): case let .idle(idle):
enqueueClearTracking() enqueueClearTracking()
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 0), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle"), frames: .range(startFrame: 0, endFrame: 0), duration: 0.3))
self.enqueueIdle(idle) self.enqueueIdle(idle)
case .eyesClosed: case .eyesClosed:
enqueueClearTracking() enqueueClearTracking()
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyClose"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 41), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyClose"), frames: .range(startFrame: 0, endFrame: 41), duration: 0.3))
case .peeking: case .peeking:
enqueueClearTracking() enqueueClearTracking()
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyCloseAndPeek"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 41), duration: 0.3)) self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyCloseAndPeek"), frames: .range(startFrame: 0, endFrame: 41), duration: 0.3))
case let .tracking(value): case let .tracking(value):
if abs(currentValue - value) > CGFloat.ulpOfOne { if abs(currentValue - value) > CGFloat.ulpOfOne {
enqueueTracking(value) enqueueTracking(value)

View File

@ -56,6 +56,26 @@ private struct ChatControllerNodeDerivedLayoutState {
var upperInputPositionBound: CGFloat? var upperInputPositionBound: CGFloat?
} }
public struct InteractiveEmojiConfiguration {
static var defaultValue: InteractiveEmojiConfiguration {
return InteractiveEmojiConfiguration(emojis: [])
}
public let emojis: [String]
fileprivate init(emojis: [String]) {
self.emojis = emojis
}
static func with(appConfiguration: AppConfiguration) -> InteractiveEmojiConfiguration {
if let data = appConfiguration.data, let value = data["emojies_send_dice"] as? [String] {
return InteractiveEmojiConfiguration(emojis: value)
} else {
return .defaultValue
}
}
}
class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let context: AccountContext let context: AccountContext
let chatLocation: ChatLocation let chatLocation: ChatLocation
@ -77,7 +97,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} }
let backgroundNode: WallpaperBackgroundNode let backgroundNode: WallpaperBackgroundNode
let backgroundDisposable = MetaDisposable() let backgroundImageDisposable = MetaDisposable()
let historyNode: ChatHistoryListNode let historyNode: ChatHistoryListNode
let reactionContainerNode: ReactionSelectionParentNode let reactionContainerNode: ReactionSelectionParentNode
let historyNodeContainer: ASDisplayNode let historyNodeContainer: ASDisplayNode
@ -129,6 +149,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
var chatPresentationInterfaceState: ChatPresentationInterfaceState var chatPresentationInterfaceState: ChatPresentationInterfaceState
var automaticMediaDownloadSettings: MediaAutoDownloadSettings var automaticMediaDownloadSettings: MediaAutoDownloadSettings
private var interactiveEmojis: [String] = []
private var interactiveEmojisDisposable: Disposable?
private let selectedMessagesPromise = Promise<Set<MessageId>?>(nil) private let selectedMessagesPromise = Promise<Set<MessageId>?>(nil)
var selectedMessages: Set<MessageId>? { var selectedMessages: Set<MessageId>? {
didSet { didSet {
@ -288,11 +311,24 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} }
} }
self.backgroundDisposable.set(chatControllerBackgroundImageSignal(wallpaper: chatPresentationInterfaceState.chatWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, accountMediaBox: context.account.postbox.mediaBox).start(next: { [weak self] image in self.backgroundImageDisposable.set(chatControllerBackgroundImageSignal(wallpaper: chatPresentationInterfaceState.chatWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, accountMediaBox: context.account.postbox.mediaBox).start(next: { [weak self] image in
if let strongSelf = self, let (image, final) = image { if let strongSelf = self, let (image, _) = image {
strongSelf.backgroundNode.image = image strongSelf.backgroundNode.image = image
} }
})) }))
self.interactiveEmojisDisposable = (self.context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|> map { preferencesView -> [String] in
let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue
let configuration = InteractiveEmojiConfiguration.with(appConfiguration: appConfiguration)
return configuration.emojis
}
|> deliverOnMainQueue).start(next: { [weak self] emojis in
if let strongSelf = self {
strongSelf.interactiveEmojis = emojis
}
})
if case .gradient = chatPresentationInterfaceState.chatWallpaper { if case .gradient = chatPresentationInterfaceState.chatWallpaper {
self.backgroundNode.imageContentMode = .scaleToFill self.backgroundNode.imageContentMode = .scaleToFill
} else { } else {
@ -350,6 +386,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} }
deinit { deinit {
self.backgroundImageDisposable.dispose()
self.interactiveEmojisDisposable?.dispose()
self.openStickersDisposable?.dispose() self.openStickersDisposable?.dispose()
self.displayVideoUnmuteTipDisposable?.dispose() self.displayVideoUnmuteTipDisposable?.dispose()
} }
@ -1468,7 +1506,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let themeUpdated = self.chatPresentationInterfaceState.theme !== chatPresentationInterfaceState.theme let themeUpdated = self.chatPresentationInterfaceState.theme !== chatPresentationInterfaceState.theme
if self.chatPresentationInterfaceState.chatWallpaper != chatPresentationInterfaceState.chatWallpaper { if self.chatPresentationInterfaceState.chatWallpaper != chatPresentationInterfaceState.chatWallpaper {
self.backgroundDisposable.set(chatControllerBackgroundImageSignal(wallpaper: chatPresentationInterfaceState.chatWallpaper, mediaBox: self.context.sharedContext.accountManager.mediaBox, accountMediaBox: self.context.account.postbox.mediaBox).start(next: { [weak self] image in self.backgroundImageDisposable.set(chatControllerBackgroundImageSignal(wallpaper: chatPresentationInterfaceState.chatWallpaper, mediaBox: self.context.sharedContext.accountManager.mediaBox, accountMediaBox: self.context.account.postbox.mediaBox).start(next: { [weak self] image in
if let strongSelf = self, let (image, final) = image { if let strongSelf = self, let (image, final) = image {
strongSelf.backgroundNode.image = image strongSelf.backgroundNode.image = image
} }
@ -2261,7 +2299,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let effectiveInputText = effectivePresentationInterfaceState.interfaceState.composeInputState.inputText let effectiveInputText = effectivePresentationInterfaceState.interfaceState.composeInputState.inputText
let trimmedInputText = effectiveInputText.string.trimmingCharacters(in: .whitespacesAndNewlines) let trimmedInputText = effectiveInputText.string.trimmingCharacters(in: .whitespacesAndNewlines)
if case let .peer(peerId) = effectivePresentationInterfaceState.chatLocation, peerId.namespace != Namespaces.Peer.SecretChat, ["🎲", "🎯"].contains(trimmedInputText) { if case let .peer(peerId) = effectivePresentationInterfaceState.chatLocation, peerId.namespace != Namespaces.Peer.SecretChat, self.interactiveEmojis.contains(trimmedInputText) {
messages.append(.message(text: "", attributes: [], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: trimmedInputText)), replyToMessageId: self.chatPresentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil)) messages.append(.message(text: "", attributes: [], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: trimmedInputText)), replyToMessageId: self.chatPresentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil))
} else { } else {
let inputText = convertMarkdownToAttributes(effectiveInputText) let inputText = convertMarkdownToAttributes(effectiveInputText)

View File

@ -14,14 +14,57 @@ enum ManagedDiceAnimationState: Equatable {
case value(Int32, Bool) case value(Int32, Bool)
} }
private func rollingAnimationItem(emoji: String) -> ManagedAnimationItem? { private func animationItem(account: Account, emojis: Signal<[TelegramMediaFile], NoError>, emoji: String, value: Int32?, immediate: Bool = false, roll: Bool = false, loop: Bool = false) -> Signal<ManagedAnimationItem?, NoError> {
return emojis
|> mapToSignal { diceEmojis -> Signal<ManagedAnimationItem?, NoError> in
if let value = value, value >= diceEmojis.count {
return .complete()
}
let file = diceEmojis[Int(value ?? 0)]
if let _ = account.postbox.mediaBox.completedResourcePath(file.resource) {
if immediate {
return .single(ManagedAnimationItem(source: .resource(account.postbox.mediaBox, file.resource), frames: .still(.end), duration: 0))
} else {
return .single(ManagedAnimationItem(source: .resource(account.postbox.mediaBox, file.resource), loop: loop))
}
} else {
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedSize = dimensions.cgSize.aspectFilled(CGSize(width: 384.0, height: 384.0))
let fetched = freeMediaFileInteractiveFetched(account: account, fileReference: .standalone(media: file))
let animationItem = Signal<ManagedAnimationItem?, NoError> { subscriber in
let fetchedDisposable = fetched.start()
let resourceDisposable = (chatMessageAnimationData(postbox: account.postbox, resource: file.resource, fitzModifier: nil, width: Int(fittedSize.width), height: Int(fittedSize.height), synchronousLoad: false)
|> filter { data in
return data.complete
}).start(next: { next in
subscriber.putNext(ManagedAnimationItem(source: .resource(account.postbox.mediaBox, file.resource), loop: loop))
})
return ActionDisposable {
fetchedDisposable.dispose()
resourceDisposable.dispose()
}
}
if roll {
return rollingAnimationItem(account: account, emojis: emojis, emoji: emoji) |> then(animationItem)
} else {
return animationItem
}
}
}
}
private func rollingAnimationItem(account: Account, emojis: Signal<[TelegramMediaFile], NoError>, emoji: String) -> Signal<ManagedAnimationItem?, NoError> {
switch emoji { switch emoji {
case "🎲": case "🎲":
return ManagedAnimationItem(source: .local("Dice_Rolling"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 60), duration: 1.0, loop: true) return .single(ManagedAnimationItem(source: .local("Dice_Rolling"), loop: true))
case "🎯": case "🎯":
return ManagedAnimationItem(source: .local("Darts_Aiming"), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: 90), duration: 1.5, loop: true) return .single(ManagedAnimationItem(source: .local("Darts_Aiming"), loop: true))
default: default:
return nil return animationItem(account: account, emojis: emojis, emoji: emoji, value: nil, loop: true)
} }
} }
@ -63,20 +106,7 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
let previousState = self.diceState let previousState = self.diceState
self.diceState = diceState self.diceState = diceState
let frameCount: Int var item: Signal<ManagedAnimationItem?, NoError>? = nil
let duration: Double
switch dice.emoji {
case "🎲":
frameCount = 180
duration = 3.0
case "🎯":
frameCount = 100
duration = 1.6
default:
frameCount = 180
duration = 1.6
}
let context = self.context let context = self.context
if let previousState = previousState { if let previousState = previousState {
@ -84,47 +114,14 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
case .rolling: case .rolling:
switch diceState { switch diceState {
case let .value(value, _): case let .value(value, _):
let animationItem: Signal<ManagedAnimationItem, NoError> = self.emojis.get() item = animationItem(account: context.account, emojis: self.emojis.get(), emoji: self.dice.emoji, value: value)
|> mapToSignal { emojis -> Signal<ManagedAnimationItem, NoError> in
guard emojis.count >= value else {
return .complete()
}
let file = emojis[Int(value) - 1]
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedSize = dimensions.cgSize.aspectFilled(CGSize(width: 384.0, height: 384.0))
let fetched = freeMediaFileInteractiveFetched(account: context.account, fileReference: .standalone(media: file))
let animationItem = Signal<ManagedAnimationItem, NoError> { subscriber in
let fetchedDisposable = fetched.start()
let resourceDisposable = (chatMessageAnimationData(postbox: context.account.postbox, resource: file.resource, fitzModifier: nil, width: Int(fittedSize.width), height: Int(fittedSize.height), synchronousLoad: false)
|> filter { data in
return data.complete
}).start(next: { next in
subscriber.putNext(ManagedAnimationItem(source: .resource(context.account.postbox.mediaBox, file.resource), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: frameCount), duration: duration))
})
return ActionDisposable {
fetchedDisposable.dispose()
resourceDisposable.dispose()
}
}
return animationItem
}
self.disposable.set((animationItem |> deliverOnMainQueue).start(next: { [weak self] item in
if let strongSelf = self {
strongSelf.trackTo(item: item)
}
}))
case .rolling: case .rolling:
break break
} }
case .value: case .value:
switch diceState { switch diceState {
case .rolling: case .rolling:
if let item = rollingAnimationItem(emoji: self.dice.emoji) { item = rollingAnimationItem(account: context.account, emojis: self.emojis.get(), emoji: self.dice.emoji)
self.trackTo(item: item)
}
case .value: case .value:
break break
} }
@ -132,58 +129,18 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
} else { } else {
switch diceState { switch diceState {
case let .value(value, immediate): case let .value(value, immediate):
let animationItem: Signal<ManagedAnimationItem, NoError> = self.emojis.get() item = animationItem(account: context.account, emojis: self.emojis.get(), emoji: self.dice.emoji, value: value, immediate: immediate, roll: true)
|> mapToSignal { emojis -> Signal<ManagedAnimationItem, NoError> in
guard emojis.count >= value else {
return .complete()
}
let file = emojis[Int(value) - 1]
if let _ = context.account.postbox.mediaBox.completedResourcePath(file.resource) {
if immediate {
return .single(ManagedAnimationItem(source: .resource(context.account.postbox.mediaBox, file.resource), frames: ManagedAnimationFrameRange(startFrame: frameCount, endFrame: frameCount), duration: 0.0))
} else {
return .single(ManagedAnimationItem(source: .resource(context.account.postbox.mediaBox, file.resource), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: frameCount), duration: duration))
}
} else {
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedSize = dimensions.cgSize.aspectFilled(CGSize(width: 384.0, height: 384.0))
let fetched = freeMediaFileInteractiveFetched(account: self.context.account, fileReference: .standalone(media: file))
let animationItem = Signal<ManagedAnimationItem, NoError> { subscriber in
let fetchedDisposable = fetched.start()
let resourceDisposable = (chatMessageAnimationData(postbox: self.context.account.postbox, resource: file.resource, fitzModifier: nil, width: Int(fittedSize.width), height: Int(fittedSize.height), synchronousLoad: false)
|> filter { data in
return data.complete
}).start(next: { next in
subscriber.putNext(ManagedAnimationItem(source: .resource(context.account.postbox.mediaBox, file.resource), frames: ManagedAnimationFrameRange(startFrame: 0, endFrame: frameCount), duration: duration))
subscriber.putCompletion()
})
return ActionDisposable {
fetchedDisposable.dispose()
resourceDisposable.dispose()
}
}
if let item = rollingAnimationItem(emoji: self.dice.emoji) {
return .single(item) |> then(animationItem)
} else {
return animationItem
}
}
}
self.disposable.set((animationItem |> deliverOnMainQueue).start(next: { [weak self] item in
if let strongSelf = self {
strongSelf.trackTo(item: item)
}
}))
case .rolling: case .rolling:
if let item = rollingAnimationItem(emoji: self.dice.emoji) { item = rollingAnimationItem(account: context.account, emojis: self.emojis.get(), emoji: self.dice.emoji)
self.trackTo(item: item)
}
} }
} }
if let item = item {
self.disposable.set((item |> deliverOnMainQueue).start(next: { [weak self] item in
if let strongSelf = self, let item = item {
strongSelf.trackTo(item: item)
}
}))
}
} }
} }

View File

@ -311,7 +311,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
if let value = dice.value { if let value = dice.value {
switch stickerPack { switch stickerPack {
case let .result(_, items, _): case let .result(_, items, _):
let item = items[Int(value) - 1] let item = items[Int(value)]
if let item = item as? StickerPackItem { if let item = item as? StickerPackItem {
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource), width: 120, height: 120, playbackMode: .once, mode: .direct) animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource), width: 120, height: 120, playbackMode: .once, mode: .direct)
} }