mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-22 11:11:10 +00:00
Merge commit 'c3f2fa5bc36d073853033b870b53f4460ba852eb'
This commit is contained in:
commit
38b71bbc08
@ -379,11 +379,11 @@ static const CGFloat outerCircleMinScale = innerCircleRadius / outerCircleRadius
|
||||
_innerCircleView.alpha = 0.0f;
|
||||
[[_presentation view] addSubview:_innerCircleView];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(micButtonDecoration)]) {
|
||||
UIView<TGModernConversationInputMicButtonDecoration> *decoration = [_delegate micButtonDecoration];
|
||||
_decoration = decoration;
|
||||
[[_presentation view] addSubview:_decoration];
|
||||
}
|
||||
// if ([_delegate respondsToSelector:@selector(micButtonDecoration)]) {
|
||||
// UIView<TGModernConversationInputMicButtonDecoration> *decoration = [_delegate micButtonDecoration];
|
||||
// _decoration = decoration;
|
||||
// [[_presentation view] addSubview:_decoration];
|
||||
// }
|
||||
|
||||
_outerCircleView = [[UIImageView alloc] initWithImage:[self outerCircleImage:self.pallete != nil ? self.pallete.buttonColor : TGAccentColor()]];
|
||||
_outerCircleView.alpha = 0.0f;
|
||||
|
@ -59,14 +59,14 @@ public final class ManagedAnimationState {
|
||||
}
|
||||
}
|
||||
|
||||
public struct ManagedAnimationFrameRange: Equatable {
|
||||
var startFrame: Int
|
||||
var endFrame: Int
|
||||
|
||||
public init(startFrame: Int, endFrame: Int) {
|
||||
self.startFrame = startFrame
|
||||
self.endFrame = endFrame
|
||||
}
|
||||
public enum ManagedAnimationFramePosition {
|
||||
case start
|
||||
case end
|
||||
}
|
||||
|
||||
public enum ManagedAnimationFrameRange: Equatable {
|
||||
case range(startFrame: Int, endFrame: Int)
|
||||
case still(ManagedAnimationFramePosition)
|
||||
}
|
||||
|
||||
public enum ManagedAnimationSource: Equatable {
|
||||
@ -111,11 +111,11 @@ public enum ManagedAnimationSource: Equatable {
|
||||
|
||||
public struct ManagedAnimationItem: Equatable {
|
||||
public let source: ManagedAnimationSource
|
||||
var frames: ManagedAnimationFrameRange
|
||||
var duration: Double
|
||||
var frames: ManagedAnimationFrameRange?
|
||||
var duration: Double?
|
||||
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.frames = frames
|
||||
self.duration = duration
|
||||
@ -195,17 +195,42 @@ open class ManagedAnimationNode: ASDisplayNode {
|
||||
guard let state = self.state else {
|
||||
return
|
||||
}
|
||||
let timestamp = CACurrentMediaTime()
|
||||
|
||||
let fps = state.fps
|
||||
let frameRange = state.item.frames
|
||||
let startFrame: Int
|
||||
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
|
||||
t = max(0.0, t)
|
||||
t = min(1.0, t)
|
||||
//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 upperBound = state.frameCount - 1
|
||||
let frameIndex = max(lowerBound, min(upperBound, frameOffset))
|
||||
|
@ -28,7 +28,7 @@ final class ManagedMonkeyAnimationNode: ManagedAnimationNode {
|
||||
init() {
|
||||
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 {
|
||||
@ -68,12 +68,12 @@ final class ManagedMonkeyAnimationNode: ManagedAnimationNode {
|
||||
private func enqueueIdle(_ idle: ManagedMonkeyAnimationIdle) {
|
||||
switch idle {
|
||||
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:
|
||||
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:
|
||||
self.trackTo(item: ManagedAnimationItem(source: .local("TwoFactorSetupMonkeyIdle2"), frames: ManagedAnimationFrameRange(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("TwoFactorSetupMonkeyIdle2"), frames: .range(startFrame: 0, endFrame: 30), duration: 0.3))
|
||||
//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 frameIndex = lowerBound + Int(value * CGFloat(upperBound - lowerBound))
|
||||
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.didTryAdvancingState = false
|
||||
self.updateAnimation()
|
||||
@ -97,13 +97,13 @@ final class ManagedMonkeyAnimationNode: ManagedAnimationNode {
|
||||
self.trackStack = self.trackStack.filter {
|
||||
$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() {
|
||||
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.didTryAdvancingState = false
|
||||
self.updateAnimation()
|
||||
@ -116,50 +116,50 @@ final class ManagedMonkeyAnimationNode: ManagedAnimationNode {
|
||||
case let .idle(idle):
|
||||
self.enqueueIdle(idle)
|
||||
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:
|
||||
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):
|
||||
enqueueTracking(value)
|
||||
}
|
||||
case .eyesClosed:
|
||||
switch monkeyState {
|
||||
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)
|
||||
case .eyesClosed:
|
||||
break
|
||||
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):
|
||||
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)
|
||||
}
|
||||
case .peeking:
|
||||
switch monkeyState {
|
||||
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)
|
||||
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:
|
||||
break
|
||||
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)
|
||||
}
|
||||
case let .tracking(currentValue):
|
||||
switch monkeyState {
|
||||
case let .idle(idle):
|
||||
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)
|
||||
case .eyesClosed:
|
||||
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:
|
||||
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):
|
||||
if abs(currentValue - value) > CGFloat.ulpOfOne {
|
||||
enqueueTracking(value)
|
||||
|
@ -56,6 +56,26 @@ private struct ChatControllerNodeDerivedLayoutState {
|
||||
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 {
|
||||
let context: AccountContext
|
||||
let chatLocation: ChatLocation
|
||||
@ -77,7 +97,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
let backgroundNode: WallpaperBackgroundNode
|
||||
let backgroundDisposable = MetaDisposable()
|
||||
let backgroundImageDisposable = MetaDisposable()
|
||||
let historyNode: ChatHistoryListNode
|
||||
let reactionContainerNode: ReactionSelectionParentNode
|
||||
let historyNodeContainer: ASDisplayNode
|
||||
@ -129,6 +149,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
var chatPresentationInterfaceState: ChatPresentationInterfaceState
|
||||
var automaticMediaDownloadSettings: MediaAutoDownloadSettings
|
||||
|
||||
private var interactiveEmojis: [String] = []
|
||||
private var interactiveEmojisDisposable: Disposable?
|
||||
|
||||
private let selectedMessagesPromise = Promise<Set<MessageId>?>(nil)
|
||||
var selectedMessages: Set<MessageId>? {
|
||||
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
|
||||
if let strongSelf = self, let (image, final) = image {
|
||||
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, _) = 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 {
|
||||
self.backgroundNode.imageContentMode = .scaleToFill
|
||||
} else {
|
||||
@ -350,6 +386,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.backgroundImageDisposable.dispose()
|
||||
self.interactiveEmojisDisposable?.dispose()
|
||||
self.openStickersDisposable?.dispose()
|
||||
self.displayVideoUnmuteTipDisposable?.dispose()
|
||||
}
|
||||
@ -1468,7 +1506,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
let themeUpdated = self.chatPresentationInterfaceState.theme !== chatPresentationInterfaceState.theme
|
||||
|
||||
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 {
|
||||
strongSelf.backgroundNode.image = image
|
||||
}
|
||||
@ -2261,7 +2299,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
let effectiveInputText = effectivePresentationInterfaceState.interfaceState.composeInputState.inputText
|
||||
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))
|
||||
} else {
|
||||
let inputText = convertMarkdownToAttributes(effectiveInputText)
|
||||
|
@ -14,14 +14,57 @@ enum ManagedDiceAnimationState: Equatable {
|
||||
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 {
|
||||
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 "🎯":
|
||||
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:
|
||||
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
|
||||
self.diceState = diceState
|
||||
|
||||
let frameCount: Int
|
||||
let duration: Double
|
||||
|
||||
switch dice.emoji {
|
||||
case "🎲":
|
||||
frameCount = 180
|
||||
duration = 3.0
|
||||
case "🎯":
|
||||
frameCount = 100
|
||||
duration = 1.6
|
||||
default:
|
||||
frameCount = 180
|
||||
duration = 1.6
|
||||
}
|
||||
var item: Signal<ManagedAnimationItem?, NoError>? = nil
|
||||
|
||||
let context = self.context
|
||||
if let previousState = previousState {
|
||||
@ -84,47 +114,14 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
|
||||
case .rolling:
|
||||
switch diceState {
|
||||
case let .value(value, _):
|
||||
let animationItem: Signal<ManagedAnimationItem, NoError> = self.emojis.get()
|
||||
|> 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)
|
||||
}
|
||||
}))
|
||||
item = animationItem(account: context.account, emojis: self.emojis.get(), emoji: self.dice.emoji, value: value)
|
||||
case .rolling:
|
||||
break
|
||||
}
|
||||
case .value:
|
||||
switch diceState {
|
||||
case .rolling:
|
||||
if let item = rollingAnimationItem(emoji: self.dice.emoji) {
|
||||
self.trackTo(item: item)
|
||||
}
|
||||
item = rollingAnimationItem(account: context.account, emojis: self.emojis.get(), emoji: self.dice.emoji)
|
||||
case .value:
|
||||
break
|
||||
}
|
||||
@ -132,58 +129,18 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
|
||||
} else {
|
||||
switch diceState {
|
||||
case let .value(value, immediate):
|
||||
let animationItem: Signal<ManagedAnimationItem, NoError> = self.emojis.get()
|
||||
|> 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)
|
||||
}
|
||||
}))
|
||||
item = animationItem(account: context.account, emojis: self.emojis.get(), emoji: self.dice.emoji, value: value, immediate: immediate, roll: true)
|
||||
case .rolling:
|
||||
if let item = rollingAnimationItem(emoji: self.dice.emoji) {
|
||||
self.trackTo(item: item)
|
||||
}
|
||||
item = rollingAnimationItem(account: context.account, emojis: self.emojis.get(), emoji: self.dice.emoji)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -311,7 +311,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
if let value = dice.value {
|
||||
switch stickerPack {
|
||||
case let .result(_, items, _):
|
||||
let item = items[Int(value) - 1]
|
||||
let item = items[Int(value)]
|
||||
if let item = item as? StickerPackItem {
|
||||
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource), width: 120, height: 120, playbackMode: .once, mode: .direct)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user