mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Merge commit '15b708791d7139840b91112cdf06950e30f9dcb0'
This commit is contained in:
commit
41fbe0ef76
@ -7077,3 +7077,7 @@ Sorry for the inconvenience.";
|
||||
"AuthSessions.View.AcceptSecretChatsInfo" = "You can disable the acception of incoming secret chats on this device.";
|
||||
|
||||
"Conversation.SendMesageAs" = "Send Message As...";
|
||||
"Conversation.InviteRequestAdminGroup" = "%1$@ is an admin of %2$@, a group you requested to join.";
|
||||
"Conversation.InviteRequestAdminChannel" = "%1$@ is an admin of %2$@, a channel you requested to join.";
|
||||
"Conversation.InviteRequestInfo" = "You received this message because you requested to join %1$@ on %2$@.";
|
||||
"Conversation.InviteRequestInfoConfirm" = "I understand";
|
||||
|
@ -110,56 +110,56 @@ final class ItemListRecentSessionItem: ListViewItem, ItemListItem {
|
||||
}
|
||||
}
|
||||
|
||||
func iconForSession(_ session: RecentAccountSession) -> (UIImage?, String?) {
|
||||
func iconForSession(_ session: RecentAccountSession) -> (UIImage?, UIColor?, String?, [String: UIColor]?) {
|
||||
let platform = session.platform.lowercased()
|
||||
let device = session.deviceModel.lowercased()
|
||||
let systemVersion = session.systemVersion.lowercased()
|
||||
if device.contains("xbox") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Xbox"), nil)
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Xbox"), UIColor(rgb: 0x35c759), nil, nil)
|
||||
}
|
||||
if device.contains("chrome") && !device.contains("chromebook") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Chrome"), "device_chrome")
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Chrome"), UIColor(rgb: 0x35c759), "device_chrome", nil)
|
||||
}
|
||||
if device.contains("brave") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Brave"), nil)
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Brave"), UIColor(rgb: 0xff9500), nil, nil)
|
||||
}
|
||||
if device.contains("vivaldi") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Vivaldi"), nil)
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Vivaldi"), UIColor(rgb: 0xff3c30), nil, nil)
|
||||
}
|
||||
if device.contains("safari") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Safari"), "device_safari")
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Safari"), UIColor(rgb: 0x0079ff), "device_safari", nil)
|
||||
}
|
||||
if device.contains("firefox") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Firefox"), nil)
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Firefox"), UIColor(rgb: 0xff9500), "device_firefox", nil)
|
||||
}
|
||||
if device.contains("opera") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Opera"), nil)
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Opera"), UIColor(rgb: 0xff3c30), nil, nil)
|
||||
}
|
||||
if platform.contains("android") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Android"), "device_android")
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Android"), UIColor(rgb: 0x35c759), "device_android", nil)
|
||||
}
|
||||
if device.contains("iphone") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/iPhone"), "device_iphone")
|
||||
return (UIImage(bundleImageName: "Settings/Devices/iPhone"), UIColor(rgb: 0x0079ff), "device_iphone", nil)
|
||||
}
|
||||
if device.contains("ipad") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/iPad"), "device_ipad")
|
||||
return (UIImage(bundleImageName: "Settings/Devices/iPad"), UIColor(rgb: 0x0079ff), "device_ipad", nil)
|
||||
}
|
||||
if (platform.contains("macos") || systemVersion.contains("macos")) && device.contains("mac") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Mac"), "device_mac")
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Mac"), UIColor(rgb: 0x0079ff), "device_mac", nil)
|
||||
}
|
||||
if platform.contains("ios") || platform.contains("macos") || systemVersion.contains("macos") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/iOS"), nil)
|
||||
return (UIImage(bundleImageName: "Settings/Devices/iOS"), UIColor(rgb: 0x0079ff), nil, nil)
|
||||
}
|
||||
if platform.contains("ubuntu") || systemVersion.contains("ubuntu") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Ubuntu"), nil)
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Ubuntu"), UIColor(rgb: 0xff9500), "device_ubuntu", nil)
|
||||
}
|
||||
if platform.contains("linux") || systemVersion.contains("linux") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Linux"), nil)
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Linux"), UIColor(rgb: 0x8e8e93), "device_linux", nil)
|
||||
}
|
||||
if platform.contains("windows") || systemVersion.contains("windows") {
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Windows"), nil)
|
||||
return (UIImage(bundleImageName: "Settings/Devices/Windows"), UIColor(rgb: 0x0079ff), "device_windows", nil)
|
||||
}
|
||||
return (nil, nil)
|
||||
return (nil, nil, nil, nil)
|
||||
}
|
||||
|
||||
private func trimmedLocationName(_ session: RecentAccountSession) -> String {
|
||||
|
@ -30,7 +30,10 @@ private final class RecentSessionsControllerArguments {
|
||||
let openOtherAppsUrl: () -> Void
|
||||
let setupAuthorizationTTL: () -> Void
|
||||
|
||||
init(context: AccountContext, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void, terminateOtherSessions: @escaping () -> Void, openSession: @escaping (RecentAccountSession) -> Void, openWebSession: @escaping (WebAuthorization, Peer?) -> Void, removeWebSession: @escaping (Int64) -> Void, terminateAllWebSessions: @escaping () -> Void, addDevice: @escaping () -> Void, openOtherAppsUrl: @escaping () -> Void, setupAuthorizationTTL: @escaping () -> Void) {
|
||||
let openDesktopLink: () -> Void
|
||||
let openWebLink: () -> Void
|
||||
|
||||
init(context: AccountContext, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void, terminateOtherSessions: @escaping () -> Void, openSession: @escaping (RecentAccountSession) -> Void, openWebSession: @escaping (WebAuthorization, Peer?) -> Void, removeWebSession: @escaping (Int64) -> Void, terminateAllWebSessions: @escaping () -> Void, addDevice: @escaping () -> Void, openOtherAppsUrl: @escaping () -> Void, setupAuthorizationTTL: @escaping () -> Void, openDesktopLink: @escaping () -> Void, openWebLink: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.setSessionIdWithRevealedOptions = setSessionIdWithRevealedOptions
|
||||
self.removeSession = removeSession
|
||||
@ -47,6 +50,9 @@ private final class RecentSessionsControllerArguments {
|
||||
self.openOtherAppsUrl = openOtherAppsUrl
|
||||
|
||||
self.setupAuthorizationTTL = setupAuthorizationTTL
|
||||
|
||||
self.openDesktopLink = openDesktopLink
|
||||
self.openWebLink = openWebLink
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +62,7 @@ private enum RecentSessionsMode: Int {
|
||||
}
|
||||
|
||||
private enum RecentSessionsSection: Int32 {
|
||||
case header
|
||||
case currentSession
|
||||
case pendingSessions
|
||||
case otherSessions
|
||||
@ -82,6 +89,7 @@ private struct SortIndex: Comparable {
|
||||
}
|
||||
|
||||
private enum RecentSessionsEntry: ItemListNodeEntry {
|
||||
case header(SortIndex, String)
|
||||
case currentSessionHeader(SortIndex, String)
|
||||
case currentSession(SortIndex, PresentationStrings, PresentationDateTimeFormat, RecentAccountSession)
|
||||
case terminateOtherSessions(SortIndex, String)
|
||||
@ -101,6 +109,8 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
case .header:
|
||||
return RecentSessionsSection.header.rawValue
|
||||
case .currentSessionHeader, .currentSession, .terminateOtherSessions, .terminateAllWebSessions, .currentAddDevice, .currentSessionInfo:
|
||||
return RecentSessionsSection.currentSession.rawValue
|
||||
case .pendingSessionsHeader, .pendingSession, .pendingSessionsInfo:
|
||||
@ -114,28 +124,30 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
|
||||
|
||||
var stableId: RecentSessionsEntryStableId {
|
||||
switch self {
|
||||
case .currentSessionHeader:
|
||||
case .header:
|
||||
return .index(0)
|
||||
case .currentSession:
|
||||
case .currentSessionHeader:
|
||||
return .index(1)
|
||||
case .terminateOtherSessions:
|
||||
case .currentSession:
|
||||
return .index(2)
|
||||
case .terminateAllWebSessions:
|
||||
case .terminateOtherSessions:
|
||||
return .index(3)
|
||||
case .currentAddDevice:
|
||||
case .terminateAllWebSessions:
|
||||
return .index(4)
|
||||
case .currentSessionInfo:
|
||||
case .currentAddDevice:
|
||||
return .index(5)
|
||||
case .pendingSessionsHeader:
|
||||
case .currentSessionInfo:
|
||||
return .index(6)
|
||||
case .pendingSessionsHeader:
|
||||
return .index(7)
|
||||
case let .pendingSession(_, _, _, _, session, _, _, _):
|
||||
return .session(session.hash)
|
||||
case .pendingSessionsInfo:
|
||||
return .index(7)
|
||||
case .otherSessionsHeader:
|
||||
return .index(8)
|
||||
case .addDevice:
|
||||
case .otherSessionsHeader:
|
||||
return .index(9)
|
||||
case .addDevice:
|
||||
return .index(10)
|
||||
case let .session(_, _, _, _, session, _, _, _):
|
||||
return .session(session.hash)
|
||||
case let .website(_, _, _, _, _, website, _, _, _, _):
|
||||
@ -143,14 +155,16 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
|
||||
case .devicesInfo:
|
||||
return .devicesInfo
|
||||
case .ttlHeader:
|
||||
return .index(10)
|
||||
case .ttlTimeout:
|
||||
return .index(11)
|
||||
case .ttlTimeout:
|
||||
return .index(12)
|
||||
}
|
||||
}
|
||||
|
||||
var sortIndex: SortIndex {
|
||||
switch self {
|
||||
case let .header(index, _):
|
||||
return index
|
||||
case let .currentSessionHeader(index, _):
|
||||
return index
|
||||
case let .currentSession(index, _, _, _):
|
||||
@ -188,6 +202,12 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
|
||||
|
||||
static func ==(lhs: RecentSessionsEntry, rhs: RecentSessionsEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .header(lhsSortIndex, lhsText):
|
||||
if case let .header(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .currentSessionHeader(lhsSortIndex, lhsText):
|
||||
if case let .currentSessionHeader(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText {
|
||||
return true
|
||||
@ -294,6 +314,10 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
|
||||
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||
let arguments = arguments as! RecentSessionsControllerArguments
|
||||
switch self {
|
||||
case let .header(_, text):
|
||||
return RecentSessionsHeaderItem(context: arguments.context, theme: presentationData.theme, text: text, animationName: "Requests", sectionId: self.section, linkAction: { _ in
|
||||
arguments.openDesktopLink()
|
||||
})
|
||||
case let .currentSessionHeader(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .currentSession(_, _, dateTimeFormat, session):
|
||||
@ -735,6 +759,10 @@ public func recentSessionsController(context: AccountContext, activeSessionsCont
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
])
|
||||
presentControllerImpl?(controller, nil)
|
||||
}, openDesktopLink: {
|
||||
|
||||
}, openWebLink: {
|
||||
|
||||
})
|
||||
|
||||
let previousMode = Atomic<RecentSessionsMode>(value: .sessions)
|
||||
|
@ -0,0 +1,169 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import ItemListUI
|
||||
import PresentationDataUtils
|
||||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import AccountContext
|
||||
import Markdown
|
||||
import TextFormat
|
||||
|
||||
class RecentSessionsHeaderItem: ListViewItem, ItemListItem {
|
||||
let context: AccountContext
|
||||
let theme: PresentationTheme
|
||||
let text: String
|
||||
let animationName: String
|
||||
let sectionId: ItemListSectionId
|
||||
let linkAction: ((ItemListTextItemLinkAction) -> Void)?
|
||||
|
||||
init(context: AccountContext, theme: PresentationTheme, text: String, animationName: String, sectionId: ItemListSectionId, linkAction: ((ItemListTextItemLinkAction) -> Void)? = nil) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.text = text
|
||||
self.animationName = animationName
|
||||
self.sectionId = sectionId
|
||||
self.linkAction = linkAction
|
||||
}
|
||||
|
||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||
async {
|
||||
let node = RecentSessionsHeaderItemNode()
|
||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||
|
||||
node.contentSize = layout.contentSize
|
||||
node.insets = layout.insets
|
||||
|
||||
Queue.mainQueue().async {
|
||||
completion(node, {
|
||||
return (nil, { _ in apply() })
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||
Queue.mainQueue().async {
|
||||
guard let nodeValue = node() as? RecentSessionsHeaderItemNode else {
|
||||
assertionFailure()
|
||||
return
|
||||
}
|
||||
|
||||
let makeLayout = nodeValue.asyncLayout()
|
||||
|
||||
async {
|
||||
let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||
Queue.mainQueue().async {
|
||||
completion(layout, { _ in
|
||||
apply()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let titleFont = Font.regular(13.0)
|
||||
|
||||
class RecentSessionsHeaderItemNode: ListViewItemNode {
|
||||
private let titleNode: TextNode
|
||||
private var animationNode: AnimatedStickerNode
|
||||
|
||||
private var item: RecentSessionsHeaderItem?
|
||||
|
||||
init() {
|
||||
self.titleNode = TextNode()
|
||||
self.titleNode.isUserInteractionEnabled = false
|
||||
self.titleNode.contentMode = .left
|
||||
self.titleNode.contentsScale = UIScreen.main.scale
|
||||
|
||||
self.animationNode = AnimatedStickerNode()
|
||||
|
||||
super.init(layerBacked: false, dynamicBounce: false)
|
||||
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.animationNode)
|
||||
}
|
||||
|
||||
override public func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
|
||||
recognizer.tapActionAtPoint = { _ in
|
||||
return .waitForSingleTap
|
||||
}
|
||||
self.view.addGestureRecognizer(recognizer)
|
||||
}
|
||||
|
||||
func asyncLayout() -> (_ item: RecentSessionsHeaderItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||
|
||||
return { item, params, neighbors in
|
||||
let leftInset: CGFloat = 32.0 + params.leftInset
|
||||
let topInset: CGFloat = 92.0
|
||||
|
||||
let attributedText = parseMarkdownIntoAttributedString(item.text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: titleFont, textColor: item.theme.list.freeTextColor), bold: MarkdownAttributeSet(font: titleFont, textColor: item.theme.list.freeTextColor), link: MarkdownAttributeSet(font: titleFont, textColor: item.theme.list.itemAccentColor), linkAttribute: { contents in
|
||||
return (TelegramTextAttributes.URL, contents)
|
||||
}))
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - leftInset * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let contentSize = CGSize(width: params.width, height: topInset + titleLayout.size.height)
|
||||
let insets = itemListNeighborsGroupedInsets(neighbors, params)
|
||||
|
||||
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
|
||||
|
||||
return (layout, { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if strongSelf.item == nil {
|
||||
strongSelf.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: item.animationName), width: 192, height: 192, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
|
||||
strongSelf.animationNode.visibility = true
|
||||
}
|
||||
strongSelf.item = item
|
||||
strongSelf.accessibilityLabel = attributedText.string
|
||||
|
||||
let iconSize = CGSize(width: 96.0, height: 96.0)
|
||||
strongSelf.animationNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: -10.0), size: iconSize)
|
||||
strongSelf.animationNode.updateLayout(size: iconSize)
|
||||
|
||||
let _ = titleApply()
|
||||
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleLayout.size.width) / 2.0), y: topInset + 8.0), size: titleLayout.size)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||
}
|
||||
|
||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
@objc private func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||
switch recognizer.state {
|
||||
case .ended:
|
||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||
switch gesture {
|
||||
case .tap:
|
||||
let titleFrame = self.titleNode.frame
|
||||
if let item = self.item, titleFrame.contains(location) {
|
||||
if let (_, attributes) = self.titleNode.attributesAtPoint(CGPoint(x: location.x - titleFrame.minX, y: location.y - titleFrame.minY)) {
|
||||
if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||
item.linkAction?(.tap(url))
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
@ -162,6 +162,7 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let contentBackgroundNode: ASDisplayNode
|
||||
private var iconNode: ASImageNode?
|
||||
private var animationBackgroundNode: ASDisplayNode?
|
||||
private var animationNode: AnimationNode?
|
||||
private var avatarNode: AvatarNode?
|
||||
private let titleNode: ImmediateTextNode
|
||||
@ -304,10 +305,17 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe
|
||||
location = session.country
|
||||
ip = session.ip
|
||||
|
||||
let (icon, animationName) = iconForSession(session)
|
||||
let (icon, backgroundColor, animationName, colors) = iconForSession(session)
|
||||
if let animationName = animationName {
|
||||
let animationNode = AnimationNode(animation: animationName, colors: [:], scale: 1.0)
|
||||
let animationNode = AnimationNode(animation: animationName, colors: colors ?? ["apple.apple.Заливка 1": backgroundColor ?? .black], scale: 1.0)
|
||||
self.animationNode = animationNode
|
||||
|
||||
animationNode.animationView()?.logHierarchyKeypaths()
|
||||
|
||||
let animationBackgroundNode = ASDisplayNode()
|
||||
animationBackgroundNode.cornerRadius = 20.0
|
||||
animationBackgroundNode.backgroundColor = backgroundColor
|
||||
self.animationBackgroundNode = animationBackgroundNode
|
||||
} else if let icon = icon {
|
||||
let iconNode = ASImageNode()
|
||||
iconNode.displaysAsynchronously = false
|
||||
@ -424,6 +432,7 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe
|
||||
self.topContentContainerNode.addSubnode(self.cancelButton)
|
||||
|
||||
self.iconNode.flatMap { self.contentContainerNode.addSubnode($0) }
|
||||
self.animationBackgroundNode.flatMap { self.contentContainerNode.addSubnode($0) }
|
||||
self.animationNode.flatMap { self.contentContainerNode.addSubnode($0) }
|
||||
self.avatarNode.flatMap { self.contentContainerNode.addSubnode($0) }
|
||||
|
||||
@ -469,6 +478,10 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe
|
||||
|
||||
let ipGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.handleIpLongPress(_:)))
|
||||
self.ipValueNode.view.addGestureRecognizer(ipGestureRecognizer)
|
||||
|
||||
if let animationNode = self.animationNode {
|
||||
animationNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.animationPressed)))
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func handleTitleLongPress(_ gestureRecognizer: UILongPressGestureRecognizer) {
|
||||
@ -560,6 +573,12 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe
|
||||
self.terminateButton.updateTheme(SolidRoundedButtonTheme(backgroundColor: self.presentationData.theme.list.itemBlocksBackgroundColor, foregroundColor: self.presentationData.theme.list.itemDestructiveColor))
|
||||
}
|
||||
|
||||
@objc func animationPressed() {
|
||||
if let animationNode = self.animationNode, !animationNode.isPlaying {
|
||||
animationNode.playOnce()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func cancelButtonPressed() {
|
||||
self.animateOut()
|
||||
}
|
||||
@ -637,6 +656,7 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let isFirstTime = self.containerLayout == nil
|
||||
self.containerLayout = (layout, navigationBarHeight)
|
||||
|
||||
var insets = layout.insets(options: [.statusBar, .input])
|
||||
@ -655,9 +675,17 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe
|
||||
|
||||
if let iconNode = self.iconNode {
|
||||
transition.updateFrame(node: iconNode, frame: iconFrame)
|
||||
} else if let animationNode = self.animationNode {
|
||||
} else if let animationNode = self.animationNode, let animationBackgroundNode = self.animationBackgroundNode {
|
||||
transition.updateFrame(node: animationNode, frame: iconFrame)
|
||||
animationNode.loop()
|
||||
transition.updateFrame(node: animationBackgroundNode, frame: iconFrame)
|
||||
if #available(iOS 13.0, *) {
|
||||
animationBackgroundNode.layer.cornerCurve = .continuous
|
||||
}
|
||||
if isFirstTime {
|
||||
Queue.mainQueue().after(0.5) {
|
||||
animationNode.playOnce()
|
||||
}
|
||||
}
|
||||
} else if let avatarNode = self.avatarNode {
|
||||
transition.updateFrame(node: avatarNode, frame: iconFrame)
|
||||
}
|
||||
@ -715,7 +743,7 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe
|
||||
|
||||
var contentHeight = locationInfoTextFrame.maxY + bottomInset + 64.0
|
||||
|
||||
if case .session = self.subject {
|
||||
if let _ = self.secretChatsBackgroundNode.supernode {
|
||||
let secretFrame = CGRect(x: inset, y: locationInfoTextFrame.maxY + 59.0, width: width - inset * 2.0, height: fieldItemHeight)
|
||||
transition.updateFrame(node: self.secretChatsBackgroundNode, frame: secretFrame)
|
||||
|
||||
|
@ -6,7 +6,7 @@ import SwiftSignalKit
|
||||
extension PeerStatusSettings {
|
||||
init(apiSettings: Api.PeerSettings) {
|
||||
switch apiSettings {
|
||||
case let .peerSettings(flags, geoDistance, _, _):
|
||||
case let .peerSettings(flags, geoDistance, requestChat, requestChatDate):
|
||||
var result = PeerStatusSettings.Flags()
|
||||
if (flags & (1 << 1)) != 0 {
|
||||
result.insert(.canAddContact)
|
||||
@ -32,7 +32,7 @@ extension PeerStatusSettings {
|
||||
if (flags & (1 << 8)) != 0 {
|
||||
result.insert(.suggestAddMembers)
|
||||
}
|
||||
self = PeerStatusSettings(flags: result, geoDistance: geoDistance)
|
||||
self = PeerStatusSettings(flags: result, geoDistance: geoDistance, requestChatPeerId: requestChat?.peerId, requestChatDate: requestChatDate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3302,67 +3302,63 @@ func replayFinalState(
|
||||
let namespace: ItemCollectionId.Namespace
|
||||
var items: [ItemCollectionItem] = []
|
||||
let info: StickerPackCollectionInfo
|
||||
switch apiSet {
|
||||
case .stickerSetNotModified:
|
||||
preconditionFailure()
|
||||
case let .stickerSet(set, packs, documents):
|
||||
var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:]
|
||||
for pack in packs {
|
||||
switch pack {
|
||||
case let .stickerPack(text, fileIds):
|
||||
let key = ValueBoxKey(text).toMemoryBuffer()
|
||||
for fileId in fileIds {
|
||||
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)
|
||||
if indexKeysByFile[mediaId] == nil {
|
||||
indexKeysByFile[mediaId] = [key]
|
||||
} else {
|
||||
indexKeysByFile[mediaId]!.append(key)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for apiDocument in documents {
|
||||
if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id {
|
||||
let fileIndexKeys: [MemoryBuffer]
|
||||
if let indexKeys = indexKeysByFile[id] {
|
||||
fileIndexKeys = indexKeys
|
||||
if case let .stickerSet(set, packs, documents) = apiSet {
|
||||
var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:]
|
||||
for pack in packs {
|
||||
switch pack {
|
||||
case let .stickerPack(text, fileIds):
|
||||
let key = ValueBoxKey(text).toMemoryBuffer()
|
||||
for fileId in fileIds {
|
||||
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)
|
||||
if indexKeysByFile[mediaId] == nil {
|
||||
indexKeysByFile[mediaId] = [key]
|
||||
} else {
|
||||
fileIndexKeys = []
|
||||
indexKeysByFile[mediaId]!.append(key)
|
||||
}
|
||||
items.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(items.count), id: id.id), file: file, indexKeys: fileIndexKeys))
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
switch set {
|
||||
case let .stickerSet(flags, _, _, _, _, _, _, _, _, _, _):
|
||||
if (flags & (1 << 3)) != 0 {
|
||||
namespace = Namespaces.ItemCollection.CloudMaskPacks
|
||||
} else {
|
||||
namespace = Namespaces.ItemCollection.CloudStickerPacks
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info = StickerPackCollectionInfo(apiSet: set, namespace: namespace)
|
||||
}
|
||||
for apiDocument in documents {
|
||||
if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id {
|
||||
let fileIndexKeys: [MemoryBuffer]
|
||||
if let indexKeys = indexKeysByFile[id] {
|
||||
fileIndexKeys = indexKeys
|
||||
} else {
|
||||
fileIndexKeys = []
|
||||
}
|
||||
items.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(items.count), id: id.id), file: file, indexKeys: fileIndexKeys))
|
||||
}
|
||||
}
|
||||
switch set {
|
||||
case let .stickerSet(flags, _, _, _, _, _, _, _, _, _, _):
|
||||
if (flags & (1 << 3)) != 0 {
|
||||
namespace = Namespaces.ItemCollection.CloudMaskPacks
|
||||
} else {
|
||||
namespace = Namespaces.ItemCollection.CloudStickerPacks
|
||||
}
|
||||
}
|
||||
|
||||
info = StickerPackCollectionInfo(apiSet: set, namespace: namespace)
|
||||
|
||||
if namespace == Namespaces.ItemCollection.CloudMaskPacks && syncMasks {
|
||||
continue loop
|
||||
} else if namespace == Namespaces.ItemCollection.CloudStickerPacks && syncStickers {
|
||||
continue loop
|
||||
if namespace == Namespaces.ItemCollection.CloudMaskPacks && syncMasks {
|
||||
continue loop
|
||||
} else if namespace == Namespaces.ItemCollection.CloudStickerPacks && syncStickers {
|
||||
continue loop
|
||||
}
|
||||
|
||||
var updatedInfos = transaction.getItemCollectionsInfos(namespace: info.id.namespace).map { $0.1 as! StickerPackCollectionInfo }
|
||||
if let index = updatedInfos.firstIndex(where: { $0.id == info.id }) {
|
||||
let currentInfo = updatedInfos[index]
|
||||
updatedInfos.remove(at: index)
|
||||
updatedInfos.insert(currentInfo, at: 0)
|
||||
} else {
|
||||
updatedInfos.insert(info, at: 0)
|
||||
transaction.replaceItemCollectionItems(collectionId: info.id, items: items)
|
||||
}
|
||||
transaction.replaceItemCollectionInfos(namespace: info.id.namespace, itemCollectionInfos: updatedInfos.map { ($0.id, $0) })
|
||||
}
|
||||
|
||||
var updatedInfos = transaction.getItemCollectionsInfos(namespace: info.id.namespace).map { $0.1 as! StickerPackCollectionInfo }
|
||||
if let index = updatedInfos.firstIndex(where: { $0.id == info.id }) {
|
||||
let currentInfo = updatedInfos[index]
|
||||
updatedInfos.remove(at: index)
|
||||
updatedInfos.insert(currentInfo, at: 0)
|
||||
} else {
|
||||
updatedInfos.insert(info, at: 0)
|
||||
transaction.replaceItemCollectionItems(collectionId: info.id, items: items)
|
||||
}
|
||||
transaction.replaceItemCollectionInfos(namespace: info.id.namespace, itemCollectionInfos: updatedInfos.map { ($0.id, $0) })
|
||||
case let .reorder(namespace, ids):
|
||||
let collectionNamespace: ItemCollectionId.Namespace
|
||||
switch namespace {
|
||||
|
@ -1235,7 +1235,7 @@ public final class AccountViewTracker {
|
||||
return
|
||||
}
|
||||
let queue = self.queue
|
||||
context.disposable.set(combineLatest(fetchAndUpdateSupplementalCachedPeerData(peerId: peerId, network: account.network, postbox: account.postbox), _internal_fetchAndUpdateCachedPeerData(accountPeerId: account.peerId, peerId: peerId, network: account.network, postbox: account.postbox)).start(next: { [weak self] supplementalStatus, cachedStatus in
|
||||
context.disposable.set(combineLatest(fetchAndUpdateSupplementalCachedPeerData(peerId: peerId, accountPeerId: account.peerId, network: account.network, postbox: account.postbox), _internal_fetchAndUpdateCachedPeerData(accountPeerId: account.peerId, peerId: peerId, network: account.network, postbox: account.postbox)).start(next: { [weak self] supplementalStatus, cachedStatus in
|
||||
queue.async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -1250,7 +1250,7 @@ public final class AccountViewTracker {
|
||||
}
|
||||
}
|
||||
|
||||
private func updateCachedPeerData(peerId: PeerId, viewId: Int32, hasCachedData: Bool) {
|
||||
private func updateCachedPeerData(peerId: PeerId, accountPeerId: PeerId, viewId: Int32, hasCachedData: Bool) {
|
||||
self.queue.async {
|
||||
let context: PeerCachedDataContext
|
||||
var dataUpdated = false
|
||||
@ -1277,7 +1277,7 @@ public final class AccountViewTracker {
|
||||
return
|
||||
}
|
||||
let queue = self.queue
|
||||
context.disposable.set(combineLatest(fetchAndUpdateSupplementalCachedPeerData(peerId: peerId, network: account.network, postbox: account.postbox), _internal_fetchAndUpdateCachedPeerData(accountPeerId: account.peerId, peerId: peerId, network: account.network, postbox: account.postbox)).start(next: { [weak self] supplementalStatus, cachedStatus in
|
||||
context.disposable.set(combineLatest(fetchAndUpdateSupplementalCachedPeerData(peerId: peerId, accountPeerId: accountPeerId, network: account.network, postbox: account.postbox), _internal_fetchAndUpdateCachedPeerData(accountPeerId: account.peerId, peerId: peerId, network: account.network, postbox: account.postbox)).start(next: { [weak self] supplementalStatus, cachedStatus in
|
||||
queue.async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -1551,6 +1551,7 @@ public final class AccountViewTracker {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return withState(signal, { [weak self] () -> Int32 in
|
||||
if let strongSelf = self {
|
||||
return OSAtomicIncrement32(&strongSelf.nextViewId)
|
||||
@ -1558,8 +1559,8 @@ public final class AccountViewTracker {
|
||||
return -1
|
||||
}
|
||||
}, next: { [weak self] next, viewId in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateCachedPeerData(peerId: peerId, viewId: viewId, hasCachedData: next.cachedData != nil)
|
||||
if let strongSelf = self, let account = strongSelf.account {
|
||||
strongSelf.updateCachedPeerData(peerId: peerId, accountPeerId: account.peerId, viewId: viewId, hasCachedData: next.cachedData != nil)
|
||||
}
|
||||
}, disposed: { [weak self] viewId in
|
||||
if let strongSelf = self {
|
||||
|
@ -32,8 +32,7 @@ private enum RequestUpdateMessageReactionError {
|
||||
}
|
||||
|
||||
private func requestUpdateMessageReaction(postbox: Postbox, network: Network, stateManager: AccountStateManager, messageId: MessageId) -> Signal<Never, RequestUpdateMessageReactionError> {
|
||||
return .complete()
|
||||
/*return postbox.transaction { transaction -> (Peer, String?)? in
|
||||
return postbox.transaction { transaction -> (Peer, String?)? in
|
||||
guard let peer = transaction.getPeer(messageId.peerId) else {
|
||||
return nil
|
||||
}
|
||||
@ -82,14 +81,14 @@ private func requestUpdateMessageReaction(postbox: Postbox, network: Network, st
|
||||
if let reactions = reactions {
|
||||
attributes.append(reactions)
|
||||
}
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
stateManager.addUpdates(result)
|
||||
}
|
||||
|> castError(RequestUpdateMessageReactionError.self)
|
||||
|> ignoreValues
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
private final class ManagedApplyPendingMessageReactionsActionsHelper {
|
||||
|
@ -64,7 +64,7 @@ public final class CachedUserData: CachedPeerData {
|
||||
public let autoremoveTimeout: CachedPeerAutoremoveTimeout
|
||||
public let themeEmoticon: String?
|
||||
|
||||
public let peerIds = Set<PeerId>()
|
||||
public let peerIds: Set<PeerId>
|
||||
public let messageIds: Set<MessageId>
|
||||
public let associatedHistoryMessageId: MessageId? = nil
|
||||
|
||||
@ -82,6 +82,7 @@ public final class CachedUserData: CachedPeerData {
|
||||
self.hasScheduledMessages = false
|
||||
self.autoremoveTimeout = .unknown
|
||||
self.themeEmoticon = nil
|
||||
self.peerIds = Set()
|
||||
self.messageIds = Set()
|
||||
}
|
||||
|
||||
@ -100,6 +101,12 @@ public final class CachedUserData: CachedPeerData {
|
||||
self.autoremoveTimeout = autoremoveTimeout
|
||||
self.themeEmoticon = themeEmoticon
|
||||
|
||||
var peerIds = Set<PeerId>()
|
||||
if let requestChatPeerId = peerStatusSettings?.requestChatPeerId {
|
||||
peerIds.insert(requestChatPeerId)
|
||||
}
|
||||
self.peerIds = peerIds
|
||||
|
||||
var messageIds = Set<MessageId>()
|
||||
if let pinnedMessageId = self.pinnedMessageId {
|
||||
messageIds.insert(pinnedMessageId)
|
||||
@ -132,6 +139,12 @@ public final class CachedUserData: CachedPeerData {
|
||||
self.autoremoveTimeout = decoder.decodeObjectForKey("artv", decoder: CachedPeerAutoremoveTimeout.init(decoder:)) as? CachedPeerAutoremoveTimeout ?? .unknown
|
||||
self.themeEmoticon = decoder.decodeOptionalStringForKey("te")
|
||||
|
||||
var peerIds = Set<PeerId>()
|
||||
if let requestChatPeerId = self.peerStatusSettings?.requestChatPeerId {
|
||||
peerIds.insert(requestChatPeerId)
|
||||
}
|
||||
self.peerIds = peerIds
|
||||
|
||||
var messageIds = Set<MessageId>()
|
||||
if let pinnedMessageId = self.pinnedMessageId {
|
||||
messageIds.insert(pinnedMessageId)
|
||||
|
@ -21,20 +21,28 @@ public struct PeerStatusSettings: PostboxCoding, Equatable {
|
||||
|
||||
public var flags: PeerStatusSettings.Flags
|
||||
public var geoDistance: Int32?
|
||||
public var requestChatPeerId: PeerId?
|
||||
public var requestChatDate: Int32?
|
||||
|
||||
public init() {
|
||||
self.flags = PeerStatusSettings.Flags()
|
||||
self.geoDistance = nil
|
||||
self.requestChatPeerId = nil
|
||||
self.requestChatDate = nil
|
||||
}
|
||||
|
||||
public init(flags: PeerStatusSettings.Flags, geoDistance: Int32? = nil) {
|
||||
public init(flags: PeerStatusSettings.Flags, geoDistance: Int32? = nil, requestChatPeerId: PeerId? = nil, requestChatDate: Int32? = nil) {
|
||||
self.flags = flags
|
||||
self.geoDistance = geoDistance
|
||||
self.requestChatPeerId = requestChatPeerId
|
||||
self.requestChatDate = requestChatDate
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.flags = Flags(rawValue: decoder.decodeInt32ForKey("flags", orElse: 0))
|
||||
self.geoDistance = decoder.decodeOptionalInt32ForKey("geoDistance")
|
||||
self.requestChatPeerId = decoder.decodeOptionalInt64ForKey("requestChatPeerId").map { PeerId($0) }
|
||||
self.requestChatDate = decoder.decodeOptionalInt32ForKey("requestChatDate")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
@ -44,6 +52,16 @@ public struct PeerStatusSettings: PostboxCoding, Equatable {
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "geoDistance")
|
||||
}
|
||||
if let requestChatPeerId = self.requestChatPeerId {
|
||||
encoder.encodeInt64(requestChatPeerId.toInt64(), forKey: "requestChatPeerId")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "requestPeerId")
|
||||
}
|
||||
if let requestChatDate = self.requestChatDate {
|
||||
encoder.encodeInt32(requestChatDate, forKey: "requestChatDate")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "requestChatDate")
|
||||
}
|
||||
}
|
||||
|
||||
public func contains(_ member: PeerStatusSettings.Flags) -> Bool {
|
||||
|
@ -3,7 +3,7 @@ import Postbox
|
||||
import TelegramApi
|
||||
import SwiftSignalKit
|
||||
|
||||
func fetchAndUpdateSupplementalCachedPeerData(peerId rawPeerId: PeerId, network: Network, postbox: Postbox) -> Signal<Bool, NoError> {
|
||||
func fetchAndUpdateSupplementalCachedPeerData(peerId rawPeerId: PeerId, accountPeerId: PeerId, network: Network, postbox: Postbox) -> Signal<Bool, NoError> {
|
||||
return postbox.combinedView(keys: [.basicPeer(rawPeerId)])
|
||||
|> mapToSignal { views -> Signal<Peer, NoError> in
|
||||
guard let view = views.views[.basicPeer(rawPeerId)] as? BasicPeerView else {
|
||||
@ -78,9 +78,33 @@ func fetchAndUpdateSupplementalCachedPeerData(peerId rawPeerId: PeerId, network:
|
||||
return network.request(Api.functions.messages.getPeerSettings(peer: inputPeer))
|
||||
|> retryRequest
|
||||
|> mapToSignal { peerSettings -> Signal<Bool, NoError> in
|
||||
let peerStatusSettings = PeerStatusSettings(apiSettings: peerSettings)
|
||||
var peers: [Peer] = []
|
||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
||||
|
||||
let peerStatusSettings: PeerStatusSettings
|
||||
switch peerSettings {
|
||||
case let .peerSettings(settings, chats, users):
|
||||
peerStatusSettings = PeerStatusSettings(apiSettings: settings)
|
||||
for chat in chats {
|
||||
if let peer = parseTelegramGroupOrChannel(chat: chat) {
|
||||
peers.append(peer)
|
||||
}
|
||||
}
|
||||
for user in users {
|
||||
let telegramUser = TelegramUser(user: user)
|
||||
peers.append(telegramUser)
|
||||
if let presence = TelegramUserPresence(apiUser: user) {
|
||||
peerPresences[telegramUser.id] = presence
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return postbox.transaction { transaction -> Bool in
|
||||
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
||||
return updated
|
||||
})
|
||||
updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences)
|
||||
|
||||
transaction.updatePeerCachedData(peerIds: Set([peer.id]), update: { _, current in
|
||||
switch peer.id.namespace {
|
||||
case Namespaces.Peer.CloudUser:
|
||||
@ -171,46 +195,67 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
|> mapToSignal { result -> Signal<Bool, NoError> in
|
||||
return postbox.transaction { transaction -> Bool in
|
||||
switch result {
|
||||
case let .userFull(_, userFullUser, _, _, _, userFullNotifySettings, _, _, _, _, _, _, _):
|
||||
if let telegramUser = TelegramUser.merge(transaction.getPeer(userFullUser.peerId) as? TelegramUser, rhs: userFullUser) {
|
||||
updatePeers(transaction: transaction, peers: [telegramUser], update: { _, updated -> Peer in
|
||||
case let .userFull(fullUser, chats, users):
|
||||
var accountUser: Api.User?
|
||||
var peers: [Peer] = []
|
||||
var peerPresences: [PeerId: PeerPresence] = [:]
|
||||
for chat in chats {
|
||||
if let peer = parseTelegramGroupOrChannel(chat: chat) {
|
||||
peers.append(peer)
|
||||
}
|
||||
}
|
||||
for user in users {
|
||||
let telegramUser = TelegramUser(user: user)
|
||||
peers.append(telegramUser)
|
||||
if let presence = TelegramUserPresence(apiUser: user) {
|
||||
peerPresences[telegramUser.id] = presence
|
||||
}
|
||||
if telegramUser.id == accountPeerId {
|
||||
accountUser = user
|
||||
}
|
||||
}
|
||||
|
||||
switch fullUser {
|
||||
case let .userFull(_, _, _, _, _, userFullNotifySettings, _, _, _, _, _, _):
|
||||
updatePeers(transaction: transaction, peers: peers, update: { previous, updated -> Peer in
|
||||
if previous?.id == accountPeerId, let accountUser = accountUser, let user = TelegramUser.merge(previous as? TelegramUser, rhs: accountUser) {
|
||||
return user
|
||||
}
|
||||
return updated
|
||||
})
|
||||
transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: userFullNotifySettings)])
|
||||
updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences)
|
||||
}
|
||||
transaction.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: userFullNotifySettings)])
|
||||
if let presence = TelegramUserPresence(apiUser: userFullUser) {
|
||||
updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: [userFullUser.peerId: presence])
|
||||
}
|
||||
}
|
||||
transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, current in
|
||||
let previous: CachedUserData
|
||||
if let current = current as? CachedUserData {
|
||||
previous = current
|
||||
} else {
|
||||
previous = CachedUserData()
|
||||
}
|
||||
switch result {
|
||||
case let .userFull(userFullFlags, _, userFullAbout, userFullSettings, _, _, userFullBotInfo, userFullPinnedMsgId, userFullCommonChatsCount, _, userFullTtlPeriod, userFullThemeEmoticon):
|
||||
let botInfo = userFullBotInfo.flatMap(BotInfo.init(apiBotInfo:))
|
||||
let isBlocked = (userFullFlags & (1 << 0)) != 0
|
||||
let voiceCallsAvailable = (userFullFlags & (1 << 4)) != 0
|
||||
let videoCallsAvailable = (userFullFlags & (1 << 13)) != 0
|
||||
transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, current in
|
||||
let previous: CachedUserData
|
||||
if let current = current as? CachedUserData {
|
||||
previous = current
|
||||
} else {
|
||||
previous = CachedUserData()
|
||||
}
|
||||
switch fullUser {
|
||||
case let .userFull(userFullFlags, _, userFullAbout, userFullSettings, _, _, userFullBotInfo, userFullPinnedMsgId, userFullCommonChatsCount, _, userFullTtlPeriod, userFullThemeEmoticon):
|
||||
let botInfo = userFullBotInfo.flatMap(BotInfo.init(apiBotInfo:))
|
||||
let isBlocked = (userFullFlags & (1 << 0)) != 0
|
||||
let voiceCallsAvailable = (userFullFlags & (1 << 4)) != 0
|
||||
let videoCallsAvailable = (userFullFlags & (1 << 13)) != 0
|
||||
|
||||
let callsPrivate = (userFullFlags & (1 << 5)) != 0
|
||||
let canPinMessages = (userFullFlags & (1 << 7)) != 0
|
||||
let pinnedMessageId = userFullPinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })
|
||||
let callsPrivate = (userFullFlags & (1 << 5)) != 0
|
||||
let canPinMessages = (userFullFlags & (1 << 7)) != 0
|
||||
let pinnedMessageId = userFullPinnedMsgId.flatMap({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })
|
||||
|
||||
let peerStatusSettings = PeerStatusSettings(apiSettings: userFullSettings)
|
||||
|
||||
let hasScheduledMessages = (userFullFlags & 1 << 12) != 0
|
||||
|
||||
let autoremoveTimeout: CachedPeerAutoremoveTimeout = .known(CachedPeerAutoremoveTimeout.Value(userFullTtlPeriod))
|
||||
|
||||
let peerStatusSettings = PeerStatusSettings(apiSettings: userFullSettings)
|
||||
|
||||
let hasScheduledMessages = (userFullFlags & 1 << 12) != 0
|
||||
|
||||
let autoremoveTimeout: CachedPeerAutoremoveTimeout = .known(CachedPeerAutoremoveTimeout.Value(userFullTtlPeriod))
|
||||
|
||||
return previous.withUpdatedAbout(userFullAbout).withUpdatedBotInfo(botInfo).withUpdatedCommonGroupCount(userFullCommonChatsCount).withUpdatedIsBlocked(isBlocked).withUpdatedVoiceCallsAvailable(voiceCallsAvailable).withUpdatedVideoCallsAvailable(videoCallsAvailable).withUpdatedCallsPrivate(callsPrivate).withUpdatedCanPinMessages(canPinMessages).withUpdatedPeerStatusSettings(peerStatusSettings).withUpdatedPinnedMessageId(pinnedMessageId).withUpdatedHasScheduledMessages(hasScheduledMessages)
|
||||
.withUpdatedAutoremoveTimeout(autoremoveTimeout)
|
||||
.withUpdatedThemeEmoticon(userFullThemeEmoticon)
|
||||
}
|
||||
})
|
||||
return previous.withUpdatedAbout(userFullAbout).withUpdatedBotInfo(botInfo).withUpdatedCommonGroupCount(userFullCommonChatsCount).withUpdatedIsBlocked(isBlocked).withUpdatedVoiceCallsAvailable(voiceCallsAvailable).withUpdatedVideoCallsAvailable(videoCallsAvailable).withUpdatedCallsPrivate(callsPrivate).withUpdatedCanPinMessages(canPinMessages).withUpdatedPeerStatusSettings(peerStatusSettings).withUpdatedPinnedMessageId(pinnedMessageId).withUpdatedHasScheduledMessages(hasScheduledMessages)
|
||||
.withUpdatedAutoremoveTimeout(autoremoveTimeout)
|
||||
.withUpdatedThemeEmoticon(userFullThemeEmoticon)
|
||||
}
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ func _internal_createStickerSet(account: Account, title: String, shortName: Stri
|
||||
|
||||
switch result {
|
||||
case .stickerSetNotModified:
|
||||
preconditionFailure()
|
||||
return .complete()
|
||||
case let .stickerSet(set, packs, documents):
|
||||
let namespace: ItemCollectionId.Namespace
|
||||
switch set {
|
||||
|
@ -3,7 +3,6 @@ import Postbox
|
||||
import TelegramApi
|
||||
import SwiftSignalKit
|
||||
|
||||
|
||||
extension StickerPackReference {
|
||||
init(_ stickerPackInfo: StickerPackCollectionInfo) {
|
||||
self = .id(id: stickerPackInfo.id.id, accessHash: stickerPackInfo.accessHash)
|
||||
@ -45,6 +44,8 @@ func updatedRemoteStickerPack(postbox: Postbox, network: Network, reference: Sti
|
||||
let info: StickerPackCollectionInfo
|
||||
var items: [StickerPackItem] = []
|
||||
switch result {
|
||||
case .stickerSetNotModified:
|
||||
return .complete()
|
||||
case let .stickerSet(set, packs, documents):
|
||||
let namespace: ItemCollectionId.Namespace
|
||||
switch set {
|
||||
|
@ -52,52 +52,54 @@ func _internal_requestStickerSet(postbox: Postbox, network: Network, reference:
|
||||
}
|
||||
|
||||
let remoteSignal = network.request(Api.functions.messages.getStickerSet(stickerset: input, hash: 0))
|
||||
|> mapError { _ -> RequestStickerSetError in
|
||||
return .invalid
|
||||
}
|
||||
|> map { result -> RequestStickerSetResult in
|
||||
var items: [ItemCollectionItem] = []
|
||||
let info: ItemCollectionInfo
|
||||
let installed: Bool
|
||||
switch result {
|
||||
case let .stickerSet(set, packs, documents):
|
||||
info = StickerPackCollectionInfo(apiSet: set, namespace: Namespaces.ItemCollection.CloudStickerPacks)
|
||||
|
||||
switch set {
|
||||
case let .stickerSet(flags, _, _, _, _, _, _, _, _, _, _):
|
||||
installed = (flags & (1 << 0) != 0)
|
||||
}
|
||||
|
||||
var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:]
|
||||
for pack in packs {
|
||||
switch pack {
|
||||
case let .stickerPack(text, fileIds):
|
||||
let key = ValueBoxKey(text).toMemoryBuffer()
|
||||
for fileId in fileIds {
|
||||
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)
|
||||
if indexKeysByFile[mediaId] == nil {
|
||||
indexKeysByFile[mediaId] = [key]
|
||||
} else {
|
||||
indexKeysByFile[mediaId]!.append(key)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for apiDocument in documents {
|
||||
if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id {
|
||||
let fileIndexKeys: [MemoryBuffer]
|
||||
if let indexKeys = indexKeysByFile[id] {
|
||||
fileIndexKeys = indexKeys
|
||||
|> mapError { _ -> RequestStickerSetError in
|
||||
return .invalid
|
||||
}
|
||||
|> mapToSignal { result -> Signal<RequestStickerSetResult, RequestStickerSetError> in
|
||||
var items: [ItemCollectionItem] = []
|
||||
let info: ItemCollectionInfo
|
||||
let installed: Bool
|
||||
switch result {
|
||||
case .stickerSetNotModified:
|
||||
return .complete()
|
||||
case let .stickerSet(set, packs, documents):
|
||||
info = StickerPackCollectionInfo(apiSet: set, namespace: Namespaces.ItemCollection.CloudStickerPacks)
|
||||
|
||||
switch set {
|
||||
case let .stickerSet(flags, _, _, _, _, _, _, _, _, _, _):
|
||||
installed = (flags & (1 << 0) != 0)
|
||||
}
|
||||
|
||||
var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:]
|
||||
for pack in packs {
|
||||
switch pack {
|
||||
case let .stickerPack(text, fileIds):
|
||||
let key = ValueBoxKey(text).toMemoryBuffer()
|
||||
for fileId in fileIds {
|
||||
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)
|
||||
if indexKeysByFile[mediaId] == nil {
|
||||
indexKeysByFile[mediaId] = [key]
|
||||
} else {
|
||||
fileIndexKeys = []
|
||||
indexKeysByFile[mediaId]!.append(key)
|
||||
}
|
||||
items.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(items.count), id: id.id), file: file, indexKeys: fileIndexKeys))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return .remote(info: info, items: items, installed: installed)
|
||||
}
|
||||
|
||||
for apiDocument in documents {
|
||||
if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id {
|
||||
let fileIndexKeys: [MemoryBuffer]
|
||||
if let indexKeys = indexKeysByFile[id] {
|
||||
fileIndexKeys = indexKeys
|
||||
} else {
|
||||
fileIndexKeys = []
|
||||
}
|
||||
items.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(items.count), id: id.id), file: file, indexKeys: fileIndexKeys))
|
||||
}
|
||||
}
|
||||
}
|
||||
return .single(.remote(info: info, items: items, installed: installed))
|
||||
}
|
||||
|
||||
if let collectionId = collectionId {
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
{"v":"5.7.4","fr":60,"ip":0,"op":180,"w":30,"h":30,"nm":"safari_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Com 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":120,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":140,"s":[185]},{"t":150,"s":[180]}],"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.15,0.205],[-0.233,0.543],[0,0],[0.142,0.444],[0.385,0.123],[1.435,-0.615],[0,0],[0.231,-0.17],[0.15,-0.205],[0.233,-0.543],[0,0],[-0.142,-0.444],[-0.385,-0.123],[-1.435,0.615],[0,0],[-0.231,0.17]],"o":[[0.17,-0.231],[0,0],[0.615,-1.435],[-0.123,-0.385],[-0.444,-0.142],[0,0],[-0.543,0.233],[-0.205,0.15],[-0.17,0.231],[0,0],[-0.615,1.435],[0.123,0.385],[0.444,0.142],[0,0],[0.543,-0.233],[0.205,-0.15]],"v":[[2.611,2.075],[3.13,1.029],[4.28,-1.654],[5.061,-4.251],[4.251,-5.061],[1.654,-4.28],[-1.029,-3.13],[-2.075,-2.611],[-2.611,-2.075],[-3.13,-1.029],[-4.28,1.654],[-5.061,4.251],[-4.251,5.061],[-1.654,4.28],[1.029,3.13],[2.075,2.611]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[2.5,2.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"mm","mm":3,"nm":"Объединить контуры 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.478431373835,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Com 2","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":290,"st":110,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Com 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Com 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":290,"st":110,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Block","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.671,-1.317],[0,-3.92],[0,0],[-0.763,-1.497],[-1.317,-0.671],[-3.92,0],[0,0],[-1.497,0.763],[-0.671,1.317],[0,3.92],[0,0],[0.763,1.497],[1.317,0.671],[3.92,0],[0,0],[1.497,-0.763]],"o":[[-0.763,1.497],[0,0],[0,3.92],[0.671,1.317],[1.497,0.763],[0,0],[3.92,0],[1.317,-0.671],[0.763,-1.497],[0,0],[0,-3.92],[-0.671,-1.317],[-1.497,-0.763],[0,0],[-3.92,0],[-1.317,0.671]],"v":[[-14.237,-11.178],[-15,-3.8],[-15,3.8],[-14.237,11.178],[-11.178,14.237],[-3.8,15],[3.8,15],[11.178,14.237],[14.237,11.178],[15,3.8],[15,-3.8],[14.237,-11.178],[11.178,-14.237],[3.8,-15],[-3.8,-15],[-11.178,-14.237]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.478431373835,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Block","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":290,"st":110,"bm":0}],"markers":[]}
|
||||
{"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"safari_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Com 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":20,"s":[185]},{"t":30,"s":[180]}],"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.15,0.205],[-0.233,0.543],[0,0],[0.142,0.444],[0.385,0.123],[1.435,-0.615],[0,0],[0.231,-0.17],[0.15,-0.205],[0.233,-0.543],[0,0],[-0.142,-0.444],[-0.385,-0.123],[-1.435,0.615],[0,0],[-0.231,0.17]],"o":[[0.17,-0.231],[0,0],[0.615,-1.435],[-0.123,-0.385],[-0.444,-0.142],[0,0],[-0.543,0.233],[-0.205,0.15],[-0.17,0.231],[0,0],[-0.615,1.435],[0.123,0.385],[0.444,0.142],[0,0],[0.543,-0.233],[0.205,-0.15]],"v":[[2.611,2.075],[3.13,1.029],[4.28,-1.654],[5.061,-4.251],[4.251,-5.061],[1.654,-4.28],[-1.029,-3.13],[-2.075,-2.611],[-2.611,-2.075],[-3.13,-1.029],[-4.28,1.654],[-5.061,4.251],[-4.251,5.061],[-1.654,4.28],[1.029,3.13],[2.075,2.611]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[2.5,2.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"mm","mm":3,"nm":"Объединить контуры 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Com 2","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Com 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Контур эллипса 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Com 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-10,"bm":0}],"markers":[]}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
||||
{"v":"5.7.4","fr":60,"ip":0,"op":120,"w":30,"h":30,"nm":"windows_30","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Union","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[15]},{"i":{"x":[0.833],"y":[0.889]},"o":{"x":[0.333],"y":[0]},"t":25,"s":[12.5]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.222]},"t":35,"s":[15]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":55,"s":[17.5]},{"t":70,"s":[15]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[15]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":25,"s":[15]},{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":35,"s":[15]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":55,"s":[15]},{"t":70,"s":[15]}],"ix":4}},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-1,11],[-1,1],[-12.667,1],[-12.667,-1],[-1,-1],[-1,-11],[1,-11],[1,-1],[12.667,-1],[12.667,1],[1,1],[1,11]],"c":true},"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Union","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Rectangle 23","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[16.667,16.667,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9,-9],[9,9],[-9,9],[-9,-9]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":25,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9,-10.667],[9,10.667],[-10.667,5.667],[-10.667,-5.667]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"t":35,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9,-9],[9,9],[-9,9],[-9,-9]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":55,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[10.667,-5.667],[10.667,5.667],[-9,10.667],[-9,-10.667]],"c":true}]},{"t":70,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9,-9],[9,9],[-9,9],[-9,-9]],"c":true}]}],"ix":2},"nm":"Контур 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Заливка 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[600,600],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Преобразовать"}],"nm":"Rectangle 23","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":-60,"bm":0}],"markers":[]}
|
@ -3473,7 +3473,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
var contactStatus: ChatContactStatus?
|
||||
if let peer = peerView.peers[peerView.peerId] {
|
||||
if let cachedData = peerView.cachedData as? CachedUserData {
|
||||
contactStatus = ChatContactStatus(canAddContact: !peerView.peerIsContact, canReportIrrelevantLocation: false, peerStatusSettings: cachedData.peerStatusSettings, invitedBy: nil)
|
||||
var requestChatPeer: Peer?
|
||||
if let requestChatPeerId = cachedData.peerStatusSettings?.requestChatPeerId {
|
||||
if let peer = peerView.peers[requestChatPeerId] {
|
||||
requestChatPeer = peer
|
||||
}
|
||||
}
|
||||
contactStatus = ChatContactStatus(canAddContact: !peerView.peerIsContact, canReportIrrelevantLocation: false, peerStatusSettings: cachedData.peerStatusSettings, invitedBy: nil, requestChatPeer: requestChatPeer)
|
||||
} else if let cachedData = peerView.cachedData as? CachedGroupData {
|
||||
var invitedBy: Peer?
|
||||
if let invitedByPeerId = cachedData.invitedBy {
|
||||
@ -3481,7 +3487,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
invitedBy = peer
|
||||
}
|
||||
}
|
||||
contactStatus = ChatContactStatus(canAddContact: false, canReportIrrelevantLocation: false, peerStatusSettings: cachedData.peerStatusSettings, invitedBy: invitedBy)
|
||||
contactStatus = ChatContactStatus(canAddContact: false, canReportIrrelevantLocation: false, peerStatusSettings: cachedData.peerStatusSettings, invitedBy: invitedBy, requestChatPeer: nil)
|
||||
} else if let cachedData = peerView.cachedData as? CachedChannelData {
|
||||
var canReportIrrelevantLocation = true
|
||||
if let peer = peerView.peers[peerView.peerId] as? TelegramChannel, peer.participationStatus == .member {
|
||||
@ -3496,7 +3502,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
invitedBy = peer
|
||||
}
|
||||
}
|
||||
contactStatus = ChatContactStatus(canAddContact: false, canReportIrrelevantLocation: canReportIrrelevantLocation, peerStatusSettings: cachedData.peerStatusSettings, invitedBy: invitedBy)
|
||||
contactStatus = ChatContactStatus(canAddContact: false, canReportIrrelevantLocation: canReportIrrelevantLocation, peerStatusSettings: cachedData.peerStatusSettings, invitedBy: invitedBy, requestChatPeer: nil)
|
||||
}
|
||||
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -13980,6 +13986,29 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.push(controller)
|
||||
}
|
||||
|
||||
private func presentChatRequestAdminInfo() {
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let controller = ActionSheetController(presentationData: presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
let text = ""
|
||||
|
||||
items.append(ActionSheetTextItem(title: text))
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.Conversation_InviteRequestInfoConfirm, color: .accent, action: { [weak self, weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
self?.interfaceInteraction?.dismissReportPeer()
|
||||
}))
|
||||
controller.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
controller.setItemGroups([])
|
||||
self.chatDisplayNode.dismissInput()
|
||||
self.push(controller)
|
||||
}
|
||||
|
||||
private var crossfading = false
|
||||
private func presentCrossfadeSnapshot() {
|
||||
guard !self.crossfading, let snapshotView = self.view.snapshotView(afterScreenUpdates: false) else {
|
||||
|
@ -198,6 +198,7 @@ struct ChatContactStatus: Equatable {
|
||||
var canReportIrrelevantLocation: Bool
|
||||
var peerStatusSettings: PeerStatusSettings?
|
||||
var invitedBy: Peer?
|
||||
var requestChatPeer: Peer?
|
||||
|
||||
var isEmpty: Bool {
|
||||
guard var peerStatusSettings = self.peerStatusSettings else {
|
||||
@ -225,6 +226,9 @@ struct ChatContactStatus: Equatable {
|
||||
if !arePeersEqual(lhs.invitedBy, rhs.invitedBy) {
|
||||
return false
|
||||
}
|
||||
if !arePeersEqual(lhs.requestChatPeer, rhs.requestChatPeer) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import LocalizedPeerData
|
||||
import TelegramStringFormatting
|
||||
import TextFormat
|
||||
import Markdown
|
||||
|
||||
private enum ChatReportPeerTitleButton: Equatable {
|
||||
case block
|
||||
@ -302,6 +304,7 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
|
||||
|
||||
private let closeButton: HighlightableButtonNode
|
||||
private var buttons: [(ChatReportPeerTitleButton, UIButton)] = []
|
||||
private let textNode: ImmediateTextNode
|
||||
|
||||
private var theme: PresentationTheme?
|
||||
|
||||
@ -316,9 +319,12 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
|
||||
self.closeButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0)
|
||||
self.closeButton.displaysAsynchronously = false
|
||||
|
||||
self.textNode = ImmediateTextNode()
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.separatorNode)
|
||||
self.addSubnode(self.textNode)
|
||||
|
||||
self.closeButton.addTarget(self, action: #selector(self.closePressed), forControlEvents: [.touchUpInside])
|
||||
self.addSubnode(self.closeButton)
|
||||
@ -425,6 +431,33 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let requestChatPeer = interfaceState.contactStatus?.requestChatPeer, let renderedPeer = interfaceState.renderedPeer, let peer = renderedPeer.chatMainPeer {
|
||||
let text: NSAttributedString
|
||||
let regular = MarkdownAttributeSet(font: Font.regular(14.0), textColor: interfaceState.theme.rootController.navigationBar.primaryTextColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.bold(14.0), textColor: interfaceState.theme.rootController.navigationBar.primaryTextColor)
|
||||
if let requestChatPeer = requestChatPeer as? TelegramChannel, case .broadcast = requestChatPeer.info {
|
||||
text = addAttributesToStringWithRanges(interfaceState.strings.Conversation_InviteRequestAdminChannel(EnginePeer(peer).compactDisplayTitle, EnginePeer(requestChatPeer).displayTitle(strings: interfaceState.strings, displayOrder: interfaceState.nameDisplayOrder))._tuple, body: regular, argumentAttributes: [0: bold, 1: bold])
|
||||
} else {
|
||||
text = addAttributesToStringWithRanges(interfaceState.strings.Conversation_InviteRequestAdminGroup(EnginePeer(peer).compactDisplayTitle, EnginePeer(requestChatPeer).displayTitle(strings: interfaceState.strings, displayOrder: interfaceState.nameDisplayOrder))._tuple, body: regular, argumentAttributes: [0: bold, 1: bold])
|
||||
}
|
||||
self.textNode.attributedText = text
|
||||
|
||||
transition.updateAlpha(node: self.textNode, alpha: 1.0)
|
||||
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: width - leftInset - rightInset - 40.0, height: 40.0))
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - textSize.width) / 2.0), y: 4.0), size: textSize)
|
||||
|
||||
for (_, view) in self.buttons {
|
||||
transition.updateAlpha(layer: view.layer, alpha: 0.0)
|
||||
}
|
||||
} else {
|
||||
transition.updateAlpha(node: self.textNode, alpha: 0.0)
|
||||
|
||||
for (_, view) in self.buttons {
|
||||
transition.updateAlpha(layer: view.layer, alpha: 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
let initialPanelHeight = panelHeight
|
||||
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: UIScreenPixel)))
|
||||
|
Loading…
x
Reference in New Issue
Block a user