mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-23 03:31:09 +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;
|
_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;
|
||||||
|
@ -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) {
|
|
||||||
self.startFrame = startFrame
|
public enum ManagedAnimationFrameRange: Equatable {
|
||||||
self.endFrame = endFrame
|
case range(startFrame: Int, endFrame: Int)
|
||||||
}
|
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))
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user