mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Polls
This commit is contained in:
parent
9ac0e6a2bf
commit
cae30133bc
@ -5247,7 +5247,7 @@ Any member of this group will be able to see messages in the channel.";
|
|||||||
"Map.NoPlacesNearby" = "There are no known places nearby.\nTry a different location.";
|
"Map.NoPlacesNearby" = "There are no known places nearby.\nTry a different location.";
|
||||||
|
|
||||||
"CreatePoll.QuizTitle" = "New Quiz";
|
"CreatePoll.QuizTitle" = "New Quiz";
|
||||||
"CreatePoll.QuizOptionsHeader" = "QUIZ OPTIONS";
|
"CreatePoll.QuizOptionsHeader" = "QUIZ ANSWERS";
|
||||||
"CreatePoll.Anonymous" = "Anonymous Voting";
|
"CreatePoll.Anonymous" = "Anonymous Voting";
|
||||||
"CreatePoll.MultipleChoice" = "Multiple Choice";
|
"CreatePoll.MultipleChoice" = "Multiple Choice";
|
||||||
"CreatePoll.MultipleChoiceQuizAlert" = "A quiz has one correct answer.";
|
"CreatePoll.MultipleChoiceQuizAlert" = "A quiz has one correct answer.";
|
||||||
@ -5258,7 +5258,7 @@ Any member of this group will be able to see messages in the channel.";
|
|||||||
"MessagePoll.LabelPoll" = "Public Poll";
|
"MessagePoll.LabelPoll" = "Public Poll";
|
||||||
"MessagePoll.LabelAnonymousQuiz" = "Anonymous Quiz";
|
"MessagePoll.LabelAnonymousQuiz" = "Anonymous Quiz";
|
||||||
"MessagePoll.LabelQuiz" = "Quiz";
|
"MessagePoll.LabelQuiz" = "Quiz";
|
||||||
"MessagePoll.SubmitVote" = "Submit Vote";
|
"MessagePoll.SubmitVote" = "Vote";
|
||||||
"MessagePoll.ViewResults" = "View Results";
|
"MessagePoll.ViewResults" = "View Results";
|
||||||
"MessagePoll.QuizNoUsers" = "Nobody answered yet";
|
"MessagePoll.QuizNoUsers" = "Nobody answered yet";
|
||||||
"MessagePoll.QuizCount_0" = "%@ answered";
|
"MessagePoll.QuizCount_0" = "%@ answered";
|
||||||
@ -5270,8 +5270,8 @@ Any member of this group will be able to see messages in the channel.";
|
|||||||
|
|
||||||
"PollResults.Title" = "Poll Results";
|
"PollResults.Title" = "Poll Results";
|
||||||
"PollResults.Collapse" = "COLLAPSE";
|
"PollResults.Collapse" = "COLLAPSE";
|
||||||
"PollResults.ShowMore_1" = "Show %@ More";
|
"PollResults.ShowMore_1" = "Show More (%@)";
|
||||||
"PollResults.ShowMore_any" = "Show %@ More";
|
"PollResults.ShowMore_any" = "Show More (%@)";
|
||||||
|
|
||||||
"Conversation.StopQuiz" = "Stop Quiz";
|
"Conversation.StopQuiz" = "Stop Quiz";
|
||||||
"Conversation.StopQuizConfirmationTitle" = "If you stop this quiz now, nobody will be able to submit answers. This action cannot be undone.";
|
"Conversation.StopQuizConfirmationTitle" = "If you stop this quiz now, nobody will be able to submit answers. This action cannot be undone.";
|
||||||
|
@ -22,18 +22,18 @@ private struct OrderedLinkedListItemOrdering: Comparable {
|
|||||||
var higherItemIds: Set<OrderedLinkedListItemOrderingId>
|
var higherItemIds: Set<OrderedLinkedListItemOrderingId>
|
||||||
|
|
||||||
static func <(lhs: OrderedLinkedListItemOrdering, rhs: OrderedLinkedListItemOrdering) -> Bool {
|
static func <(lhs: OrderedLinkedListItemOrdering, rhs: OrderedLinkedListItemOrdering) -> Bool {
|
||||||
if lhs.lowerItemIds.contains(rhs.id) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if rhs.lowerItemIds.contains(lhs.id) {
|
if rhs.lowerItemIds.contains(lhs.id) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if lhs.higherItemIds.contains(rhs.id) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if rhs.higherItemIds.contains(lhs.id) {
|
if rhs.higherItemIds.contains(lhs.id) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.lowerItemIds.contains(rhs.id) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.higherItemIds.contains(rhs.id) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -2064,8 +2064,9 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !nodeFrame.size.height.isEqual(to: node.apparentHeight) {
|
if !nodeFrame.size.height.isEqual(to: node.apparentHeight) {
|
||||||
|
let addAnimation = previousFrame?.height != nodeFrame.size.height
|
||||||
node.addApparentHeightAnimation(nodeFrame.size.height, duration: insertionAnimationDuration * UIView.animationDurationFactor(), beginAt: timestamp, update: { [weak node] progress, currentValue in
|
node.addApparentHeightAnimation(nodeFrame.size.height, duration: insertionAnimationDuration * UIView.animationDurationFactor(), beginAt: timestamp, update: { [weak node] progress, currentValue in
|
||||||
if let node = node {
|
if let node = node, addAnimation {
|
||||||
node.animateFrameTransition(progress, currentValue)
|
node.animateFrameTransition(progress, currentValue)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1275,7 +1275,7 @@ public final class ItemListPeerItemHeader: ListViewItemHeader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class ItemListPeerItemHeaderNode: ListViewItemHeaderNode {
|
public final class ItemListPeerItemHeaderNode: ListViewItemHeaderNode, ItemListHeaderItemNode {
|
||||||
private var theme: PresentationTheme
|
private var theme: PresentationTheme
|
||||||
private var strings: PresentationStrings
|
private var strings: PresentationStrings
|
||||||
private var actionTitle: String?
|
private var actionTitle: String?
|
||||||
|
@ -8,6 +8,10 @@ import SyncCore
|
|||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import MergeLists
|
import MergeLists
|
||||||
|
|
||||||
|
public protocol ItemListHeaderItemNode: class {
|
||||||
|
func updateTheme(theme: PresentationTheme)
|
||||||
|
}
|
||||||
|
|
||||||
public typealias ItemListSectionId = Int32
|
public typealias ItemListSectionId = Int32
|
||||||
|
|
||||||
public protocol ItemListNodeAnyEntry {
|
public protocol ItemListNodeAnyEntry {
|
||||||
@ -467,6 +471,12 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.rightOverlayNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
self.rightOverlayNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.listNode.forEachItemHeaderNode({ itemHeaderNode in
|
||||||
|
if let itemHeaderNode = itemHeaderNode as? ItemListHeaderItemNode {
|
||||||
|
itemHeaderNode.updateTheme(theme: transition.theme)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if let updateStyle = transition.updateStyle {
|
if let updateStyle = transition.updateStyle {
|
||||||
|
@ -181,7 +181,7 @@ public func mergeListsStableWithUpdates<T>(leftList: [T], rightList: [T], allUpd
|
|||||||
return (removeIndices, insertItems, updatedIndices)
|
return (removeIndices, insertItems, updatedIndices)
|
||||||
}
|
}
|
||||||
|
|
||||||
@inlinable
|
//@inlinable
|
||||||
public func mergeListsStableWithUpdates<T>(leftList: [T], rightList: [T], isLess: (T, T) -> Bool, isEqual: (T, T) -> Bool, getId: (T) -> AnyHashable, allUpdated: Bool = false) -> ([Int], [(Int, T, Int?)], [(Int, T, Int)]) {
|
public func mergeListsStableWithUpdates<T>(leftList: [T], rightList: [T], isLess: (T, T) -> Bool, isEqual: (T, T) -> Bool, getId: (T) -> AnyHashable, allUpdated: Bool = false) -> ([Int], [(Int, T, Int?)], [(Int, T, Int)]) {
|
||||||
var removeIndices: [Int] = []
|
var removeIndices: [Int] = []
|
||||||
var insertItems: [(Int, T, Int?)] = []
|
var insertItems: [(Int, T, Int?)] = []
|
||||||
@ -207,6 +207,25 @@ public func mergeListsStableWithUpdates<T>(leftList: [T], rightList: [T], isLess
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
var leftStableIds: [AnyHashable] = []
|
||||||
|
var rightStableIds: [AnyHashable] = []
|
||||||
|
for item in leftList {
|
||||||
|
leftStableIds.append(getId(item))
|
||||||
|
}
|
||||||
|
for item in rightList {
|
||||||
|
rightStableIds.append(getId(item))
|
||||||
|
}
|
||||||
|
if Set(leftStableIds) == Set(rightStableIds) && leftStableIds != rightStableIds {
|
||||||
|
/*var i = 0
|
||||||
|
var j = 0
|
||||||
|
while true {
|
||||||
|
if getId(leftList[i]) != getId(rightList[i]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
print("order changed")
|
||||||
|
}
|
||||||
|
|
||||||
var currentList = leftList
|
var currentList = leftList
|
||||||
|
|
||||||
var i = 0
|
var i = 0
|
||||||
|
@ -453,7 +453,7 @@ public func archivedStickerPacksController(context: AccountContext, mode: Archiv
|
|||||||
}
|
}
|
||||||
presentStickerPackController = { [weak controller] info in
|
presentStickerPackController = { [weak controller] info in
|
||||||
let packReference: StickerPackReference = .id(id: info.id.id, accessHash: info.accessHash)
|
let packReference: StickerPackReference = .id(id: info.id.id, accessHash: info.accessHash)
|
||||||
presentControllerImpl?(StickerPackScreen(context: context, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: controller?.navigationController as? NavigationController), nil)
|
presentControllerImpl?(StickerPackScreen(context: context, mode: .settings, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: controller?.navigationController as? NavigationController), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return controller
|
return controller
|
||||||
|
@ -265,7 +265,7 @@ public func featuredStickerPacksController(context: AccountContext) -> ViewContr
|
|||||||
|
|
||||||
presentStickerPackController = { [weak controller] info in
|
presentStickerPackController = { [weak controller] info in
|
||||||
let packReference: StickerPackReference = .id(id: info.id.id, accessHash: info.accessHash)
|
let packReference: StickerPackReference = .id(id: info.id.id, accessHash: info.accessHash)
|
||||||
presentControllerImpl?(StickerPackScreen(context: context, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: controller?.navigationController as? NavigationController), nil)
|
presentControllerImpl?(StickerPackScreen(context: context, mode: .settings, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: controller?.navigationController as? NavigationController), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return controller
|
return controller
|
||||||
|
@ -838,7 +838,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
|||||||
packs.insert(packReference, at: 0)
|
packs.insert(packReference, at: 0)
|
||||||
}
|
}
|
||||||
if let mainStickerPack = mainStickerPack {
|
if let mainStickerPack = mainStickerPack {
|
||||||
presentControllerImpl?(StickerPackScreen(context: context, mainStickerPack: mainStickerPack, stickerPacks: packs, parentNavigationController: controller?.navigationController as? NavigationController, actionPerformed: { info, items, action in
|
presentControllerImpl?(StickerPackScreen(context: context, mode: .settings, mainStickerPack: mainStickerPack, stickerPacks: packs, parentNavigationController: controller?.navigationController as? NavigationController, actionPerformed: { info, items, action in
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
var animateInAsReplacement = false
|
var animateInAsReplacement = false
|
||||||
if let navigationController = navigationControllerImpl?() {
|
if let navigationController = navigationControllerImpl?() {
|
||||||
|
@ -847,8 +847,8 @@ public enum StickerPackScreenPerformedAction {
|
|||||||
case remove(positionInList: Int)
|
case remove(positionInList: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func StickerPackScreen(context: AccountContext, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)? = nil, actionPerformed: ((StickerPackCollectionInfo, [ItemCollectionItem], StickerPackScreenPerformedAction) -> Void)? = nil) -> ViewController {
|
public func StickerPackScreen(context: AccountContext, mode: StickerPackPreviewControllerMode = .default, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)? = nil, actionPerformed: ((StickerPackCollectionInfo, [ItemCollectionItem], StickerPackScreenPerformedAction) -> Void)? = nil) -> ViewController {
|
||||||
let controller = StickerPackPreviewController(context: context, stickerPack: mainStickerPack, mode: .default, parentNavigationController: parentNavigationController, actionPerformed: actionPerformed)
|
let controller = StickerPackPreviewController(context: context, stickerPack: mainStickerPack, mode: mode, parentNavigationController: parentNavigationController, actionPerformed: actionPerformed)
|
||||||
controller.sendSticker = sendSticker
|
controller.sendSticker = sendSticker
|
||||||
return controller
|
return controller
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import SyncCore
|
|||||||
import Postbox
|
import Postbox
|
||||||
import TextFormat
|
import TextFormat
|
||||||
import UrlEscaping
|
import UrlEscaping
|
||||||
import CheckNode
|
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import AccountContext
|
import AccountContext
|
||||||
import AvatarNode
|
import AvatarNode
|
||||||
@ -89,40 +88,67 @@ func countNicePercent(votes: [Int], total: Int) -> [Int] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final class ChatMessagePollOptionRadioNodeParameters: NSObject {
|
private final class ChatMessagePollOptionRadioNodeParameters: NSObject {
|
||||||
|
let timestamp: Double
|
||||||
let staticColor: UIColor
|
let staticColor: UIColor
|
||||||
let animatedColor: UIColor
|
let animatedColor: UIColor
|
||||||
|
let fillColor: UIColor
|
||||||
|
let foregroundColor: UIColor
|
||||||
let offset: Double?
|
let offset: Double?
|
||||||
|
let isChecked: Bool?
|
||||||
|
let checkTransition: ChatMessagePollOptionRadioNodeCheckTransition?
|
||||||
|
|
||||||
init(staticColor: UIColor, animatedColor: UIColor, offset: Double?) {
|
init(timestamp: Double, staticColor: UIColor, animatedColor: UIColor, fillColor: UIColor, foregroundColor: UIColor, offset: Double?, isChecked: Bool?, checkTransition: ChatMessagePollOptionRadioNodeCheckTransition?) {
|
||||||
|
self.timestamp = timestamp
|
||||||
self.staticColor = staticColor
|
self.staticColor = staticColor
|
||||||
self.animatedColor = animatedColor
|
self.animatedColor = animatedColor
|
||||||
|
self.fillColor = fillColor
|
||||||
|
self.foregroundColor = foregroundColor
|
||||||
self.offset = offset
|
self.offset = offset
|
||||||
|
self.isChecked = isChecked
|
||||||
|
self.checkTransition = checkTransition
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class ChatMessagePollOptionRadioNodeCheckTransition {
|
||||||
|
let startTime: Double
|
||||||
|
let duration: Double
|
||||||
|
let previousValue: Bool
|
||||||
|
let updatedValue: Bool
|
||||||
|
|
||||||
|
init(startTime: Double, duration: Double, previousValue: Bool, updatedValue: Bool) {
|
||||||
|
self.startTime = startTime
|
||||||
|
self.duration = duration
|
||||||
|
self.previousValue = previousValue
|
||||||
|
self.updatedValue = updatedValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final class ChatMessagePollOptionRadioNode: ASDisplayNode {
|
private final class ChatMessagePollOptionRadioNode: ASDisplayNode {
|
||||||
private(set) var staticColor: UIColor?
|
private(set) var staticColor: UIColor?
|
||||||
private(set) var animatedColor: UIColor?
|
private(set) var animatedColor: UIColor?
|
||||||
|
private(set) var fillColor: UIColor?
|
||||||
|
private(set) var foregroundColor: UIColor?
|
||||||
private var isInHierarchyValue: Bool = false
|
private var isInHierarchyValue: Bool = false
|
||||||
private(set) var isAnimating: Bool = false
|
private(set) var isAnimating: Bool = false
|
||||||
private var startTime: Double?
|
private var startTime: Double?
|
||||||
|
private var checkTransition: ChatMessagePollOptionRadioNodeCheckTransition?
|
||||||
|
private(set) var isChecked: Bool?
|
||||||
|
|
||||||
private var checkNode: CheckNode?
|
private var displayLink: ConstantDisplayLinkAnimator?
|
||||||
|
|
||||||
private var displayLink: CADisplayLink?
|
|
||||||
|
|
||||||
private var shouldBeAnimating: Bool {
|
private var shouldBeAnimating: Bool {
|
||||||
return self.isInHierarchyValue && self.isAnimating
|
return self.isInHierarchyValue && (self.isAnimating || self.checkTransition != nil)
|
||||||
}
|
|
||||||
|
|
||||||
var isChecked: Bool? {
|
|
||||||
return self.checkNode?.isChecked
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateIsChecked(_ value: Bool, animated: Bool) {
|
func updateIsChecked(_ value: Bool, animated: Bool) {
|
||||||
self.checkNode?.setIsChecked(value, animated: animated)
|
if let previousValue = self.isChecked, previousValue != value {
|
||||||
|
self.checkTransition = ChatMessagePollOptionRadioNodeCheckTransition(startTime: CACurrentMediaTime(), duration: 0.15, previousValue: previousValue, updatedValue: value)
|
||||||
|
self.isChecked = value
|
||||||
|
self.updateAnimating()
|
||||||
|
self.setNeedsDisplay()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
@ -132,6 +158,10 @@ private final class ChatMessagePollOptionRadioNode: ASDisplayNode {
|
|||||||
self.isOpaque = false
|
self.isOpaque = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.displayLink?.isPaused = true
|
||||||
|
}
|
||||||
|
|
||||||
override func willEnterHierarchy() {
|
override func willEnterHierarchy() {
|
||||||
super.willEnterHierarchy()
|
super.willEnterHierarchy()
|
||||||
|
|
||||||
@ -154,8 +184,10 @@ private final class ChatMessagePollOptionRadioNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(staticColor: UIColor, animatedColor: UIColor, foregroundColor: UIColor, isSelectable: Bool, isAnimating: Bool) {
|
func update(staticColor: UIColor, animatedColor: UIColor, fillColor: UIColor, foregroundColor: UIColor, isSelectable: Bool, isAnimating: Bool) {
|
||||||
var updated = false
|
var updated = false
|
||||||
|
let shouldHaveBeenAnimating = self.shouldBeAnimating
|
||||||
|
let wasAnimating = self.isAnimating
|
||||||
if !staticColor.isEqual(self.staticColor) {
|
if !staticColor.isEqual(self.staticColor) {
|
||||||
self.staticColor = staticColor
|
self.staticColor = staticColor
|
||||||
updated = true
|
updated = true
|
||||||
@ -164,61 +196,55 @@ private final class ChatMessagePollOptionRadioNode: ASDisplayNode {
|
|||||||
self.animatedColor = animatedColor
|
self.animatedColor = animatedColor
|
||||||
updated = true
|
updated = true
|
||||||
}
|
}
|
||||||
let wasAnimating = self.isAnimating
|
if !fillColor.isEqual(self.fillColor) {
|
||||||
|
self.fillColor = fillColor
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
if !foregroundColor.isEqual(self.foregroundColor) {
|
||||||
|
self.foregroundColor = foregroundColor
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
if isSelectable != (self.isChecked != nil) {
|
||||||
|
if isSelectable {
|
||||||
|
self.isChecked = false
|
||||||
|
} else {
|
||||||
|
self.isChecked = nil
|
||||||
|
self.checkTransition = nil
|
||||||
|
}
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
if isAnimating != self.isAnimating {
|
if isAnimating != self.isAnimating {
|
||||||
let previous = self.shouldBeAnimating
|
|
||||||
self.isAnimating = isAnimating
|
self.isAnimating = isAnimating
|
||||||
let updated = self.shouldBeAnimating
|
let updated = self.shouldBeAnimating
|
||||||
if previous != updated {
|
if shouldHaveBeenAnimating != updated {
|
||||||
self.updateAnimating()
|
self.updateAnimating()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isSelectable && !isAnimating {
|
|
||||||
if self.checkNode == nil {
|
|
||||||
updated = true
|
|
||||||
let checkNode = CheckNode(strokeColor: staticColor, fillColor: animatedColor, foregroundColor: foregroundColor, style: .plain)
|
|
||||||
self.checkNode = checkNode
|
|
||||||
self.addSubnode(checkNode)
|
|
||||||
checkNode.isUserInteractionEnabled = false
|
|
||||||
checkNode.frame = CGRect(origin: CGPoint(x: -5.0, y: -5.0), size: CGSize(width: 32.0, height: 32.0))
|
|
||||||
}
|
|
||||||
} else if let checkNode = self.checkNode {
|
|
||||||
updated = true
|
|
||||||
self.checkNode = nil
|
|
||||||
if wasAnimating != self.isAnimating {
|
|
||||||
checkNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak checkNode] _ in
|
|
||||||
checkNode?.removeFromSupernode()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
checkNode.removeFromSupernode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if updated {
|
if updated {
|
||||||
self.setNeedsDisplay()
|
self.setNeedsDisplay()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateAnimating() {
|
private func updateAnimating() {
|
||||||
if self.shouldBeAnimating {
|
let timestamp = CACurrentMediaTime()
|
||||||
self.startTime = CACurrentMediaTime()
|
if let checkTransition = self.checkTransition {
|
||||||
if self.displayLink == nil {
|
if checkTransition.startTime + checkTransition.duration <= timestamp {
|
||||||
class DisplayLinkProxy: NSObject {
|
self.checkTransition = nil
|
||||||
var f: () -> Void
|
}
|
||||||
init(_ f: @escaping () -> Void) {
|
}
|
||||||
self.f = f
|
|
||||||
}
|
if self.shouldBeAnimating {
|
||||||
|
if self.isAnimating && self.startTime == nil {
|
||||||
@objc func displayLinkEvent() {
|
self.startTime = timestamp
|
||||||
self.f()
|
}
|
||||||
}
|
if self.displayLink == nil {
|
||||||
}
|
self.displayLink = ConstantDisplayLinkAnimator(update: { [weak self] in
|
||||||
let displayLink = CADisplayLink(target: DisplayLinkProxy({ [weak self] in
|
self?.updateAnimating()
|
||||||
self?.setNeedsDisplay()
|
self?.setNeedsDisplay()
|
||||||
}), selector: #selector(DisplayLinkProxy.displayLinkEvent))
|
})
|
||||||
displayLink.add(to: .main, forMode: .common)
|
self.displayLink?.isPaused = false
|
||||||
self.displayLink = displayLink
|
self.setNeedsDisplay()
|
||||||
}
|
}
|
||||||
self.setNeedsDisplay()
|
|
||||||
} else if let displayLink = self.displayLink {
|
} else if let displayLink = self.displayLink {
|
||||||
self.startTime = nil
|
self.startTime = nil
|
||||||
displayLink.invalidate()
|
displayLink.invalidate()
|
||||||
@ -228,12 +254,13 @@ private final class ChatMessagePollOptionRadioNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
override public func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
||||||
if let staticColor = self.staticColor, let animatedColor = self.animatedColor {
|
if let staticColor = self.staticColor, let animatedColor = self.animatedColor, let fillColor = self.fillColor, let foregroundColor = self.foregroundColor {
|
||||||
|
let timestamp = CACurrentMediaTime()
|
||||||
var offset: Double?
|
var offset: Double?
|
||||||
if let startTime = self.startTime {
|
if let startTime = self.startTime {
|
||||||
offset = CACurrentMediaTime() - startTime
|
offset = CACurrentMediaTime() - startTime
|
||||||
}
|
}
|
||||||
return ChatMessagePollOptionRadioNodeParameters(staticColor: self.checkNode == nil ? staticColor : .clear, animatedColor: animatedColor, offset: offset)
|
return ChatMessagePollOptionRadioNodeParameters(timestamp: timestamp, staticColor: staticColor, animatedColor: animatedColor, fillColor: fillColor, foregroundColor: foregroundColor, offset: offset, isChecked: self.isChecked, checkTransition: self.checkTransition)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -312,8 +339,73 @@ private final class ChatMessagePollOptionRadioNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
context.setStrokeColor(parameters.staticColor.cgColor)
|
if let isChecked = parameters.isChecked {
|
||||||
context.strokeEllipse(in: CGRect(origin: CGPoint(x: 0.5, y: 0.5), size: CGSize(width: bounds.width - 1.0, height: bounds.height - 1.0)))
|
let checkedT: CGFloat
|
||||||
|
let fromValue: CGFloat
|
||||||
|
let toValue: CGFloat
|
||||||
|
let fromAlpha: CGFloat
|
||||||
|
let toAlpha: CGFloat
|
||||||
|
if let checkTransition = parameters.checkTransition {
|
||||||
|
checkedT = CGFloat(max(0.0, min(1.0, (parameters.timestamp - checkTransition.startTime) / checkTransition.duration)))
|
||||||
|
fromValue = checkTransition.previousValue ? bounds.width : 0.0
|
||||||
|
fromAlpha = checkTransition.previousValue ? 1.0 : 0.0
|
||||||
|
toValue = checkTransition.updatedValue ? bounds.width : 0.0
|
||||||
|
toAlpha = checkTransition.updatedValue ? 1.0 : 0.0
|
||||||
|
} else {
|
||||||
|
checkedT = 1.0
|
||||||
|
fromValue = isChecked ? bounds.width : 0.0
|
||||||
|
fromAlpha = isChecked ? 1.0 : 0.0
|
||||||
|
toValue = isChecked ? bounds.width : 0.0
|
||||||
|
toAlpha = isChecked ? 1.0 : 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
let diameter = fromValue * (1.0 - checkedT) + toValue * checkedT
|
||||||
|
let alpha = fromAlpha * (1.0 - checkedT) + toAlpha * checkedT
|
||||||
|
|
||||||
|
if abs(diameter - 1.0) > CGFloat.ulpOfOne {
|
||||||
|
context.setStrokeColor(parameters.staticColor.cgColor)
|
||||||
|
context.strokeEllipse(in: CGRect(origin: CGPoint(x: 0.5, y: 0.5), size: CGSize(width: bounds.width - 1.0, height: bounds.height - 1.0)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !diameter.isZero {
|
||||||
|
context.setFillColor(parameters.fillColor.withAlphaComponent(alpha).cgColor)
|
||||||
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: (bounds.width - diameter) / 2.0, y: (bounds.width - diameter) / 2.0), size: CGSize(width: diameter, height: diameter)))
|
||||||
|
|
||||||
|
context.setLineWidth(1.5)
|
||||||
|
context.setLineJoin(.round)
|
||||||
|
context.setLineCap(.round)
|
||||||
|
|
||||||
|
context.setStrokeColor(parameters.foregroundColor.withAlphaComponent(alpha).cgColor)
|
||||||
|
if parameters.foregroundColor.alpha.isZero {
|
||||||
|
context.setBlendMode(.clear)
|
||||||
|
}
|
||||||
|
let startPoint = CGPoint(x: 6.0, y: 12.13)
|
||||||
|
let centerPoint = CGPoint(x: 9.28, y: 15.37)
|
||||||
|
let endPoint = CGPoint(x: 16.0, y: 8.0)
|
||||||
|
|
||||||
|
let pathT = alpha
|
||||||
|
let pathMiddleT: CGFloat = 0.4
|
||||||
|
|
||||||
|
context.move(to: startPoint)
|
||||||
|
if pathT >= pathMiddleT {
|
||||||
|
context.addLine(to: centerPoint)
|
||||||
|
|
||||||
|
let pathEndT = (pathT - pathMiddleT) / (1.0 - pathMiddleT)
|
||||||
|
if pathEndT >= 1.0 {
|
||||||
|
context.addLine(to: endPoint)
|
||||||
|
} else {
|
||||||
|
context.addLine(to: CGPoint(x: (1.0 - pathEndT) * centerPoint.x + pathEndT * endPoint.x, y: (1.0 - pathEndT) * centerPoint.y + pathEndT * endPoint.y))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
context.addLine(to: CGPoint(x: (1.0 - pathT) * startPoint.x + pathT * centerPoint.x, y: (1.0 - pathT) * startPoint.y + pathT * centerPoint.y))
|
||||||
|
}
|
||||||
|
context.strokePath()
|
||||||
|
context.setBlendMode(.normal)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
context.setStrokeColor(parameters.staticColor.cgColor)
|
||||||
|
context.strokeEllipse(in: CGRect(origin: CGPoint(x: 0.5, y: 0.5), size: CGSize(width: bounds.width - 1.0, height: bounds.height - 1.0)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -574,7 +666,7 @@ private final class ChatMessagePollOptionNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
let radioSize: CGFloat = 22.0
|
let radioSize: CGFloat = 22.0
|
||||||
radioNode.frame = CGRect(origin: CGPoint(x: 12.0, y: 12.0), size: CGSize(width: radioSize, height: radioSize))
|
radioNode.frame = CGRect(origin: CGPoint(x: 12.0, y: 12.0), size: CGSize(width: radioSize, height: radioSize))
|
||||||
radioNode.update(staticColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.radioButton : presentationData.theme.theme.chat.message.outgoing.polls.radioButton, animatedColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.radioProgress : presentationData.theme.theme.chat.message.outgoing.polls.radioProgress, foregroundColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.barIconForeground : presentationData.theme.theme.chat.message.outgoing.polls.barIconForeground, isSelectable: isSelectable, isAnimating: inProgress)
|
radioNode.update(staticColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.radioButton : presentationData.theme.theme.chat.message.outgoing.polls.radioButton, animatedColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.radioProgress : presentationData.theme.theme.chat.message.outgoing.polls.radioProgress, fillColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.bar : presentationData.theme.theme.chat.message.outgoing.polls.bar, foregroundColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.barIconForeground : presentationData.theme.theme.chat.message.outgoing.polls.barIconForeground, isSelectable: isSelectable, isAnimating: inProgress)
|
||||||
} else if let radioNode = node.radioNode {
|
} else if let radioNode = node.radioNode {
|
||||||
node.radioNode = nil
|
node.radioNode = nil
|
||||||
if animated {
|
if animated {
|
||||||
|
@ -305,7 +305,7 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
|
|||||||
params.navigationController?.pushViewController(controller)
|
params.navigationController?.pushViewController(controller)
|
||||||
return true
|
return true
|
||||||
case let .stickerPack(reference):
|
case let .stickerPack(reference):
|
||||||
let controller = StickerPackScreen(context: params.context, mainStickerPack: reference, stickerPacks: [reference], sendSticker: params.sendSticker, actionPerformed: { info, items, action in
|
let controller = StickerPackScreen(context: params.context, mainStickerPack: reference, stickerPacks: [reference], parentNavigationController: params.navigationController, sendSticker: params.sendSticker, actionPerformed: { info, items, action in
|
||||||
let presentationData = params.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = params.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
var animateInAsReplacement = false
|
var animateInAsReplacement = false
|
||||||
if let navigationController = params.navigationController {
|
if let navigationController = params.navigationController {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user