Dice fixes

This commit is contained in:
Ilya Laktyushin
2020-04-26 21:06:57 +04:00
parent 5a6963b125
commit 9ec67698f5
6 changed files with 54 additions and 21 deletions

View File

@@ -10,7 +10,6 @@ import SwiftSignalKit
public final class ManagedAnimationState {
public let item: ManagedAnimationItem
private let instance: LottieInstance
let frameCount: Int
@@ -19,6 +18,8 @@ public final class ManagedAnimationState {
var relativeTime: Double = 0.0
public var frameIndex: Int?
public var executedCallbacks = Set<Int>()
private let renderContext: DrawingContext
public init?(displaySize: CGSize, item: ManagedAnimationItem, current: ManagedAnimationState?) {
@@ -109,17 +110,19 @@ public enum ManagedAnimationSource: Equatable {
}
}
public struct ManagedAnimationItem: Equatable {
public struct ManagedAnimationItem {
public let source: ManagedAnimationSource
var frames: ManagedAnimationFrameRange?
var duration: Double?
var loop: Bool
var callbacks: [(Int, () -> Void)]
public init(source: ManagedAnimationSource, frames: ManagedAnimationFrameRange? = nil, duration: Double? = nil, loop: Bool = false) {
public init(source: ManagedAnimationSource, frames: ManagedAnimationFrameRange? = nil, duration: Double? = nil, loop: Bool = false, callbacks: [(Int, () -> Void)] = []) {
self.source = source
self.frames = frames
self.duration = duration
self.loop = loop
self.callbacks = callbacks
}
}
@@ -240,6 +243,13 @@ open class ManagedAnimationNode: ASDisplayNode {
if let image = state.draw() {
self.imageNode.image = image
}
for (callbackFrame, callback) in state.item.callbacks {
if !state.executedCallbacks.contains(callbackFrame) && frameIndex >= callbackFrame {
state.executedCallbacks.insert(callbackFrame)
callback()
}
}
}
var animationAdvancement: Double = 1.0 / 60.0

View File

@@ -6573,8 +6573,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
if let value = value {
self.present(UndoOverlayController(presentationData: self.presentationData, content: .dice(dice: dice, account: self.context.account, text: value, action: self.presentationData.strings.Conversation_SendDice), elevatedLayout: true, action: { [weak self] action in
if let strongSelf = self, action == .undo {
self.present(UndoOverlayController(presentationData: self.presentationData, content: .dice(dice: dice, account: self.context.account, text: value, action: canSendMessagesToChat(self.presentationInterfaceState) ? self.presentationData.strings.Conversation_SendDice : nil), elevatedLayout: true, action: { [weak self] action in
if let strongSelf = self, canSendMessagesToChat(strongSelf.presentationInterfaceState), action == .undo {
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: dice.emoji)), replyToMessageId: nil, localGroupingKey: nil)])
}
return false

View File

@@ -210,6 +210,13 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
if let telegramDice = self.telegramDice {
let animationNode = ManagedDiceAnimationNode(context: item.context, emoji: telegramDice.emoji)
if !item.message.effectivelyIncoming(item.context.account.peerId) {
animationNode.success = { [weak self] in
if let strongSelf = self, let item = strongSelf.item {
item.controllerInteraction.animateDiceSuccess()
}
}
}
self.animationNode = animationNode
} else {
let animationNode = AnimatedStickerNode()

View File

@@ -14,19 +14,25 @@ enum ManagedDiceAnimationState: Equatable {
case value(Int32, Bool)
}
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
private func animationItem(account: Account, emojis: Signal<[TelegramMediaFile], NoError>, configuration: Signal<InteractiveEmojiConfiguration?, NoError> = .single(nil), emoji: String, value: Int32?, immediate: Bool = false, roll: Bool = false, loop: Bool = false, successCallback: (() -> Void)? = nil) -> Signal<ManagedAnimationItem?, NoError> {
return combineLatest(emojis, configuration)
|> mapToSignal { diceEmojis, configuration -> Signal<ManagedAnimationItem?, NoError> in
if let value = value, value >= diceEmojis.count {
return .complete()
}
let file = diceEmojis[Int(value ?? 0)]
var callbacks: [(Int, () -> Void)] = []
if !loop, let successCallback = successCallback, let value = value, let configuration = configuration, let success = configuration.successParameters[emoji], value == success.value {
callbacks.append((success.frame, successCallback))
}
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))
return .single(ManagedAnimationItem(source: .resource(account.postbox.mediaBox, file.resource), loop: loop, callbacks: callbacks))
}
} else {
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
@@ -39,7 +45,7 @@ private func animationItem(account: Account, emojis: Signal<[TelegramMediaFile],
|> filter { data in
return data.complete
}).start(next: { next in
subscriber.putNext(ManagedAnimationItem(source: .resource(account.postbox.mediaBox, file.resource), loop: loop))
subscriber.putNext(ManagedAnimationItem(source: .resource(account.postbox.mediaBox, file.resource), loop: loop, callbacks: callbacks))
})
return ActionDisposable {
@@ -91,7 +97,7 @@ public struct InteractiveEmojiConfiguration {
var successParameters: [String: InteractiveEmojiSuccessParameters] = [:]
if let success = data["emojies_send_dice_success"] as? [String: [String: Double]] {
for (key, dict) in success {
if let successValue = dict[""], let successFrame = dict[""] {
if let successValue = dict["value"], let successFrame = dict["frame_start"] {
successParameters[key] = InteractiveEmojiSuccessParameters(value: Int(successValue), frame: Int(successFrame))
}
}
@@ -110,18 +116,20 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
private var diceState: ManagedDiceAnimationState? = nil
private let disposable = MetaDisposable()
private let configuration = Promise<InteractiveEmojiConfiguration?>()
private let emojis = Promise<[TelegramMediaFile]>()
var success: (() -> Void)?
init(context: AccountContext, emoji: String) {
self.context = context
self.emoji = emoji
self.context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|> map { preferencesView -> InteractiveEmojiConfiguration in
self.configuration.set(self.context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|> map { preferencesView -> InteractiveEmojiConfiguration? in
let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue
return InteractiveEmojiConfiguration.with(appConfiguration: appConfiguration)
}
})
self.emojis.set(loadedStickerPack(postbox: context.account.postbox, network: context.account.network, reference: .dice(emoji), forceActualized: false)
|> mapToSignal { stickerPack -> Signal<[TelegramMediaFile], NoError> in
switch stickerPack {
@@ -155,7 +163,9 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
case .rolling:
switch diceState {
case let .value(value, _):
item = animationItem(account: context.account, emojis: self.emojis.get(), emoji: self.emoji, value: value)
item = animationItem(account: context.account, emojis: self.emojis.get(), configuration: self.configuration.get(), emoji: self.emoji, value: value, successCallback: { [weak self] in
self?.success?()
})
case .rolling:
break
}
@@ -170,7 +180,9 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
} else {
switch diceState {
case let .value(value, immediate):
item = animationItem(account: context.account, emojis: self.emojis.get(), emoji: self.emoji, value: value, immediate: immediate, roll: true)
item = animationItem(account: context.account, emojis: self.emojis.get(), configuration: self.configuration.get(), emoji: self.emoji, value: value, immediate: immediate, roll: true, successCallback: { [weak self] in
self?.success?()
})
case .rolling:
item = rollingAnimationItem(account: context.account, emojis: self.emojis.get(), emoji: self.emoji)
}

View File

@@ -17,7 +17,7 @@ public enum UndoOverlayContent {
case swipeToReply(title: String, text: String)
case actionSucceeded(title: String, text: String, cancel: String)
case stickersModified(title: String, text: String, undo: Bool, info: StickerPackCollectionInfo, topItem: ItemCollectionItem?, account: Account)
case dice(dice: TelegramMediaDice, account: Account, text: String, action: String)
case dice(dice: TelegramMediaDice, account: Account, text: String, action: String?)
}
public enum UndoOverlayAction {

View File

@@ -290,15 +290,19 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
let link = MarkdownAttributeSet(font: Font.regular(14.0), textColor: undoTextColor)
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: link, linkAttribute: { _ in return nil }), textAlignment: .natural)
self.textNode.attributedText = attributedText
displayUndo = true
undoText = action
if let action = action {
displayUndo = true
undoText = action
} else {
displayUndo = false
}
self.originalRemainingSeconds = 5
self.stickerImageSize = CGSize(width: 42.0, height: 42.0)
switch dice.emoji {
case "🎲":
self.stickerOffset = CGPoint(x: 0.0, y: -8.0)
self.stickerOffset = CGPoint(x: 0.0, y: -7.0)
default:
break
}