mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge commit 'a329f55dce' into formatted-date-api
# Conflicts: # submodules/TelegramCore/Sources/State/Serialization.swift
This commit is contained in:
commit
e294569f5d
81 changed files with 927 additions and 332 deletions
|
|
@ -1980,7 +1980,15 @@ private final class NotificationServiceHandler {
|
|||
}
|
||||
if enableInlineEmoji, let textEntitiesAttribute = message.textEntitiesAttribute, let author = message.author {
|
||||
let authorTitle = author.debugDisplayTitle
|
||||
let messagePrefix = "\(authorTitle): "
|
||||
var needsPrefix = false
|
||||
if message.id.peerId.namespace == Namespaces.Peer.CloudGroup {
|
||||
needsPrefix = true
|
||||
} else if let channel = message.peers[message.id.peerId] as? TelegramChannel {
|
||||
if case .group = channel.info {
|
||||
needsPrefix = true
|
||||
}
|
||||
}
|
||||
let messagePrefix = needsPrefix ? "\(authorTitle): " : ""
|
||||
let messagePrefixLength = (messagePrefix as NSString).length
|
||||
for entity in textEntitiesAttribute.entities {
|
||||
if case let .CustomEmoji(_, fileId) = entity.type {
|
||||
|
|
|
|||
|
|
@ -203,56 +203,87 @@ static void CollectAccessibilityElementsForContainer(ASDisplayNode *container, U
|
|||
/// Collect all accessibliity elements for a given view and view node
|
||||
static void CollectAccessibilityElementsForView(UIView *view, NSMutableArray *elements)
|
||||
{
|
||||
ASDisplayNodeCAssertNotNil(elements, @"Should pass in a NSMutableArray");
|
||||
|
||||
ASDisplayNode *node = view.asyncdisplaykit_node;
|
||||
|
||||
static Class displayListViewClass = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
displayListViewClass = NSClassFromString(@"Display.ListView");
|
||||
});
|
||||
BOOL anySubNodeIsCollection = (nil != ASDisplayNodeFindFirstNode(node,
|
||||
^BOOL(ASDisplayNode *nodeToCheck) {
|
||||
ASDisplayNodeCAssertNotNil(elements, @"Should pass in a NSMutableArray");
|
||||
|
||||
ASDisplayNode *node = view.asyncdisplaykit_node;
|
||||
|
||||
static Class displayListViewClass = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
displayListViewClass = NSClassFromString(@"Display.ListView");
|
||||
});
|
||||
BOOL anySubNodeIsCollection = (nil != ASDisplayNodeFindFirstNode(node,
|
||||
^BOOL(ASDisplayNode *nodeToCheck) {
|
||||
if (displayListViewClass != nil && [nodeToCheck isKindOfClass:displayListViewClass]) {
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
/*return ASDynamicCast(nodeToCheck, ASCollectionNode) != nil ||
|
||||
ASDynamicCast(nodeToCheck, ASTableNode) != nil;*/
|
||||
}));
|
||||
|
||||
if (node.isAccessibilityContainer && !anySubNodeIsCollection) {
|
||||
CollectAccessibilityElementsForContainer(node, view, elements);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle rasterize case
|
||||
if (node.rasterizesSubtree) {
|
||||
CollectUIAccessibilityElementsForNode(node, node, view, elements);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!node.isLayerBacked) {
|
||||
for (UIView *subview in node.view.subviews) {
|
||||
ASDisplayNode *subnode = subview.asyncdisplaykit_node;
|
||||
if (subnode) {
|
||||
if (subnode.isAccessibilityElement) {
|
||||
// An accessiblityElement can either be a UIView or a UIAccessibilityElement
|
||||
if (subnode.isLayerBacked) {
|
||||
// No view for layer backed nodes exist. It's necessary to create a UIAccessibilityElement that represents this node
|
||||
UIAccessibilityElement *accessiblityElement = [ASAccessibilityElement accessibilityElementWithContainer:view node:subnode containerNode:node];
|
||||
[elements addObject:accessiblityElement];
|
||||
} else {
|
||||
// Accessiblity element is not layer backed just add the view as accessibility element
|
||||
[elements addObject:subnode.view];
|
||||
}
|
||||
} else if (subnode.isLayerBacked) {
|
||||
// Go down the hierarchy of the layer backed subnode and collect all of the UIAccessibilityElement
|
||||
CollectUIAccessibilityElementsForNode(subnode, node, view, elements);
|
||||
} else if ([subnode accessibilityElementCount] > 0) {
|
||||
// UIView is itself a UIAccessibilityContainer just add it
|
||||
[elements addObject:subnode.view];
|
||||
}
|
||||
} else {
|
||||
// Plain UIView without an associated ASDisplayNode
|
||||
if (subview.isAccessibilityElement) {
|
||||
[elements addObject:subview];
|
||||
} else if ([subview accessibilityElementCount] > 0) {
|
||||
[elements addObject:subview];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (ASDisplayNode *subnode in node.subnodes) {
|
||||
if (subnode.isAccessibilityElement) {
|
||||
// An accessiblityElement can either be a UIView or a UIAccessibilityElement
|
||||
if (subnode.isLayerBacked) {
|
||||
// No view for layer backed nodes exist. It's necessary to create a UIAccessibilityElement that represents this node
|
||||
UIAccessibilityElement *accessiblityElement = [ASAccessibilityElement accessibilityElementWithContainer:view node:subnode containerNode:node];
|
||||
[elements addObject:accessiblityElement];
|
||||
} else {
|
||||
// Accessiblity element is not layer backed just add the view as accessibility element
|
||||
[elements addObject:subnode.view];
|
||||
}
|
||||
} else if (subnode.isLayerBacked) {
|
||||
// Go down the hierarchy of the layer backed subnode and collect all of the UIAccessibilityElement
|
||||
CollectUIAccessibilityElementsForNode(subnode, node, view, elements);
|
||||
} else if ([subnode accessibilityElementCount] > 0) {
|
||||
// UIView is itself a UIAccessibilityContainer just add it
|
||||
[elements addObject:subnode.view];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
/*return ASDynamicCast(nodeToCheck, ASCollectionNode) != nil ||
|
||||
ASDynamicCast(nodeToCheck, ASTableNode) != nil;*/
|
||||
}));
|
||||
|
||||
if (node.isAccessibilityContainer && !anySubNodeIsCollection) {
|
||||
CollectAccessibilityElementsForContainer(node, view, elements);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle rasterize case
|
||||
if (node.rasterizesSubtree) {
|
||||
CollectUIAccessibilityElementsForNode(node, node, view, elements);
|
||||
return;
|
||||
}
|
||||
|
||||
for (ASDisplayNode *subnode in node.subnodes) {
|
||||
if (subnode.isAccessibilityElement) {
|
||||
|
||||
// An accessiblityElement can either be a UIView or a UIAccessibilityElement
|
||||
if (subnode.isLayerBacked) {
|
||||
// No view for layer backed nodes exist. It's necessary to create a UIAccessibilityElement that represents this node
|
||||
UIAccessibilityElement *accessiblityElement = [ASAccessibilityElement accessibilityElementWithContainer:view node:subnode containerNode:node];
|
||||
[elements addObject:accessiblityElement];
|
||||
} else {
|
||||
// Accessiblity element is not layer backed just add the view as accessibility element
|
||||
[elements addObject:subnode.view];
|
||||
}
|
||||
} else if (subnode.isLayerBacked) {
|
||||
// Go down the hierarchy of the layer backed subnode and collect all of the UIAccessibilityElement
|
||||
CollectUIAccessibilityElementsForNode(subnode, node, view, elements);
|
||||
} else if ([subnode accessibilityElementCount] > 0) {
|
||||
// UIView is itself a UIAccessibilityContainer just add it
|
||||
[elements addObject:subnode.view];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@interface _ASDisplayView () {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDeco
|
|||
|
||||
private(set) var isAnimating = false
|
||||
|
||||
public var hitTestSize: CGFloat?
|
||||
|
||||
public typealias BlobRange = (min: CGFloat, max: CGFloat)
|
||||
|
||||
public init(
|
||||
|
|
@ -224,6 +226,15 @@ public final class VoiceBlobView: UIView, TGModernConversationInputMicButtonDeco
|
|||
|
||||
self.updateBlobsState()
|
||||
}
|
||||
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if let hitTestSize = self.hitTestSize {
|
||||
if !CGSize(width: hitTestSize, height: hitTestSize).centered(in: self.bounds).contains(point) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
}
|
||||
|
||||
final class BlobNode: ASDisplayNode {
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ final class AuthorizationSequenceSignUpController: ViewController {
|
|||
items.append(.separator)
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Login_Announce_Notify, icon: { theme in
|
||||
if !announceSignUp {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { [weak self] _, a in
|
||||
|
|
@ -128,7 +128,7 @@ final class AuthorizationSequenceSignUpController: ViewController {
|
|||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Login_Announce_DontNotify, icon: { theme in
|
||||
if announceSignUp {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { [weak self] _, a in
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ swift_library(
|
|||
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
|
||||
"//submodules/TelegramUI/Components/SearchInputPanelComponent",
|
||||
"//submodules/TelegramUI/Components/GlassControls",
|
||||
"//submodules/UIKitRuntimeUtils",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import DeviceModel
|
|||
import LegacyMediaPickerUI
|
||||
import PassKit
|
||||
import AlertComponent
|
||||
import UIKitRuntimeUtils
|
||||
|
||||
private final class TonSchemeHandler: NSObject, WKURLSchemeHandler {
|
||||
private final class PendingTask {
|
||||
|
|
@ -217,6 +218,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
|||
var cancelInteractiveTransitionGestures: () -> Void = {}
|
||||
|
||||
private var tempFile: TempBoxFile?
|
||||
private var disposeTrustedDomain: (() -> Void)?
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, url: String, preferredConfiguration: WKWebViewConfiguration? = nil) {
|
||||
self.context = context
|
||||
|
|
@ -264,6 +266,30 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
|||
configuration.userContentController = contentController
|
||||
configuration.applicationNameForUserAgent = computedUserAgent()
|
||||
}
|
||||
|
||||
if context.sharedContext.immediateExperimentalUISettings.enablePWA {
|
||||
if #available(iOS 17.0, *) {
|
||||
if let parsedUrl = URL(string: url), let host = parsedUrl.host {
|
||||
let rootPath = context.sharedContext.applicationBindings.containerPath + "/telegram-data"
|
||||
let pwaPath = rootPath + "/pwa"
|
||||
let uuidPath = pwaPath + "/uuid_\(host)"
|
||||
let uuid: UUID
|
||||
if let value = try? String(contentsOf: URL(fileURLWithPath: uuidPath), encoding: .utf8) {
|
||||
uuid = UUID(uuidString: value)!
|
||||
} else {
|
||||
uuid = UUID()
|
||||
let _ = try? FileManager.default.createDirectory(at: URL(fileURLWithPath: pwaPath), withIntermediateDirectories: true)
|
||||
let _ = try? uuid.uuidString.write(to: URL(fileURLWithPath: uuidPath), atomically: true, encoding: .utf8)
|
||||
}
|
||||
|
||||
configuration.websiteDataStore = WKWebsiteDataStore(forIdentifier: uuid)
|
||||
|
||||
configuration.limitsNavigationsToAppBoundDomains = true
|
||||
disposeTrustedDomain = WebHelpers.addTrustedDomain(host)
|
||||
WebHelpers.forceRefreshTrustedDomains(configuration.websiteDataStore)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.webView = WebView(frame: CGRect(), configuration: configuration)
|
||||
self.webView.allowsLinkPreview = true
|
||||
|
|
@ -273,18 +299,16 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
|||
}
|
||||
|
||||
var title: String = ""
|
||||
var request: URLRequest?
|
||||
if url.hasPrefix("file://") {
|
||||
var updatedPath = url
|
||||
let tempFile = TempBox.shared.file(path: url.replacingOccurrences(of: "file://", with: ""), fileName: "file.xlsx")
|
||||
updatedPath = tempFile.path
|
||||
self.tempFile = tempFile
|
||||
|
||||
let request = URLRequest(url: URL(fileURLWithPath: updatedPath))
|
||||
self.webView.load(request)
|
||||
request = URLRequest(url: URL(fileURLWithPath: updatedPath))
|
||||
} else if let parsedUrl = URL(string: url) {
|
||||
let request = URLRequest(url: parsedUrl)
|
||||
self.webView.load(request)
|
||||
|
||||
request = URLRequest(url: parsedUrl)
|
||||
title = getDisplayUrl(url, hostOnly: true)
|
||||
}
|
||||
|
||||
|
|
@ -299,6 +323,10 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
|||
self.webView.backgroundColor = presentationData.theme.list.plainBackgroundColor
|
||||
self.webView.alpha = 0.0
|
||||
|
||||
if let request {
|
||||
self.webView.load(request)
|
||||
}
|
||||
|
||||
self.webView.allowsBackForwardNavigationGestures = true
|
||||
self.webView.scrollView.delegate = self
|
||||
self.webView.scrollView.clipsToBounds = false
|
||||
|
|
@ -360,6 +388,8 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
|||
|
||||
self.faviconDisposable.dispose()
|
||||
self.instantPageDisposable.dispose()
|
||||
|
||||
self.disposeTrustedDomain?()
|
||||
}
|
||||
|
||||
private func handleScriptMessage(_ message: WKScriptMessage) {
|
||||
|
|
|
|||
|
|
@ -3742,7 +3742,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Chat_ContextViewAsTopics, icon: { theme in
|
||||
if !isViewingAsTopics {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak sourceController] _, a in
|
||||
|
|
@ -3778,7 +3778,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Chat_ContextViewAsMessages, icon: { theme in
|
||||
if isViewingAsTopics {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak sourceController] _, a in
|
||||
|
|
@ -5439,14 +5439,23 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
})
|
||||
}
|
||||
|
||||
if let self, case let .channel(channel) = peer.peer, channel.flags.contains(.isCreator) {
|
||||
let _ = (self.context.engine.peers.getFutureCreatorAfterLeave(peerId: channel.id)
|
||||
let shouldCheckFutureCreator: Bool
|
||||
if case let .channel(channel) = peer.peer, channel.flags.contains(.isCreator) {
|
||||
shouldCheckFutureCreator = true
|
||||
} else if case let .legacyGroup(group) = peer.peer, case .creator = group.role {
|
||||
shouldCheckFutureCreator = true
|
||||
} else {
|
||||
shouldCheckFutureCreator = false
|
||||
}
|
||||
|
||||
if let self, shouldCheckFutureCreator {
|
||||
let _ = (self.context.engine.peers.getFutureCreatorAfterLeave(peerId: peer.peerId)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] nextCreator in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let nextCreator, let peer = peer.peer {
|
||||
self.presentLeaveChannelConfirmation(peer: peer, nextCreator: nextCreator, completion: { commit in
|
||||
self.presentLeaveChatConfirmation(peer: peer, nextCreator: nextCreator, completion: { commit in
|
||||
if commit {
|
||||
proceed()
|
||||
}
|
||||
|
|
@ -5913,14 +5922,24 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
removed()
|
||||
})
|
||||
}
|
||||
|
||||
let shouldCheckFutureCreator: Bool
|
||||
if case let .channel(channel) = peer.peer, channel.flags.contains(.isCreator) {
|
||||
let _ = (self.context.engine.peers.getFutureCreatorAfterLeave(peerId: channel.id)
|
||||
shouldCheckFutureCreator = true
|
||||
} else if case let .legacyGroup(group) = peer.peer, case .creator = group.role {
|
||||
shouldCheckFutureCreator = true
|
||||
} else {
|
||||
shouldCheckFutureCreator = false
|
||||
}
|
||||
|
||||
if shouldCheckFutureCreator {
|
||||
let _ = (self.context.engine.peers.getFutureCreatorAfterLeave(peerId: peer.peerId)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] nextCreator in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let nextCreator, let peer = peer.peer {
|
||||
self.presentLeaveChannelConfirmation(peer: peer, nextCreator: nextCreator, completion: { commit in
|
||||
self.presentLeaveChatConfirmation(peer: peer, nextCreator: nextCreator, completion: { commit in
|
||||
if commit {
|
||||
proceed()
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import PeerInfoUI
|
|||
import OwnershipTransferController
|
||||
|
||||
extension ChatListControllerImpl {
|
||||
func presentLeaveChannelConfirmation(peer: EnginePeer, nextCreator: EnginePeer, completion: @escaping (Bool) -> Void) {
|
||||
func presentLeaveChatConfirmation(peer: EnginePeer, nextCreator: EnginePeer, completion: @escaping (Bool) -> Void) {
|
||||
Task { @MainActor in
|
||||
let accountPeer = await (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))).get()
|
||||
|
||||
|
|
@ -5587,7 +5587,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
}
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.ChatList_Search_Messages_Menu_AllChats, icon: { theme in
|
||||
return scope == .everywhere ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return scope == .everywhere ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { [weak self] _, f in
|
||||
guard let self else {
|
||||
return
|
||||
|
|
@ -5596,7 +5596,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
self.searchScopePromise.set(.everywhere)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.ChatList_Search_Messages_Menu_PrivateChats, icon: { theme in
|
||||
return scope == .privateChats ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return scope == .privateChats ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { [weak self] _, f in
|
||||
guard let self else {
|
||||
return
|
||||
|
|
@ -5605,7 +5605,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
self.searchScopePromise.set(.privateChats)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.ChatList_Search_Messages_Menu_GroupChats, icon: { theme in
|
||||
return scope == .groups ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return scope == .groups ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { [weak self] _, f in
|
||||
guard let self else {
|
||||
return
|
||||
|
|
@ -5614,7 +5614,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
self.searchScopePromise.set(.groups)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.ChatList_Search_Messages_Menu_Channels, icon: { theme in
|
||||
return scope == .channels ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return scope == .channels ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { [weak self] _, f in
|
||||
guard let self else {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -896,7 +896,7 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceView {
|
|||
)
|
||||
}
|
||||
counterLayout = counterValue
|
||||
if spec.component.count != 0 {
|
||||
if spec.component.count != 0 || hasTitle {
|
||||
size.width += spacing + counterValue.size.width
|
||||
} else {
|
||||
size.width -= 1.0
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||
case experimentalCompatibility(Bool)
|
||||
case enableDebugDataDisplay(Bool)
|
||||
case fakeGlass(Bool)
|
||||
case forceClearGlass(Bool)
|
||||
case browserExperiment(Bool)
|
||||
case allForumsHaveTabs(Bool)
|
||||
case enableReactionOverrides(Bool)
|
||||
|
|
@ -109,7 +110,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||
case playerV2(Bool)
|
||||
case devRequests(Bool)
|
||||
case enableUpdates(Bool)
|
||||
case fakeAds(Bool)
|
||||
case pwa(Bool)
|
||||
case enableLocalTranslation(Bool)
|
||||
case preferredVideoCodec(Int, String, String?, Bool)
|
||||
case disableVideoAspectScaling(Bool)
|
||||
|
|
@ -135,7 +136,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||
return DebugControllerSection.web.rawValue
|
||||
case .keepChatNavigationStack, .skipReadHistory, .alwaysDisplayTyping, .debugRatingLayout, .crashOnSlowQueries, .crashOnMemoryPressure:
|
||||
return DebugControllerSection.experiments.rawValue
|
||||
case .clearTips, .resetNotifications, .crash, .fillLocalSavedMessageCache, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .resetTagHoles, .reindexUnread, .resetCacheIndex, .reindexCache, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .compressedEmojiCache, .storiesJpegExperiment, .checkSerializedData, .enableQuickReactionSwitch, .experimentalCompatibility, .enableDebugDataDisplay, .fakeGlass, .browserExperiment, .allForumsHaveTabs, .enableReactionOverrides, .restorePurchases, .disableReloginTokens, .liveStreamV2, .experimentalCallMute, .playerV2, .devRequests, .enableUpdates, .fakeAds, .enableLocalTranslation:
|
||||
case .clearTips, .resetNotifications, .crash, .fillLocalSavedMessageCache, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .resetTagHoles, .reindexUnread, .resetCacheIndex, .reindexCache, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .compressedEmojiCache, .storiesJpegExperiment, .checkSerializedData, .enableQuickReactionSwitch, .experimentalCompatibility, .enableDebugDataDisplay, .fakeGlass, .forceClearGlass, .browserExperiment, .allForumsHaveTabs, .enableReactionOverrides, .restorePurchases, .disableReloginTokens, .liveStreamV2, .experimentalCallMute, .playerV2, .devRequests, .enableUpdates, .pwa, .enableLocalTranslation:
|
||||
return DebugControllerSection.experiments.rawValue
|
||||
case .logTranslationRecognition, .resetTranslationStates:
|
||||
return DebugControllerSection.translation.rawValue
|
||||
|
|
@ -228,24 +229,26 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||
return 38
|
||||
case .fakeGlass:
|
||||
return 39
|
||||
case .browserExperiment:
|
||||
case .forceClearGlass:
|
||||
return 40
|
||||
case .allForumsHaveTabs:
|
||||
case .browserExperiment:
|
||||
return 41
|
||||
case .enableReactionOverrides:
|
||||
case .allForumsHaveTabs:
|
||||
return 42
|
||||
case .restorePurchases:
|
||||
case .enableReactionOverrides:
|
||||
return 43
|
||||
case .logTranslationRecognition:
|
||||
case .restorePurchases:
|
||||
return 44
|
||||
case .resetTranslationStates:
|
||||
case .logTranslationRecognition:
|
||||
return 45
|
||||
case .compressedEmojiCache:
|
||||
case .resetTranslationStates:
|
||||
return 46
|
||||
case .storiesJpegExperiment:
|
||||
case .compressedEmojiCache:
|
||||
return 47
|
||||
case .disableReloginTokens:
|
||||
case .storiesJpegExperiment:
|
||||
return 48
|
||||
case .disableReloginTokens:
|
||||
return 49
|
||||
case .checkSerializedData:
|
||||
return 50
|
||||
case .enableQuickReactionSwitch:
|
||||
|
|
@ -258,7 +261,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||
return 54
|
||||
case .devRequests:
|
||||
return 55
|
||||
case .fakeAds:
|
||||
case .pwa:
|
||||
return 56
|
||||
case .enableLocalTranslation:
|
||||
return 57
|
||||
|
|
@ -1200,7 +1203,18 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||
})
|
||||
case .resetWebViewCache:
|
||||
return ItemListActionItem(presentationData: presentationData, systemStyle: .glass, title: "Clear Web View Cache", kind: .destructive, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
WKWebsiteDataStore.default().removeData(ofTypes: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache], modifiedSince: Date(timeIntervalSince1970: 0), completionHandler:{ })
|
||||
WKWebsiteDataStore.default().removeData(ofTypes: [
|
||||
WKWebsiteDataTypeDiskCache,
|
||||
WKWebsiteDataTypeOfflineWebApplicationCache,
|
||||
WKWebsiteDataTypeMemoryCache,
|
||||
WKWebsiteDataTypeLocalStorage,
|
||||
WKWebsiteDataTypeCookies,
|
||||
WKWebsiteDataTypeSessionStorage,
|
||||
WKWebsiteDataTypeIndexedDBDatabases,
|
||||
WKWebsiteDataTypeWebSQLDatabases,
|
||||
WKWebsiteDataTypeFetchCache,
|
||||
WKWebsiteDataTypeServiceWorkerRegistrations
|
||||
], modifiedSince: Date(timeIntervalSince1970: 0), completionHandler:{ })
|
||||
})
|
||||
case .optimizeDatabase:
|
||||
return ItemListActionItem(presentationData: presentationData, systemStyle: .glass, title: "Optimize Database", kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
|
|
@ -1268,6 +1282,16 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||
})
|
||||
}).start()
|
||||
})
|
||||
case let .forceClearGlass(value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: "Force clear glass", value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in
|
||||
var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings
|
||||
settings.forceClearGlass = value
|
||||
return PreferencesEntry(settings)
|
||||
})
|
||||
}).start()
|
||||
})
|
||||
case let .browserExperiment(value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: "Inline UI", value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
|
||||
|
|
@ -1392,12 +1416,12 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||
})
|
||||
}).start()
|
||||
})
|
||||
case let .fakeAds(value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: "Fake Ads", value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
case let .pwa(value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, systemStyle: .glass, title: "Test1", value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in
|
||||
var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings
|
||||
settings.fakeAds = value
|
||||
settings.enablePWA = value
|
||||
return PreferencesEntry(settings)
|
||||
})
|
||||
}).start()
|
||||
|
|
@ -1488,7 +1512,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||
}
|
||||
}
|
||||
|
||||
private func debugControllerEntries(sharedContext: SharedAccountContext, presentationData: PresentationData, loggingSettings: LoggingSettings, mediaInputSettings: MediaInputSettings, experimentalSettings: ExperimentalUISettings, networkSettings: NetworkSettings?, hasLegacyAppData: Bool, useBetaFeatures: Bool) -> [DebugControllerEntry] {
|
||||
private func debugControllerEntries(context: AccountContext?, sharedContext: SharedAccountContext, presentationData: PresentationData, loggingSettings: LoggingSettings, mediaInputSettings: MediaInputSettings, experimentalSettings: ExperimentalUISettings, networkSettings: NetworkSettings?, hasLegacyAppData: Bool, useBetaFeatures: Bool) -> [DebugControllerEntry] {
|
||||
var entries: [DebugControllerEntry] = []
|
||||
|
||||
let isMainApp = sharedContext.applicationBindings.isMainApp
|
||||
|
|
@ -1544,6 +1568,7 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present
|
|||
entries.append(.experimentalCompatibility(experimentalSettings.experimentalCompatibility))
|
||||
entries.append(.enableDebugDataDisplay(experimentalSettings.enableDebugDataDisplay))
|
||||
entries.append(.fakeGlass(experimentalSettings.fakeGlass))
|
||||
entries.append(.forceClearGlass(experimentalSettings.forceClearGlass))
|
||||
#if DEBUG
|
||||
entries.append(.browserExperiment(experimentalSettings.browserExperiment))
|
||||
#else
|
||||
|
|
@ -1572,7 +1597,18 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present
|
|||
entries.append(.playerV2(experimentalSettings.playerV2))
|
||||
|
||||
entries.append(.devRequests(experimentalSettings.devRequests))
|
||||
entries.append(.fakeAds(experimentalSettings.fakeAds))
|
||||
|
||||
if let data = context?.currentAppConfiguration.with({ $0 }).data {
|
||||
var displayPwa = false
|
||||
if let _ = data["ios_display_pwa"] {
|
||||
displayPwa = true
|
||||
} else if let isDev = data["dev"] as? Double, isDev == 1.0 {
|
||||
displayPwa = true
|
||||
}
|
||||
if displayPwa {
|
||||
entries.append(.pwa(experimentalSettings.enablePWA))
|
||||
}
|
||||
}
|
||||
entries.append(.enableLocalTranslation(experimentalSettings.enableLocalTranslation))
|
||||
entries.append(.enableUpdates(experimentalSettings.enableUpdates))
|
||||
}
|
||||
|
|
@ -1658,7 +1694,7 @@ public func debugController(sharedContext: SharedAccountContext, context: Accoun
|
|||
}
|
||||
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text("Debug"), leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: debugControllerEntries(sharedContext: sharedContext, presentationData: presentationData, loggingSettings: loggingSettings, mediaInputSettings: mediaInputSettings, experimentalSettings: experimentalSettings, networkSettings: networkSettings, hasLegacyAppData: hasLegacyAppData, useBetaFeatures: useBetaFeatures), style: .blocks)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: debugControllerEntries(context: context, sharedContext: sharedContext, presentationData: presentationData, loggingSettings: loggingSettings, mediaInputSettings: mediaInputSettings, experimentalSettings: experimentalSettings, networkSettings: networkSettings, hasLegacyAppData: hasLegacyAppData, useBetaFeatures: useBetaFeatures), style: .blocks)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1340,13 +1340,14 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
isOpen: false
|
||||
))),
|
||||
action: { [weak self] in
|
||||
guard let self, let buttonPanelView = self.buttonPanel.view as? GlassControlPanelComponent.View, let centerItemView = buttonPanelView.centerItemView else {
|
||||
guard let self, let buttonPanelView = self.buttonPanel.view as? GlassControlPanelComponent.View else {
|
||||
return
|
||||
}
|
||||
guard let itemView = centerItemView.itemView(id: AnyHashable("settings")) else {
|
||||
return
|
||||
if let centerItemView = buttonPanelView.centerItemView, let itemView = centerItemView.itemView(id: AnyHashable("settings")) {
|
||||
self.settingsButtonPressed(sourceView: itemView)
|
||||
} else if let rightItemView = buttonPanelView.rightItemView, let itemView = rightItemView.itemView(id: AnyHashable("settings")) {
|
||||
self.settingsButtonPressed(sourceView: itemView)
|
||||
}
|
||||
self.settingsButtonPressed(sourceView: itemView)
|
||||
}
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1469,8 +1469,14 @@ public class GalleryController: ViewController, StandalonePresentableController,
|
|||
}
|
||||
|
||||
self.galleryNode.controlsVisibilityChanged = { [weak self] visible in
|
||||
self?.prefersOnScreenNavigationHidden = !visible
|
||||
self?.galleryNode.pager.centralItemNode()?.controlsVisibilityUpdated(isVisible: visible)
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.prefersOnScreenNavigationHidden = !visible
|
||||
|
||||
self.galleryNode.pager.forEachItemNode { itemNode in
|
||||
itemNode.controlsVisibilityUpdated(isVisible: visible)
|
||||
}
|
||||
}
|
||||
|
||||
self.galleryNode.updateOrientation = { [weak self] orientation in
|
||||
|
|
|
|||
|
|
@ -3350,7 +3350,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
if isSelected && value == nil {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: .white)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}), action: { _, f in
|
||||
f(.default)
|
||||
|
|
@ -3383,7 +3383,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
if isSelected {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: .white)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}, action: { [weak strongSelf] _, f in
|
||||
f(.default)
|
||||
|
|
@ -3437,7 +3437,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
if isSelected {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: .white)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
|
|
|||
|
|
@ -166,13 +166,16 @@ class LegacyBufferReader {
|
|||
if count == 0 {
|
||||
return 0
|
||||
}
|
||||
else if count > 0 && count <= 4 || self.offset + UInt(count) <= self.buffer._size {
|
||||
var value: Int32 = 0
|
||||
memcpy(&value, self.buffer.data?.advanced(by: Int(self.offset)), count)
|
||||
self.offset += UInt(count)
|
||||
return value
|
||||
guard count > 0, count <= 4, self.offset + UInt(count) <= self.buffer._size else {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
guard let bufferData = self.buffer.data else {
|
||||
return nil
|
||||
}
|
||||
var value: Int32 = 0
|
||||
memcpy(&value, bufferData.advanced(by: Int(self.offset)), count)
|
||||
self.offset += UInt(count)
|
||||
return value
|
||||
}
|
||||
|
||||
func readBuffer(_ count: Int) -> LegacyBuffer? {
|
||||
|
|
|
|||
|
|
@ -83,12 +83,14 @@ final class PeerChatTopTaggedMessageIdsTable: Table {
|
|||
let currentTopMessageId = self.get(peerId: message.id.peerId, threadId: message.threadId, namespace: message.id.namespace)
|
||||
if currentTopMessageId == nil || currentTopMessageId! < message.id {
|
||||
self.set(peerId: message.id.peerId, threadId: message.threadId, namespace: message.id.namespace, id: message.id)
|
||||
self.set(peerId: message.id.peerId, threadId: 0, namespace: message.id.namespace, id: message.id)
|
||||
}
|
||||
}
|
||||
case let .Remove(indices):
|
||||
for (index, _, threadId) in indices {
|
||||
if let messageId = self.get(peerId: index.id.peerId, threadId: threadId, namespace: index.id.namespace), index.id == messageId {
|
||||
self.set(peerId: index.id.peerId, threadId: threadId, namespace: index.id.namespace, id: nil)
|
||||
self.set(peerId: index.id.peerId, threadId: 0, namespace: index.id.namespace, id: nil)
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
|
@ -110,8 +112,12 @@ final class PeerChatTopTaggedMessageIdsTable: Table {
|
|||
if let maybeMessageId = maybeMessageId {
|
||||
var messageIdId: Int32 = maybeMessageId.id
|
||||
self.valueBox.set(self.table, key: self.key(combinedId: record.peerAndThreadId, namespace: record.namespace), value: MemoryBuffer(memory: &messageIdId, capacity: 4, length: 4, freeWhenDone: false))
|
||||
if record.peerAndThreadId.threadId != nil {
|
||||
self.valueBox.set(self.table, key: self.key(combinedId: PeerAndThreadId(peerId: record.peerAndThreadId.peerId, threadId: 0), namespace: record.namespace), value: MemoryBuffer(memory: &messageIdId, capacity: 4, length: 4, freeWhenDone: false))
|
||||
}
|
||||
} else {
|
||||
self.valueBox.remove(self.table, key: self.key(combinedId: record.peerAndThreadId, namespace: record.namespace), secure: false)
|
||||
self.valueBox.remove(self.table, key: self.key(combinedId: PeerAndThreadId(peerId: record.peerAndThreadId.peerId, threadId: 0), namespace: record.namespace), secure: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3507,7 +3507,13 @@ final class PostboxImpl {
|
|||
}
|
||||
if let peerId = mainPeerIdForTopTaggedMessages {
|
||||
for namespace in topTaggedMessageIdNamespaces {
|
||||
if let messageId = self.peerChatTopTaggedMessageIdsTable.get(peerId: peerId.peerId, threadId: peerId.threadId, namespace: namespace) {
|
||||
var messageId: MessageId?
|
||||
messageId = self.peerChatTopTaggedMessageIdsTable.get(peerId: peerId.peerId, threadId: peerId.threadId, namespace: namespace)
|
||||
if messageId == nil && peerId.threadId == nil {
|
||||
messageId = self.peerChatTopTaggedMessageIdsTable.get(peerId: peerId.peerId, threadId: 0, namespace: namespace)
|
||||
}
|
||||
|
||||
if let messageId {
|
||||
if let index = self.messageHistoryIndexTable.getIndex(messageId) {
|
||||
if let message = self.messageHistoryTable.getMessage(index) {
|
||||
topTaggedMessages[namespace] = MessageHistoryTopTaggedMessage.intermediate(message)
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ public func storageUsageExceptionsScreen(
|
|||
if currentValue == value {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}, action: { _, f in
|
||||
applyValue(value)
|
||||
|
|
|
|||
|
|
@ -1173,6 +1173,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||
dict[-1094555409] = { return Api.Update.parse_updateNotifySettings($0) }
|
||||
dict[-1955438642] = { return Api.Update.parse_updatePaidReactionPrivacy($0) }
|
||||
dict[-337610926] = { return Api.Update.parse_updatePeerBlocked($0) }
|
||||
dict[1115654513] = { return Api.Update.parse_updatePeerHistoryNoForward($0) }
|
||||
dict[-1147422299] = { return Api.Update.parse_updatePeerHistoryTTL($0) }
|
||||
dict[-1263546448] = { return Api.Update.parse_updatePeerLocated($0) }
|
||||
dict[1786671974] = { return Api.Update.parse_updatePeerSettings($0) }
|
||||
|
|
|
|||
|
|
@ -969,6 +969,14 @@ public extension Api {
|
|||
self.peerId = peerId
|
||||
}
|
||||
}
|
||||
public class Cons_updatePeerHistoryNoForward {
|
||||
public var flags: Int32
|
||||
public var peer: Api.Peer
|
||||
public init(flags: Int32, peer: Api.Peer) {
|
||||
self.flags = flags
|
||||
self.peer = peer
|
||||
}
|
||||
}
|
||||
public class Cons_updatePeerHistoryTTL {
|
||||
public var flags: Int32
|
||||
public var peer: Api.Peer
|
||||
|
|
@ -1531,6 +1539,7 @@ public extension Api {
|
|||
case updateNotifySettings(Cons_updateNotifySettings)
|
||||
case updatePaidReactionPrivacy(Cons_updatePaidReactionPrivacy)
|
||||
case updatePeerBlocked(Cons_updatePeerBlocked)
|
||||
case updatePeerHistoryNoForward(Cons_updatePeerHistoryNoForward)
|
||||
case updatePeerHistoryTTL(Cons_updatePeerHistoryTTL)
|
||||
case updatePeerLocated(Cons_updatePeerLocated)
|
||||
case updatePeerSettings(Cons_updatePeerSettings)
|
||||
|
|
@ -2488,6 +2497,13 @@ public extension Api {
|
|||
serializeInt32(_data.flags, buffer: buffer, boxed: false)
|
||||
_data.peerId.serialize(buffer, true)
|
||||
break
|
||||
case .updatePeerHistoryNoForward(let _data):
|
||||
if boxed {
|
||||
buffer.appendInt32(1115654513)
|
||||
}
|
||||
serializeInt32(_data.flags, buffer: buffer, boxed: false)
|
||||
_data.peer.serialize(buffer, true)
|
||||
break
|
||||
case .updatePeerHistoryTTL(let _data):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1147422299)
|
||||
|
|
@ -3192,6 +3208,8 @@ public extension Api {
|
|||
return ("updatePaidReactionPrivacy", [("`private`", _data.`private` as Any)])
|
||||
case .updatePeerBlocked(let _data):
|
||||
return ("updatePeerBlocked", [("flags", _data.flags as Any), ("peerId", _data.peerId as Any)])
|
||||
case .updatePeerHistoryNoForward(let _data):
|
||||
return ("updatePeerHistoryNoForward", [("flags", _data.flags as Any), ("peer", _data.peer as Any)])
|
||||
case .updatePeerHistoryTTL(let _data):
|
||||
return ("updatePeerHistoryTTL", [("flags", _data.flags as Any), ("peer", _data.peer as Any), ("ttlPeriod", _data.ttlPeriod as Any)])
|
||||
case .updatePeerLocated(let _data):
|
||||
|
|
@ -5158,6 +5176,22 @@ public extension Api {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_updatePeerHistoryNoForward(_ reader: BufferReader) -> Update? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Api.Peer?
|
||||
if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.Peer
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.Update.updatePeerHistoryNoForward(Cons_updatePeerHistoryNoForward(flags: _1!, peer: _2!))
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_updatePeerHistoryTTL(_ reader: BufferReader) -> Update? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
|
|
|
|||
|
|
@ -3191,23 +3191,6 @@ public extension Api.functions.channels {
|
|||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.channels {
|
||||
static func editCreator(channel: Api.InputChannel, userId: Api.InputUser, password: Api.InputCheckPasswordSRP) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1892102881)
|
||||
channel.serialize(buffer, true)
|
||||
userId.serialize(buffer, true)
|
||||
password.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "channels.editCreator", parameters: [("channel", String(describing: channel)), ("userId", String(describing: userId)), ("password", String(describing: password))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.channels {
|
||||
static func editLocation(channel: Api.InputChannel, geoPoint: Api.InputGeoPoint, address: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
|
|
@ -3371,21 +3354,6 @@ public extension Api.functions.channels {
|
|||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.channels {
|
||||
static func getFutureCreatorAfterLeave(channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.User>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1610016593)
|
||||
channel.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "channels.getFutureCreatorAfterLeave", parameters: [("channel", String(describing: channel))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.User? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.User?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.User
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.channels {
|
||||
static func getGroupsForDiscussion() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.Chats>) {
|
||||
let buffer = Buffer()
|
||||
|
|
@ -5742,6 +5710,23 @@ public extension Api.functions.messages {
|
|||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func editChatCreator(peer: Api.InputPeer, userId: Api.InputUser, password: Api.InputCheckPasswordSRP) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-146556841)
|
||||
peer.serialize(buffer, true)
|
||||
userId.serialize(buffer, true)
|
||||
password.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "messages.editChatCreator", parameters: [("peer", String(describing: peer)), ("userId", String(describing: userId)), ("password", String(describing: password))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Updates
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func editChatDefaultBannedRights(peer: Api.InputPeer, bannedRights: Api.ChatBannedRights) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
|
|
@ -6781,6 +6766,21 @@ public extension Api.functions.messages {
|
|||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func getFutureChatCreatorAfterLeave(peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.User>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(998051494)
|
||||
peer.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "messages.getFutureChatCreatorAfterLeave", parameters: [("peer", String(describing: peer))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.User? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.User?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.User
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func getGameHighScores(peer: Api.InputPeer, id: Int32, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.HighScores>) {
|
||||
let buffer = Buffer()
|
||||
|
|
|
|||
|
|
@ -571,7 +571,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, ASScrollVi
|
|||
if isSelected && value == nil {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}), action: { [weak self] _, f in
|
||||
scheduleTooltip(nil)
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ extension VideoChatScreenComponent.View {
|
|||
if isSelected {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: .white)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
|
@ -730,7 +730,7 @@ extension VideoChatScreenComponent.View {
|
|||
if output == currentOutput {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.actionSheet.primaryTextColor)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
|
@ -763,7 +763,7 @@ extension VideoChatScreenComponent.View {
|
|||
items.append(.separator)
|
||||
items.append(.action(ContextMenuActionItem(text: environment.strings.VoiceChat_SpeakPermissionEveryone, icon: { theme in
|
||||
if isMuted {
|
||||
return nil
|
||||
return UIImage()
|
||||
} else {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.actionSheet.primaryTextColor)
|
||||
}
|
||||
|
|
@ -777,7 +777,7 @@ extension VideoChatScreenComponent.View {
|
|||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: environment.strings.VoiceChat_SpeakPermissionAdmin, icon: { theme in
|
||||
if !isMuted {
|
||||
return nil
|
||||
return UIImage()
|
||||
} else {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.actionSheet.primaryTextColor)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ private final class VoiceChatShareScreenContextItemNode: ASDisplayNode, ContextM
|
|||
}
|
||||
|
||||
func canBeHighlighted() -> Bool {
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
func updateIsHighlighted(isHighlighted: Bool) {
|
||||
|
|
|
|||
|
|
@ -2010,6 +2010,26 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
|
|||
updatedState.updateStarGiftAuctionMyState(giftId: giftId, state: GiftAuctionContext.State.MyState(apiAuctionUserState: userState))
|
||||
case let .updateEmojiGameInfo(updateEmojiGameInfoData):
|
||||
updatedState.updateEmojiGameInfo(info: EmojiGameInfo(apiEmojiGameInfo: updateEmojiGameInfoData.info))
|
||||
case let .updatePeerHistoryNoForward(updatePeerHistoryNoForwardData):
|
||||
let (flags, peer) = (updatePeerHistoryNoForwardData.flags, updatePeerHistoryNoForwardData.peer)
|
||||
let peerId = peer.peerId
|
||||
updatedState.updateCachedPeerData(peerId, { current in
|
||||
if let previous = current as? CachedUserData {
|
||||
var updatedFlags = previous.flags
|
||||
if (flags & (1 << 0)) != 0 {
|
||||
updatedFlags.insert(.myCopyProtectionEnabled)
|
||||
} else {
|
||||
updatedFlags.remove(.myCopyProtectionEnabled)
|
||||
}
|
||||
if (flags & (1 << 1)) != 0 {
|
||||
updatedFlags.insert(.copyProtectionEnabled)
|
||||
} else {
|
||||
updatedFlags.remove(.copyProtectionEnabled)
|
||||
}
|
||||
return previous.withUpdatedFlags(updatedFlags)
|
||||
}
|
||||
return current
|
||||
})
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
|||
|
||||
public class Serialization: NSObject, MTSerialization {
|
||||
public func currentLayer() -> UInt {
|
||||
return 225
|
||||
return 223
|
||||
}
|
||||
|
||||
public func parseMessage(_ data: Data!) -> Any! {
|
||||
|
|
|
|||
|
|
@ -627,6 +627,8 @@ public struct CachedUserFlags: OptionSet {
|
|||
public static let canViewRevenue = CachedUserFlags(rawValue: 1 << 5)
|
||||
public static let botCanManageEmojiStatus = CachedUserFlags(rawValue: 1 << 6)
|
||||
public static let displayGiftButton = CachedUserFlags(rawValue: 1 << 7)
|
||||
public static let myCopyProtectionEnabled = CachedUserFlags(rawValue: 1 << 8)
|
||||
public static let copyProtectionEnabled = CachedUserFlags(rawValue: 1 << 9)
|
||||
}
|
||||
|
||||
public final class EditableBotInfo: PostboxCoding, Equatable {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import Postbox
|
|||
import TelegramApi
|
||||
|
||||
|
||||
public enum ChannelOwnershipTransferError {
|
||||
public enum ChatOwnershipTransferError {
|
||||
case generic
|
||||
case twoStepAuthMissing
|
||||
case twoStepAuthTooFresh(Int32)
|
||||
|
|
@ -20,12 +20,12 @@ public enum ChannelOwnershipTransferError {
|
|||
case userBlocked
|
||||
}
|
||||
|
||||
func _internal_checkOwnershipTranfserAvailability(postbox: Postbox, network: Network, accountStateManager: AccountStateManager, memberId: PeerId) -> Signal<Never, ChannelOwnershipTransferError> {
|
||||
func _internal_checkOwnershipTranfserAvailability(postbox: Postbox, network: Network, accountStateManager: AccountStateManager, memberId: PeerId) -> Signal<Never, ChatOwnershipTransferError> {
|
||||
return postbox.transaction { transaction -> Peer? in
|
||||
return transaction.getPeer(memberId)
|
||||
}
|
||||
|> castError(ChannelOwnershipTransferError.self)
|
||||
|> mapToSignal { user -> Signal<Never, ChannelOwnershipTransferError> in
|
||||
|> castError(ChatOwnershipTransferError.self)
|
||||
|> mapToSignal { user -> Signal<Never, ChatOwnershipTransferError> in
|
||||
guard let user = user else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
|
@ -33,8 +33,8 @@ func _internal_checkOwnershipTranfserAvailability(postbox: Postbox, network: Net
|
|||
return .fail(.generic)
|
||||
}
|
||||
|
||||
return network.request(Api.functions.channels.editCreator(channel: .inputChannelEmpty, userId: apiUser, password: .inputCheckPasswordEmpty))
|
||||
|> mapError { error -> ChannelOwnershipTransferError in
|
||||
return network.request(Api.functions.messages.editChatCreator(peer: .inputPeerEmpty, userId: apiUser, password: .inputCheckPasswordEmpty))
|
||||
|> mapError { error -> ChatOwnershipTransferError in
|
||||
if error.errorDescription == "PASSWORD_HASH_INVALID" {
|
||||
return .requestPassword
|
||||
} else if error.errorDescription == "PASSWORD_MISSING" {
|
||||
|
|
@ -64,39 +64,39 @@ func _internal_checkOwnershipTranfserAvailability(postbox: Postbox, network: Net
|
|||
}
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<Never, ChannelOwnershipTransferError> in
|
||||
|> mapToSignal { updates -> Signal<Never, ChatOwnershipTransferError> in
|
||||
accountStateManager.addUpdates(updates)
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_updateChannelOwnership(account: Account, channelId: PeerId, memberId: PeerId, password: String) -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> {
|
||||
func _internal_updateChatOwnership(account: Account, peerId: PeerId, memberId: PeerId, password: String) -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChatOwnershipTransferError> {
|
||||
guard !password.isEmpty else {
|
||||
return .fail(.invalidPassword)
|
||||
}
|
||||
|
||||
return combineLatest(_internal_fetchChannelParticipant(account: account, peerId: channelId, participantId: account.peerId), _internal_fetchChannelParticipant(account: account, peerId: channelId, participantId: memberId))
|
||||
|> mapError { _ -> ChannelOwnershipTransferError in
|
||||
return combineLatest(_internal_fetchChannelParticipant(account: account, peerId: peerId, participantId: account.peerId), _internal_fetchChannelParticipant(account: account, peerId: peerId, participantId: memberId))
|
||||
|> mapError { _ -> ChatOwnershipTransferError in
|
||||
}
|
||||
|> mapToSignal { currentCreator, currentParticipant -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> in
|
||||
return account.postbox.transaction { transaction -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> in
|
||||
if let channel = transaction.getPeer(channelId) as? TelegramChannel, let inputChannel = apiInputChannel(channel), let accountUser = transaction.getPeer(account.peerId), let user = transaction.getPeer(memberId), let inputUser = apiInputUser(user) {
|
||||
|> mapToSignal { currentCreator, currentParticipant -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChatOwnershipTransferError> in
|
||||
return account.postbox.transaction { transaction -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChatOwnershipTransferError> in
|
||||
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer), let accountUser = transaction.getPeer(account.peerId), let user = transaction.getPeer(memberId), let inputUser = apiInputUser(user) {
|
||||
|
||||
let flags: TelegramChatAdminRightsFlags = TelegramChatAdminRightsFlags.peerSpecific(peer: .channel(channel))
|
||||
let flags: TelegramChatAdminRightsFlags = TelegramChatAdminRightsFlags.peerSpecific(peer: EnginePeer(peer))
|
||||
|
||||
let updatedParticipant = ChannelParticipant.creator(id: user.id, adminInfo: nil, rank: currentParticipant?.rank)
|
||||
let updatedPreviousCreator = ChannelParticipant.member(id: accountUser.id, invitedAt: Int32(Date().timeIntervalSince1970), adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(rights: flags), promotedBy: accountUser.id, canBeEditedByAccountPeer: false), banInfo: nil, rank: currentCreator?.rank, subscriptionUntilDate: nil)
|
||||
|
||||
let checkPassword = _internal_twoStepAuthData(account.network)
|
||||
|> mapError { error -> ChannelOwnershipTransferError in
|
||||
|> mapError { error -> ChatOwnershipTransferError in
|
||||
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||
return .limitExceeded
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
|> mapToSignal { authData -> Signal<Api.InputCheckPasswordSRP, ChannelOwnershipTransferError> in
|
||||
|> mapToSignal { authData -> Signal<Api.InputCheckPasswordSRP, ChatOwnershipTransferError> in
|
||||
if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData {
|
||||
guard let kdfResult = passwordKDF(encryptionProvider: account.network.encryptionProvider, password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else {
|
||||
return .fail(.generic)
|
||||
|
|
@ -108,9 +108,9 @@ func _internal_updateChannelOwnership(account: Account, channelId: PeerId, membe
|
|||
}
|
||||
|
||||
return checkPassword
|
||||
|> mapToSignal { password -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> in
|
||||
return account.network.request(Api.functions.channels.editCreator(channel: inputChannel, userId: inputUser, password: password), automaticFloodWait: false)
|
||||
|> mapError { error -> ChannelOwnershipTransferError in
|
||||
|> mapToSignal { password -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChatOwnershipTransferError> in
|
||||
return account.network.request(Api.functions.messages.editChatCreator(peer: inputPeer, userId: inputUser, password: password), automaticFloodWait: false)
|
||||
|> mapError { error -> ChatOwnershipTransferError in
|
||||
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||
return .limitExceeded
|
||||
} else if error.errorDescription == "PASSWORD_HASH_INVALID" {
|
||||
|
|
@ -140,11 +140,11 @@ func _internal_updateChannelOwnership(account: Account, channelId: PeerId, membe
|
|||
}
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> in
|
||||
|> mapToSignal { updates -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChatOwnershipTransferError> in
|
||||
account.stateManager.addUpdates(updates)
|
||||
|
||||
return account.postbox.transaction { transaction -> [(ChannelParticipant?, RenderedChannelParticipant)] in
|
||||
transaction.updatePeerCachedData(peerIds: Set([channelId]), update: { _, cachedData -> CachedPeerData? in
|
||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
|
||||
if let cachedData = cachedData as? CachedChannelData, let adminCount = cachedData.participantsSummary.adminCount {
|
||||
var updatedAdminCount = adminCount
|
||||
var wasAdmin = false
|
||||
|
|
@ -179,14 +179,14 @@ func _internal_updateChannelOwnership(account: Account, channelId: PeerId, membe
|
|||
}
|
||||
return [(currentCreator, RenderedChannelParticipant(participant: updatedPreviousCreator, peer: accountUser, peers: peers, presences: presences)), (currentParticipant, RenderedChannelParticipant(participant: updatedParticipant, peer: user, peers: peers, presences: presences))]
|
||||
}
|
||||
|> mapError { _ -> ChannelOwnershipTransferError in }
|
||||
|> mapError { _ -> ChatOwnershipTransferError in }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|> mapError { _ -> ChannelOwnershipTransferError in }
|
||||
|> mapError { _ -> ChatOwnershipTransferError in }
|
||||
|> switchToLatest
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,13 +83,13 @@ func _internal_removePeerChat(account: Account, transaction: Transaction, mediaB
|
|||
|
||||
func _internal_getFutureCreatorAfterLeave(account: Account, peerId: EnginePeer.Id) -> Signal<EnginePeer?, NoError> {
|
||||
return account.postbox.transaction { transaction in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|> mapToSignal { channel in
|
||||
guard let channel else {
|
||||
|> mapToSignal { peer in
|
||||
guard let peer else {
|
||||
return .single(nil)
|
||||
}
|
||||
return account.network.request(Api.functions.channels.getFutureCreatorAfterLeave(channel: channel))
|
||||
return account.network.request(Api.functions.messages.getFutureChatCreatorAfterLeave(peer: peer))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ in
|
||||
return .single(nil)
|
||||
|
|
|
|||
|
|
@ -486,12 +486,12 @@ public extension TelegramEngine {
|
|||
return _internal_channelMembers(postbox: self.account.postbox, network: self.account.network, accountPeerId: self.account.peerId, peerId: peerId, category: category, offset: offset, limit: limit, hash: hash)
|
||||
}
|
||||
|
||||
public func checkOwnershipTranfserAvailability(memberId: PeerId) -> Signal<Never, ChannelOwnershipTransferError> {
|
||||
public func checkOwnershipTranfserAvailability(memberId: PeerId) -> Signal<Never, ChatOwnershipTransferError> {
|
||||
return _internal_checkOwnershipTranfserAvailability(postbox: self.account.postbox, network: self.account.network, accountStateManager: self.account.stateManager, memberId: memberId)
|
||||
}
|
||||
|
||||
public func updateChannelOwnership(channelId: PeerId, memberId: PeerId, password: String) -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> {
|
||||
return _internal_updateChannelOwnership(account: self.account, channelId: channelId, memberId: memberId, password: password)
|
||||
public func updateChatOwnership(peerId: PeerId, memberId: PeerId, password: String) -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChatOwnershipTransferError> {
|
||||
return _internal_updateChatOwnership(account: self.account, peerId: peerId, memberId: memberId, password: password)
|
||||
}
|
||||
|
||||
public func searchGroupMembers(peerId: PeerId, query: String) -> Signal<[EnginePeer], NoError> {
|
||||
|
|
|
|||
|
|
@ -297,6 +297,8 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
|||
let canViewRevenue = (userFullFlags2 & (1 << 9)) != 0
|
||||
let botCanManageEmojiStatus = (userFullFlags2 & (1 << 10)) != 0
|
||||
let displayGiftButton = (userFullFlags2 & (1 << 16)) != 0
|
||||
let myCopyProtectionEnabled = (userFullFlags2 & (1 << 23)) != 0
|
||||
let copyProtectionEnabled = (userFullFlags2 & (1 << 24)) != 0
|
||||
|
||||
var flags: CachedUserFlags = previous.flags
|
||||
if premiumRequired {
|
||||
|
|
@ -334,6 +336,16 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
|||
} else {
|
||||
flags.remove(.displayGiftButton)
|
||||
}
|
||||
if myCopyProtectionEnabled {
|
||||
flags.insert(.myCopyProtectionEnabled)
|
||||
} else {
|
||||
flags.remove(.myCopyProtectionEnabled)
|
||||
}
|
||||
if copyProtectionEnabled {
|
||||
flags.insert(.copyProtectionEnabled)
|
||||
} else {
|
||||
flags.remove(.copyProtectionEnabled)
|
||||
}
|
||||
|
||||
let callsPrivate = (userFullFlags & (1 << 5)) != 0
|
||||
let canPinMessages = (userFullFlags & (1 << 7)) != 0
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public func stringForFullAuthorName(message: EngineMessage, strings: Presentatio
|
|||
} else if author.isDeleted {
|
||||
authorName = strings.User_DeletedAccount
|
||||
} else {
|
||||
authorName = author.compactDisplayTitle
|
||||
authorName = author.displayTitle(strings: strings, displayOrder: nameDisplayOrder)
|
||||
}
|
||||
if let peer = message.peers[message.id.peerId].flatMap(EnginePeer.init), author.id != peer.id {
|
||||
authorString = [authorName, peer.displayTitle(strings: strings, displayOrder: nameDisplayOrder)]
|
||||
|
|
|
|||
|
|
@ -3522,9 +3522,9 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||
},
|
||||
mosaicStatusOrigin: mosaicStatusOrigin,
|
||||
mosaicStatusSizeAndApply: mosaicStatusSizeAndApply,
|
||||
unlockButtonPosition: unlockButtonPosition?.offsetBy(dx: 0.0, dy: layoutInsets.top),
|
||||
unlockButtonPosition: unlockButtonPosition,
|
||||
unlockButtonSizeAndApply: unlockButtonSizeApply,
|
||||
mediaInfoOrigin: mediaInfoOrigin?.offsetBy(dx: 0.0, dy: layoutInsets.top),
|
||||
mediaInfoOrigin: mediaInfoOrigin,
|
||||
mediaInfoSizeAndApply: mediaInfoSizeApply,
|
||||
needsSummarizeButton: needsSummarizeButton,
|
||||
needsShareButton: needsShareButton,
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ final class BoostSlowModeButton: HighlightTrackingButtonNode {
|
|||
self?.requestUpdate()
|
||||
}, queue: .mainQueue())
|
||||
self.updateTimer?.start()
|
||||
} else {
|
||||
text = stringForDuration(0)
|
||||
}
|
||||
} else {
|
||||
self.updateTimer?.invalidate()
|
||||
|
|
@ -115,7 +117,7 @@ final class BoostSlowModeButton: HighlightTrackingButtonNode {
|
|||
self.textNode.segments = segments
|
||||
|
||||
let textSize = self.textNode.updateLayout(size: CGSize(width: 200.0, height: 100.0), animated: true)
|
||||
let totalSize = CGSize(width: textSize.width > 0.0 ? textSize.width + 38.0 : 33.0, height: 33.0)
|
||||
let totalSize = CGSize(width: textSize.width > 0.0 ? textSize.width + 38.0 : 40.0, height: 40.0)
|
||||
|
||||
self.containerNode.bounds = CGRect(origin: .zero, size: totalSize)
|
||||
self.containerNode.position = CGPoint(x: totalSize.width / 2.0, y: totalSize.height / 2.0)
|
||||
|
|
|
|||
|
|
@ -1172,9 +1172,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||
self.touchDownGestureRecognizer = recognizer
|
||||
|
||||
textInputNode.textView.accessibilityHint = self.textPlaceholderNode.attributedText?.string
|
||||
|
||||
self.isAccessibilityContainer = true
|
||||
self.accessibilityElements = [textInputNode.textView]
|
||||
}
|
||||
|
||||
private func textFieldMaxHeight(_ maxHeight: CGFloat, metrics: LayoutMetrics, bottomInset: CGFloat) -> CGFloat {
|
||||
|
|
@ -2206,9 +2203,11 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||
|
||||
var rightSlowModeInset: CGFloat = 0.0
|
||||
var slowModeButtonSize: CGSize = .zero
|
||||
if let presentationInterfaceState = self.presentationInterfaceState, (presentationInterfaceState.boostsToUnrestrict ?? 0) > 0 {
|
||||
var hasSlowmodeButton = false
|
||||
if let presentationInterfaceState = self.presentationInterfaceState, (presentationInterfaceState.boostsToUnrestrict ?? 0) > 0, presentationInterfaceState.slowmodeState != nil {
|
||||
slowModeButtonSize = self.slowModeButton.update(size: CGSize(width: width, height: 40.0), interfaceState: presentationInterfaceState)
|
||||
rightSlowModeInset = max(0.0, slowModeButtonSize.width - 33.0)
|
||||
rightSlowModeInset = max(0.0, slowModeButtonSize.width + 4.0)
|
||||
hasSlowmodeButton = true
|
||||
}
|
||||
self.rightSlowModeInset = rightSlowModeInset
|
||||
|
||||
|
|
@ -2395,7 +2394,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||
if additionalSideInsets.right > 0.0 {
|
||||
textFieldInsets.right += additionalSideInsets.right / 3.0
|
||||
}
|
||||
if inputHasText || self.extendedSearchLayout || hasMediaDraft || hasForward {
|
||||
if inputHasText || self.extendedSearchLayout || hasMediaDraft || hasForward || hasSlowmodeButton {
|
||||
} else {
|
||||
if let customRightAction = self.customRightAction, case .empty = customRightAction {
|
||||
textFieldInsets.right = 8.0
|
||||
|
|
@ -3023,6 +3022,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||
var nextButtonTopRight = CGPoint(x: textInputContainerBackgroundFrame.width - accessoryButtonInset, y: textInputContainerBackgroundFrame.height - minimalInputHeight)
|
||||
if self.extendedSearchLayout {
|
||||
nextButtonTopRight.x -= 46.0
|
||||
} else if hasSlowmodeButton {
|
||||
} else if inputHasText || hasMediaDraft || hasForward {
|
||||
nextButtonTopRight.x -= sendActionButtonsSize.width
|
||||
}
|
||||
|
|
@ -3172,7 +3172,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||
}
|
||||
|
||||
var mediaActionButtonsFrame = CGRect(origin: CGPoint(x: textInputContainerBackgroundFrame.maxX + 6.0, y: textInputContainerBackgroundFrame.maxY - mediaActionButtonsSize.height), size: mediaActionButtonsSize)
|
||||
if inputHasText || self.extendedSearchLayout || hasMediaDraft || interfaceState.interfaceState.forwardMessageIds != nil {
|
||||
if inputHasText || self.extendedSearchLayout || hasMediaDraft || interfaceState.interfaceState.forwardMessageIds != nil || hasSlowmodeButton {
|
||||
mediaActionButtonsFrame.origin.x = width + 8.0
|
||||
}
|
||||
transition.updateFrame(node: self.mediaActionButtons, frame: mediaActionButtonsFrame)
|
||||
|
|
@ -3235,7 +3235,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||
self.sendActionButtons.updateAbsoluteRect(CGRect(x: rect.origin.x + sendActionButtonsFrame.origin.x, y: rect.origin.y + sendActionButtonsFrame.origin.y, width: sendActionButtonsFrame.width, height: sendActionButtonsFrame.height), within: containerSize, transition: transition)
|
||||
}
|
||||
|
||||
let slowModeButtonFrame = CGRect(origin: CGPoint(x: hideOffset.x + width - rightInset - 5.0 - slowModeButtonSize.width + composeButtonsOffset, y: hideOffset.y + panelHeight - minimalHeight + 6.0), size: slowModeButtonSize)
|
||||
let slowModeButtonFrame = CGRect(origin: CGPoint(x: hideOffset.x + width - rightInset - 5.0 - slowModeButtonSize.width + composeButtonsOffset, y: hideOffset.y + panelHeight - minimalHeight), size: slowModeButtonSize)
|
||||
transition.updateFrame(node: self.slowModeButton, frame: slowModeButtonFrame)
|
||||
|
||||
if let _ = interfaceState.inputTextPanelState.mediaRecordingState {
|
||||
|
|
@ -4381,7 +4381,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||
}
|
||||
})
|
||||
|
||||
blurTransitionOut.animateBlur(layer: self.sendActionButtons.sendContainerNode.layer, fromRadius: 0.0, toRadius: sendButtonBlurOut)
|
||||
blurTransitionOut.setBlur(layer: self.sendActionButtons.sendContainerNode.layer, radius: sendButtonBlurOut)
|
||||
|
||||
if let sendButtonRadialStatusNode = self.sendActionButtons.sendButtonRadialStatusNode {
|
||||
alphaTransition.updateAlpha(node: sendButtonRadialStatusNode, alpha: 0.0)
|
||||
|
|
@ -4412,7 +4412,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||
if (hasText || keepSendButtonEnabled && !mediaInputIsActive && !hasSlowModeButton) {
|
||||
if self.sendActionButtons.sendContainerNode.alpha.isZero && self.rightSlowModeInset.isZero {
|
||||
alphaTransition.updateAlpha(node: self.sendActionButtons.sendContainerNode, alpha: 1.0)
|
||||
blurTransitionIn.animateBlur(layer: self.sendActionButtons.sendContainerNode.layer, fromRadius: sendButtonBlurOut, toRadius: 0.0)
|
||||
blurTransitionIn.setBlur(layer: self.sendActionButtons.sendContainerNode.layer, radius: 0.0)
|
||||
transition.animatePositionAdditive(layer: self.sendActionButtons.sendButton.imageNode.layer, offset: CGPoint(x: -22.0, y: 18.0))
|
||||
if let sendButtonRadialStatusNode = self.sendActionButtons.sendButtonRadialStatusNode {
|
||||
alphaTransition.updateAlpha(node: sendButtonRadialStatusNode, alpha: 1.0)
|
||||
|
|
@ -4427,7 +4427,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
|||
strongSelf.applyUpdateSendButtonIcon()
|
||||
}
|
||||
})
|
||||
blurTransitionOut.animateBlur(layer: self.sendActionButtons.sendContainerNode.layer, fromRadius: 0.0, toRadius: sendButtonBlurOut)
|
||||
blurTransitionOut.setBlur(layer: self.sendActionButtons.sendContainerNode.layer, radius: sendButtonBlurOut)
|
||||
if let sendButtonRadialStatusNode = self.sendActionButtons.sendButtonRadialStatusNode {
|
||||
alphaTransition.updateAlpha(node: sendButtonRadialStatusNode, alpha: 0.0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -322,6 +322,7 @@ public final class ChatTextInputMediaRecordingButton: TGModernConversationInputM
|
|||
)
|
||||
let theme = self.hidesOnLock ? defaultDarkColorPresentationTheme : self.theme
|
||||
blobView.setColor(theme.chat.inputPanel.actionControlFillColor)
|
||||
blobView.hitTestSize = 110.0
|
||||
self.micDecorationValue = blobView
|
||||
return blobView
|
||||
}
|
||||
|
|
|
|||
|
|
@ -549,18 +549,18 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
|||
shimmeringForegroundColor = presentationData.theme.contextMenu.primaryColor.withMultipliedAlpha(0.07)
|
||||
}
|
||||
|
||||
let textRightInset: CGFloat
|
||||
let textRightInset: CGFloat = 8.0
|
||||
var textLeftInset: CGFloat = horizontalInset
|
||||
|
||||
if let _ = self.iconNode.image {
|
||||
textRightInset = iconSize.width - 2.0
|
||||
} else {
|
||||
textRightInset = 0.0
|
||||
textLeftInset = 60.0
|
||||
}
|
||||
|
||||
let makeTextLayout = TextNodeWithEntities.asyncLayout(self.textNode)
|
||||
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, minimumNumberOfLines: 0, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: width - horizontalInset * 2.0 - textRightInset, height: .greatestFiniteMagnitude), alignment: .left, lineSpacing: 0.12, cutout: nil, insets: UIEdgeInsets(), lineColor: nil, textShadowColor: nil, textStroke: nil))
|
||||
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, minimumNumberOfLines: 0, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: width - textLeftInset - textRightInset, height: .greatestFiniteMagnitude), alignment: .left, lineSpacing: 0.12, cutout: nil, insets: UIEdgeInsets(), lineColor: nil, textShadowColor: nil, textStroke: nil))
|
||||
let _ = textApply(self.arguments?.withUpdatedPlaceholderColor(shimmeringForegroundColor))
|
||||
|
||||
let textFrame = CGRect(origin: CGPoint(x: horizontalInset, y: topInset), size: textLayout.size)
|
||||
let textFrame = CGRect(origin: CGPoint(x: textLeftInset, y: topInset), size: textLayout.size)
|
||||
transition.updateFrame(node: self.textNode.textNode, frame: textFrame)
|
||||
if textFrame.size.height.isZero {
|
||||
self.textNode.textNode.alpha = 0.0
|
||||
|
|
|
|||
|
|
@ -827,6 +827,17 @@ public final class ContextControllerActionsListStackItem: ContextControllerActio
|
|||
self.addSubnode(item.node)
|
||||
}
|
||||
|
||||
if let tipSignal = tipSignal {
|
||||
self.tipDisposable = (tipSignal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] tip in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.tip = tip
|
||||
requestUpdate(.immediate)
|
||||
}).strict()
|
||||
}
|
||||
|
||||
requestUpdateAction = { [weak self] id, action in
|
||||
guard let self else {
|
||||
return
|
||||
|
|
@ -981,17 +992,26 @@ public final class ContextControllerActionsListStackItem: ContextControllerActio
|
|||
if let tip = self.tip {
|
||||
let tipNode: InnerTextSelectionTipContainerNode
|
||||
var tipTransition = transition
|
||||
if let current = self.tipNode {
|
||||
if let current = self.tipNode, current.tip == tip {
|
||||
tipNode = current
|
||||
} else {
|
||||
tipTransition = .immediate
|
||||
|
||||
let previousTipNode = self.tipNode
|
||||
tipNode = InnerTextSelectionTipContainerNode(presentationData: presentationData, tip: tip, isInline: true)
|
||||
self.addSubnode(tipNode)
|
||||
self.tipNode = tipNode
|
||||
let getController = self.getController
|
||||
tipNode.requestDismiss = { completion in
|
||||
getController()?.dismiss(completion: completion)
|
||||
}
|
||||
self.addSubnode(tipNode)
|
||||
self.tipNode = tipNode
|
||||
|
||||
if let previousTipNode = previousTipNode {
|
||||
previousTipNode.animateTransitionInside(other: tipNode)
|
||||
previousTipNode.removeFromSupernode()
|
||||
|
||||
tipNode.animateContentIn()
|
||||
}
|
||||
}
|
||||
|
||||
let tipSeparatorNode: ContextControllerActionsListSeparatorItemNode
|
||||
|
|
@ -1004,12 +1024,15 @@ public final class ContextControllerActionsListStackItem: ContextControllerActio
|
|||
}
|
||||
|
||||
let (tipSeparatorMinSize, tipSeparatorApply) = tipSeparatorNode.update(presentationData: presentationData, constrainedSize: CGSize(width: combinedSize.width, height: 10.0))
|
||||
tipSeparatorNode.isHidden = self.itemNodes.isEmpty
|
||||
let tipSeparatorSize = CGSize(width: combinedSize.width, height: tipSeparatorMinSize.height)
|
||||
tipSeparatorApply(tipSeparatorSize, tipTransition)
|
||||
let tipSeparatorFrame = CGRect(origin: nextItemOrigin, size: tipSeparatorSize)
|
||||
tipTransition.updateFrame(node: tipSeparatorNode, frame: tipSeparatorFrame)
|
||||
nextItemOrigin.y += tipSeparatorSize.height
|
||||
combinedSize.height += tipSeparatorSize.height
|
||||
if !tipSeparatorNode.isHidden {
|
||||
nextItemOrigin.y += tipSeparatorSize.height
|
||||
combinedSize.height += tipSeparatorSize.height
|
||||
}
|
||||
|
||||
let tipSize = tipNode.updateLayout(widthClass: .compact, presentation: .inline, width: combinedSize.width, transition: tipTransition)
|
||||
let tipFrame = CGRect(origin: nextItemOrigin, size: tipSize)
|
||||
|
|
@ -1488,7 +1511,6 @@ public final class ContextControllerActionsStackNodeImpl: ASDisplayNode, Context
|
|||
}
|
||||
}
|
||||
|
||||
self.sourceExtractableContainer = nil
|
||||
self.contentContainer.frame = CGRect(origin: CGPoint(), size: sourceSize)
|
||||
self.contentContainer.layer.cornerRadius = normalCornerRadius
|
||||
|
||||
|
|
@ -1553,7 +1575,7 @@ public final class ContextControllerActionsStackNodeImpl: ASDisplayNode, Context
|
|||
self.backgroundView.update(size: size, cornerRadius: min(30.0, size.height * 0.5), isDark: presentationData.theme.overallDarkAppearance, tintColor: .init(kind: .panel), isInteractive: true, transition: transition)
|
||||
|
||||
if let sourceExtractableContainer = self.sourceExtractableContainer {
|
||||
transition.setFrame(view: sourceExtractableContainer.extractableContentView, frame: CGRect(origin: CGPoint(), size: size))
|
||||
transition.setFrame(view: sourceExtractableContainer.extractableContentView, frame: CGRect(origin: CGPoint(x: self.backgroundContainerInset, y: self.backgroundContainerInset), size: size))
|
||||
sourceExtractableContainer.updateState(state: .extracted(size: size, cornerRadius: min(30.0, size.height * 0.5), state: .animatedIn), transition: .transition(transition.containedViewLayoutTransition), completion: nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ private final class CraftGiftPageContent: Component {
|
|||
let starsTopUpOptionsPromise: Promise<[StarsTopUpOption]?>
|
||||
let selectGift: (Int32, GiftItem) -> Void
|
||||
let removeGift: (Int32) -> Void
|
||||
let craftAnotherGift: () -> Void
|
||||
let dismiss: () -> Void
|
||||
|
||||
init(
|
||||
|
|
@ -86,6 +87,7 @@ private final class CraftGiftPageContent: Component {
|
|||
starsTopUpOptionsPromise: Promise<[StarsTopUpOption]?>,
|
||||
selectGift: @escaping (Int32, GiftItem) -> Void,
|
||||
removeGift: @escaping (Int32) -> Void,
|
||||
craftAnotherGift: @escaping () -> Void,
|
||||
dismiss: @escaping () -> Void
|
||||
) {
|
||||
self.context = context
|
||||
|
|
@ -102,6 +104,7 @@ private final class CraftGiftPageContent: Component {
|
|||
self.starsTopUpOptionsPromise = starsTopUpOptionsPromise
|
||||
self.selectGift = selectGift
|
||||
self.removeGift = removeGift
|
||||
self.craftAnotherGift = craftAnotherGift
|
||||
self.dismiss = dismiss
|
||||
}
|
||||
|
||||
|
|
@ -1203,7 +1206,13 @@ private final class CraftGiftPageContent: Component {
|
|||
}
|
||||
if let _ = view {
|
||||
if case let .gift(gift) = component.result {
|
||||
let giftController = GiftViewScreen(context: component.context, subject: .profileGift(component.context.account.peerId, gift))
|
||||
let giftController = GiftViewScreen(
|
||||
context: component.context,
|
||||
subject: .profileGift(component.context.account.peerId, gift),
|
||||
customAction: .init(title: environment.strings.Gift_Craft_CraftingFailed_CraftAnotherGift, action: {
|
||||
component.craftAnotherGift()
|
||||
})
|
||||
)
|
||||
if let navigationController = controller.navigationController {
|
||||
navigationController.pushViewController(giftController, animated: true)
|
||||
|
||||
|
|
@ -1548,6 +1557,36 @@ private final class SheetContainerComponent: CombinedComponent {
|
|||
}
|
||||
}
|
||||
|
||||
let navigationController = environment.controller()?.navigationController as? NavigationController
|
||||
let profileGiftsContext = (environment.controller() as? GiftCraftScreen)?.profileGiftsContext
|
||||
let resaleContext = state.resaleContext
|
||||
let starsTopUpOptionsPromise = state.starsTopUpOptionsPromise
|
||||
let craftAnotherGift = { [weak navigationController] in
|
||||
guard let navigationController else {
|
||||
return
|
||||
}
|
||||
if let genericGift = externalState.starGiftsMap[component.gift.giftId] {
|
||||
HapticFeedback().impact(.light)
|
||||
|
||||
let selectController = SelectCraftGiftScreen(
|
||||
context: component.context,
|
||||
craftContext: component.craftContext,
|
||||
resaleContext: resaleContext,
|
||||
gift: component.gift,
|
||||
genericGift: genericGift,
|
||||
selectedGiftIds: Set(),
|
||||
starsTopUpOptions: starsTopUpOptionsPromise.get(),
|
||||
selectGift: { [weak navigationController] item in
|
||||
if let navigationController{
|
||||
let craftController = GiftCraftScreen(context: component.context, gift: item.gift, profileGiftsContext: profileGiftsContext)
|
||||
navigationController.pushViewController(craftController)
|
||||
}
|
||||
}
|
||||
)
|
||||
navigationController.pushViewController(selectController)
|
||||
}
|
||||
}
|
||||
|
||||
let theme = environment.theme
|
||||
|
||||
var colors: (UIColor, UIColor, UIColor, UIColor, UIColor) = (
|
||||
|
|
@ -1720,6 +1759,7 @@ private final class SheetContainerComponent: CombinedComponent {
|
|||
state.selectedGiftIds[index] = nil
|
||||
state.updated(transition: .spring(duration: 0.4))
|
||||
},
|
||||
craftAnotherGift: craftAnotherGift,
|
||||
dismiss: {
|
||||
dismiss(true)
|
||||
}
|
||||
|
|
@ -1791,26 +1831,9 @@ private final class SheetContainerComponent: CombinedComponent {
|
|||
if state.displayInfo {
|
||||
state.displayInfo = false
|
||||
state.updated(transition: .spring(duration: 0.3))
|
||||
} else if state.displayFailure, let genericGift = externalState.starGiftsMap[component.gift.giftId] {
|
||||
HapticFeedback().impact(.light)
|
||||
|
||||
let selectController = SelectCraftGiftScreen(
|
||||
context: component.context,
|
||||
craftContext: component.craftContext,
|
||||
resaleContext: state.resaleContext,
|
||||
gift: component.gift,
|
||||
genericGift: genericGift,
|
||||
selectedGiftIds: Set(),
|
||||
starsTopUpOptions: state.starsTopUpOptionsPromise.get(),
|
||||
selectGift: { item in
|
||||
if let controller = controller() as? GiftCraftScreen, let navigationController = controller.navigationController as? NavigationController {
|
||||
let craftController = GiftCraftScreen(context: component.context, gift: item.gift, profileGiftsContext: controller.profileGiftsContext)
|
||||
controller.dismissAnimated()
|
||||
navigationController.pushViewController(craftController)
|
||||
}
|
||||
}
|
||||
)
|
||||
environment.controller()?.push(selectController)
|
||||
} else if state.displayFailure {
|
||||
craftAnotherGift()
|
||||
dismiss(true)
|
||||
} else {
|
||||
HapticFeedback().impact(.medium)
|
||||
|
||||
|
|
@ -1861,6 +1884,10 @@ private final class SheetContainerComponent: CombinedComponent {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Queue.mainQueue().after(1.0) {
|
||||
craftContext.reload()
|
||||
}
|
||||
}, error: { error in
|
||||
switch error {
|
||||
case .craftFailed:
|
||||
|
|
|
|||
|
|
@ -153,6 +153,8 @@ final class SelectGiftPageContent: Component {
|
|||
}
|
||||
transition.setFrame(view: self.loadingView, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight - 170.0), size: loadingSize))
|
||||
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
|
||||
var itemFrame = CGRect(origin: CGPoint(x: itemSideInset, y: contentHeight), size: itemSize)
|
||||
var itemsHeight: CGFloat = 0.0
|
||||
var validIds: [AnyHashable] = []
|
||||
|
|
@ -245,6 +247,12 @@ final class SelectGiftPageContent: Component {
|
|||
}
|
||||
}
|
||||
itemTransition.setFrame(view: itemView, frame: itemFrame)
|
||||
|
||||
var canCraft = true
|
||||
if let profileGift = self.giftMap[gift.gift.id], let canCraftDate = profileGift.canCraftAt, currentTime < canCraftDate {
|
||||
canCraft = false
|
||||
}
|
||||
transition.setAlpha(view: itemView, alpha: canCraft ? 1.0 : 0.5)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -414,6 +422,7 @@ final class SelectGiftPageContent: Component {
|
|||
contentHeight += 32.0
|
||||
|
||||
contentHeight = self.updateScrolling(interactive: false, transition: transition)
|
||||
let originalContentHeight = contentHeight
|
||||
|
||||
let resaleCount = component.genericGift.availability?.resale ?? 0
|
||||
let saleTitle = environment.strings.Gift_Craft_Select_SaleGiftsCount(Int32(clamping: resaleCount)).uppercased()
|
||||
|
|
@ -483,7 +492,11 @@ final class SelectGiftPageContent: Component {
|
|||
}
|
||||
transition.setFrame(view: storeGiftsView, frame: storeGiftsFrame)
|
||||
|
||||
storeGiftsView.updateScrolling(bounds: CGRect(origin: .zero, size: availableSize), transition: .immediate)
|
||||
var effectiveBounds = CGRect(origin: .zero, size: CGSize(width: availableSize.width, height: 1000.0))
|
||||
if let bounds = self.currentBounds {
|
||||
effectiveBounds = bounds.offsetBy(dx: 0.0, dy: -originalContentHeight)
|
||||
}
|
||||
storeGiftsView.updateScrolling(bounds: effectiveBounds, transition: .immediate)
|
||||
}
|
||||
contentHeight += storeGiftsSize.height
|
||||
contentHeight += 90.0
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ private func actionForAttribute(attribute: StarGift.UniqueGift.Attribute, presen
|
|||
return ContextMenuActionItem(text: title, entities: entities, entityFiles: entityFiles, enableEntityAnimations: false, customTextInsets: UIEdgeInsets(top: 0.0, left: 18.0 + 5.0, bottom: 0.0, right: 0.0), parseMarkdown: true, icon: { _ in
|
||||
return nil
|
||||
}, additionalLeftIcon: { theme in
|
||||
return isSelected ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return isSelected ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
getController()?.dismiss(result: .dismissWithoutContent, completion: nil)
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ private func actionForAttribute(attribute: StarGift.UniqueGift.Attribute, presen
|
|||
return ContextMenuActionItem(text: title, entities: entities, icon: { _ in
|
||||
return generateGradientFilledCircleImage(diameter: 24.0, colors: [UIColor(rgb: UInt32(bitPattern: innerColor)).cgColor, UIColor(rgb: UInt32(bitPattern: outerColor)).cgColor])
|
||||
}, additionalLeftIcon: { theme in
|
||||
return isSelected ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return isSelected ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
getController()?.dismiss(result: .dismissWithoutContent, completion: nil)
|
||||
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ public final class GiftStoreContentComponent: Component {
|
|||
if let initialCount = self.initialCount, initialCount < minimumCountToDisplayFilters {
|
||||
topInset = component.navigationHeight
|
||||
}
|
||||
|
||||
|
||||
let visibleBounds = bounds.insetBy(dx: 0.0, dy: -10.0)
|
||||
if let starGifts = self.effectiveGifts {
|
||||
let sideInset: CGFloat = 16.0 + component.safeInsets.left
|
||||
|
|
@ -1269,8 +1269,10 @@ final class GiftStoreScreenComponent: Component {
|
|||
guard let self, let component = self.component, let environment = self.environment else {
|
||||
return
|
||||
}
|
||||
let controller = component.context.sharedContext.makeStarsTransactionsScreen(context: component.context, starsContext: starsContext)
|
||||
environment.controller()?.push(controller)
|
||||
Queue.mainQueue().after(0.3) {
|
||||
let controller = component.context.sharedContext.makeStarsTransactionsScreen(context: component.context, starsContext: starsContext)
|
||||
environment.controller()?.push(controller)
|
||||
}
|
||||
}
|
||||
)))
|
||||
|
||||
|
|
@ -1283,8 +1285,10 @@ final class GiftStoreScreenComponent: Component {
|
|||
guard let self, let component = self.component, let environment = self.environment else {
|
||||
return
|
||||
}
|
||||
let controller = component.context.sharedContext.makeStarsTransactionsScreen(context: component.context, starsContext: tonContext)
|
||||
environment.controller()?.push(controller)
|
||||
Queue.mainQueue().after(0.3) {
|
||||
let controller = component.context.sharedContext.makeStarsTransactionsScreen(context: component.context, starsContext: tonContext)
|
||||
environment.controller()?.push(controller)
|
||||
}
|
||||
}
|
||||
)))
|
||||
|
||||
|
|
|
|||
|
|
@ -4677,7 +4677,26 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
)
|
||||
|
||||
let buttonChild: _UpdatedChildComponent
|
||||
if state.canSkip {
|
||||
if let controller = controller() as? GiftViewScreen, let customAction = controller.customAction {
|
||||
buttonChild = button.update(
|
||||
component: ButtonComponent(
|
||||
background: buttonBackground,
|
||||
content: AnyComponentWithIdentity(
|
||||
id: AnyHashable("custom"),
|
||||
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: customAction.title, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center))))
|
||||
),
|
||||
isEnabled: true,
|
||||
displaysProgress: state.inProgress,
|
||||
action: { [weak state] in
|
||||
if let state {
|
||||
customAction.action()
|
||||
state.dismiss(animated: true)
|
||||
}
|
||||
}),
|
||||
availableSize: buttonSize,
|
||||
transition: context.transition
|
||||
)
|
||||
} else if state.canSkip {
|
||||
buttonChild = button.update(
|
||||
component: ButtonComponent(
|
||||
background: buttonBackground,
|
||||
|
|
@ -5630,6 +5649,16 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||
}
|
||||
}
|
||||
|
||||
public struct CustomAction {
|
||||
public let title: String
|
||||
public let action: () -> Void
|
||||
|
||||
public init(title: String, action: @escaping () -> Void) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
}
|
||||
}
|
||||
|
||||
private let context: AccountContext
|
||||
private let subject: GiftViewScreen.Subject
|
||||
|
||||
|
|
@ -5671,6 +5700,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||
fileprivate let togglePinnedToTop: ((StarGiftReference, Bool) -> Bool)?
|
||||
fileprivate let shareStory: ((StarGift.UniqueGift) -> Void)?
|
||||
fileprivate let openChatTheme: (() -> Void)?
|
||||
fileprivate let customAction: CustomAction?
|
||||
|
||||
public var disposed: () -> Void = {}
|
||||
|
||||
|
|
@ -5690,7 +5720,8 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||
updateResellStars: ((StarGiftReference, CurrencyAmount?) -> Signal<Never, UpdateStarGiftPriceError>)? = nil,
|
||||
togglePinnedToTop: ((StarGiftReference, Bool) -> Bool)? = nil,
|
||||
shareStory: ((StarGift.UniqueGift) -> Void)? = nil,
|
||||
openChatTheme: (() -> Void)? = nil
|
||||
openChatTheme: (() -> Void)? = nil,
|
||||
customAction: CustomAction? = nil
|
||||
) {
|
||||
self.context = context
|
||||
self.subject = subject
|
||||
|
|
@ -5706,6 +5737,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||
self.togglePinnedToTop = togglePinnedToTop
|
||||
self.shareStory = shareStory
|
||||
self.openChatTheme = openChatTheme
|
||||
self.customAction = customAction
|
||||
|
||||
if case let .unique(gift) = subject.arguments?.gift, gift.resellForTonOnly {
|
||||
self.balanceCurrency = .ton
|
||||
|
|
|
|||
|
|
@ -437,7 +437,21 @@ public class GlassBackgroundView: UIView {
|
|||
if let legacyView = self.legacyView {
|
||||
switch shape {
|
||||
case let .roundedRect(cornerRadius):
|
||||
legacyView.update(size: size, cornerRadius: cornerRadius, transition: transition)
|
||||
let style: LegacyGlassView.Style
|
||||
switch tintColor.kind {
|
||||
case .panel:
|
||||
style = .normal
|
||||
case .clear:
|
||||
style = .clear
|
||||
case let .custom(styleValue, _):
|
||||
switch styleValue {
|
||||
case .clear:
|
||||
style = .clear
|
||||
case .default:
|
||||
style = .normal
|
||||
}
|
||||
}
|
||||
legacyView.update(size: size, cornerRadius: cornerRadius, style: style, transition: transition)
|
||||
}
|
||||
transition.setFrame(view: legacyView, frame: CGRect(origin: CGPoint(), size: size))
|
||||
transition.setAlpha(view: legacyView, alpha: isVisible ? 1.0 : 0.0)
|
||||
|
|
@ -512,19 +526,28 @@ public class GlassBackgroundView: UIView {
|
|||
|
||||
if let foregroundView = self.foregroundView {
|
||||
let fillColor: UIColor
|
||||
let borderWidthFactor: CGFloat
|
||||
switch tintColor.kind {
|
||||
case .panel:
|
||||
borderWidthFactor = 1.0
|
||||
if isDark {
|
||||
fillColor = UIColor(white: 1.0, alpha: 1.0).mixedWith(.black, alpha: 1.0 - 0.11).withAlphaComponent(0.85)
|
||||
} else {
|
||||
fillColor = UIColor(white: 1.0, alpha: 0.7)
|
||||
}
|
||||
case .clear:
|
||||
borderWidthFactor = 2.0
|
||||
fillColor = UIColor(white: 1.0, alpha: 0.0)
|
||||
case let .custom(_, color):
|
||||
case let .custom(style, color):
|
||||
fillColor = color
|
||||
switch style {
|
||||
case .clear:
|
||||
borderWidthFactor = 2.0
|
||||
case .default:
|
||||
borderWidthFactor = 1.0
|
||||
}
|
||||
}
|
||||
foregroundView.image = GlassBackgroundView.generateLegacyGlassImage(size: CGSize(width: outerCornerRadius * 2.0, height: outerCornerRadius * 2.0), inset: shadowInset, isDark: isDark, fillColor: fillColor)
|
||||
foregroundView.image = GlassBackgroundView.generateLegacyGlassImage(size: CGSize(width: outerCornerRadius * 2.0, height: outerCornerRadius * 2.0), inset: shadowInset, borderWidthFactor: borderWidthFactor, isDark: isDark, fillColor: fillColor)
|
||||
transition.setAlpha(view: foregroundView, alpha: isVisible ? 1.0 : 0.0)
|
||||
} else {
|
||||
if let nativeParamsView = self.nativeParamsView, let nativeView = self.nativeView {
|
||||
|
|
@ -565,11 +588,21 @@ public class GlassBackgroundView: UIView {
|
|||
|
||||
if glassEffect == nil {
|
||||
if nativeView.effect is UIGlassEffect {
|
||||
if transition.animation.isImmediate {
|
||||
nativeView.effect = nil
|
||||
} else {
|
||||
transition.animateView {
|
||||
if #available(iOS 26.1, *) {
|
||||
if transition.animation.isImmediate {
|
||||
nativeView.effect = nil
|
||||
} else {
|
||||
transition.animateView {
|
||||
nativeView.effect = nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if transition.animation.isImmediate {
|
||||
nativeView.effect = UIVisualEffect()
|
||||
} else {
|
||||
transition.animateView {
|
||||
nativeView.effect = UIVisualEffect()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -598,6 +631,9 @@ public class GlassBackgroundView: UIView {
|
|||
}
|
||||
}
|
||||
|
||||
if let nativeParamsView = self.nativeParamsView {
|
||||
transition.setFrame(view: nativeParamsView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size))
|
||||
}
|
||||
transition.setFrame(view: self.maskContainerView, frame: CGRect(origin: CGPoint(), size: CGSize(width: size.width + shadowInset * 2.0, height: size.height + shadowInset * 2.0)))
|
||||
transition.setFrame(view: self.maskContentView, frame: CGRect(origin: CGPoint(x: shadowInset, y: shadowInset), size: size))
|
||||
if let foregroundView = self.foregroundView {
|
||||
|
|
@ -631,7 +667,7 @@ public final class GlassBackgroundContainerView: UIView {
|
|||
}
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
if #available(iOS 26.0, *) {
|
||||
if #available(iOS 26.0, *), !GlassBackgroundView.useCustomGlassImpl {
|
||||
let effect = UIGlassContainerEffect()
|
||||
effect.spacing = 7.0
|
||||
let nativeView = UIVisualEffectView(effect: effect)
|
||||
|
|
@ -707,6 +743,9 @@ public final class GlassBackgroundContainerView: UIView {
|
|||
nativeParamsView.lumaMin = 0.8
|
||||
nativeParamsView.lumaMax = 0.801
|
||||
}
|
||||
if let nativeParamsView = self.nativeParamsView {
|
||||
transition.setFrame(view: nativeParamsView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size))
|
||||
}
|
||||
|
||||
transition.animateView {
|
||||
nativeView.frame = CGRect(origin: CGPoint(), size: size)
|
||||
|
|
@ -768,7 +807,7 @@ private extension CGContext {
|
|||
}
|
||||
|
||||
public extension GlassBackgroundView {
|
||||
static func generateLegacyGlassImage(size: CGSize, inset: CGFloat, isDark: Bool, fillColor: UIColor) -> UIImage {
|
||||
static func generateLegacyGlassImage(size: CGSize, inset: CGFloat, borderWidthFactor: CGFloat = 1.0, isDark: Bool, fillColor: UIColor) -> UIImage {
|
||||
var size = size
|
||||
if size == .zero {
|
||||
size = CGSize(width: 2.0, height: 2.0)
|
||||
|
|
@ -908,7 +947,7 @@ public extension GlassBackgroundView {
|
|||
var ellipseRect = CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset)
|
||||
context.fillEllipse(in: ellipseRect)
|
||||
|
||||
let lineWidth: CGFloat = isDark ? 0.8 : 0.8
|
||||
let lineWidth: CGFloat = (isDark ? 0.8 : 0.8) * borderWidthFactor
|
||||
let strokeColor: UIColor
|
||||
let blendMode: CGBlendMode
|
||||
let baseAlpha: CGFloat = isDark ? 0.3 : 0.6
|
||||
|
|
@ -956,20 +995,6 @@ public extension GlassBackgroundView {
|
|||
|
||||
context.resetClip()
|
||||
context.setBlendMode(.normal)
|
||||
|
||||
//let image = makeInnerShadowPillImageExact(size: CGSize(width: size.width - inset * 2.0, height: size.height - inset * 2.0), scale: UIScreenScale, glossColor: UIColor(white: 1.0, alpha: 1.0), borderWidth: 1.33)
|
||||
/*let image = generateCircleImage(diameter: size.width - inset * 2.0, lineWidth: 0.5, color: UIColor(white: 1.0, alpha: 1.0))!
|
||||
|
||||
if s == 0.0 && abs(a - 0.7) < 0.1 && !isDark {
|
||||
image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset), blendMode: .normal, alpha: 1.0)
|
||||
} else if s <= 0.3 && !isDark {
|
||||
image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset), blendMode: .normal, alpha: 0.7)
|
||||
} else if b >= 0.2 {
|
||||
let maxAlpha: CGFloat = isDark ? 0.7 : 0.8
|
||||
image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset), blendMode: .overlay, alpha: max(0.5, min(1.0, maxAlpha * s)))
|
||||
} else {
|
||||
image.draw(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset), blendMode: .normal, alpha: 0.5)
|
||||
}*/
|
||||
}
|
||||
innerImage.draw(in: CGRect(origin: CGPoint(), size: size))
|
||||
}.stretchableImage(withLeftCapWidth: Int(size.width * 0.5), topCapHeight: Int(size.height * 0.5))
|
||||
|
|
|
|||
|
|
@ -81,13 +81,20 @@ private final class BackdropLayerDelegate: NSObject, CALayerDelegate {
|
|||
}
|
||||
|
||||
final class LegacyGlassView: UIView {
|
||||
enum Style {
|
||||
case normal
|
||||
case clear
|
||||
}
|
||||
|
||||
private struct Params: Equatable {
|
||||
let size: CGSize
|
||||
let cornerRadius: CGFloat
|
||||
let style: Style
|
||||
|
||||
init(size: CGSize, cornerRadius: CGFloat) {
|
||||
init(size: CGSize, cornerRadius: CGFloat, style: Style) {
|
||||
self.size = size
|
||||
self.cornerRadius = cornerRadius
|
||||
self.style = style
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,19 +116,8 @@ final class LegacyGlassView: UIView {
|
|||
self.layer.addSublayer(backdropLayer)
|
||||
backdropLayer.delegate = self.backdropLayerDelegate
|
||||
|
||||
let blur: CGFloat
|
||||
let scale: CGFloat
|
||||
|
||||
blur = 2.0
|
||||
scale = 1.0
|
||||
|
||||
invokeBackdropLayerSetScaleMethod(object: backdropLayer, scale: scale)
|
||||
backdropLayer.rasterizationScale = scale
|
||||
|
||||
if let blurFilter = CALayer.blur() {
|
||||
blurFilter.setValue(blur as NSNumber, forKey: "inputRadius")
|
||||
backdropLayer.filters = [blurFilter]
|
||||
}
|
||||
invokeBackdropLayerSetScaleMethod(object: backdropLayer, scale: 1.0)
|
||||
backdropLayer.rasterizationScale = 1.0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -129,8 +125,9 @@ final class LegacyGlassView: UIView {
|
|||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func update(size: CGSize, cornerRadius: CGFloat, transition: ComponentTransition) {
|
||||
let params = Params(size: size, cornerRadius: cornerRadius)
|
||||
func update(size: CGSize, cornerRadius: CGFloat, style: Style, transition: ComponentTransition) {
|
||||
let params = Params(size: size, cornerRadius: cornerRadius, style: style)
|
||||
let previousParams = self.params
|
||||
if self.params == params {
|
||||
return
|
||||
}
|
||||
|
|
@ -140,6 +137,18 @@ final class LegacyGlassView: UIView {
|
|||
return
|
||||
}
|
||||
|
||||
if previousParams?.style != style {
|
||||
if let blurFilter = CALayer.blur() {
|
||||
switch style {
|
||||
case .clear:
|
||||
blurFilter.setValue(6.0 as NSNumber, forKey: "inputRadius")
|
||||
case .normal:
|
||||
blurFilter.setValue(2.0 as NSNumber, forKey: "inputRadius")
|
||||
}
|
||||
backdropLayer.filters = [blurFilter]
|
||||
}
|
||||
}
|
||||
|
||||
transition.setCornerRadius(layer: self.layer, cornerRadius: cornerRadius)
|
||||
transition.setFrame(layer: backdropLayer, frame: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
|
|
|
|||
|
|
@ -408,7 +408,7 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||
items.append(.action(ContextMenuActionItem(text: title, textLayout: .multiline, textFont: .small, icon: { _ in return nil }, action: emptyAction)))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.MediaPicker_Timer_ViewOnce, icon: { theme in
|
||||
return currentValue == viewOnceTimeout ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return currentValue == viewOnceTimeout ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, a in
|
||||
a(.default)
|
||||
|
||||
|
|
@ -419,7 +419,7 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||
|
||||
for value in values {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.MediaPicker_Timer_Seconds(value), icon: { theme in
|
||||
return currentValue == value ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return currentValue == value ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, a in
|
||||
a(.default)
|
||||
|
||||
|
|
@ -428,7 +428,7 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.MediaPicker_Timer_DoNotDelete, icon: { theme in
|
||||
return currentValue == nil ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return currentValue == nil ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, a in
|
||||
a(.default)
|
||||
|
||||
|
|
|
|||
|
|
@ -7286,7 +7286,7 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||
color: theme.contextMenu.primaryColor
|
||||
)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
},
|
||||
action: { [weak self] _, a in
|
||||
|
|
|
|||
|
|
@ -561,7 +561,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, ASScrollVi
|
|||
if isSelected && value == nil {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}), action: { [weak self] _, f in
|
||||
scheduleTooltip(nil)
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ final class AffiliateProgramSetupScreenComponent: Component {
|
|||
if isSelected {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.actionSheet.primaryTextColor)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
|
|
|||
|
|
@ -172,28 +172,28 @@ extension PeerInfoScreenNode {
|
|||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Unlimited, icon: { theme in
|
||||
return filter.contains(.unlimited) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return filter.contains(.unlimited) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
toggleFilter(.unlimited)
|
||||
}, longPressAction: { _, f in
|
||||
switchToFilter(.unlimited)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Limited, icon: { theme in
|
||||
return filter.contains(.limitedNonUpgradable) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return filter.contains(.limitedNonUpgradable) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
toggleFilter(.limitedNonUpgradable)
|
||||
}, longPressAction: { _, f in
|
||||
switchToFilter(.limitedNonUpgradable)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Upgradable, icon: { theme in
|
||||
return filter.contains(.limitedUpgradable) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return filter.contains(.limitedUpgradable) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
toggleFilter(.limitedUpgradable)
|
||||
}, longPressAction: { _, f in
|
||||
switchToFilter(.limitedUpgradable)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Unique, icon: { theme in
|
||||
return filter.contains(.unique) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return filter.contains(.unique) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
toggleFilter(.unique)
|
||||
}, longPressAction: { _, f in
|
||||
|
|
@ -204,14 +204,14 @@ extension PeerInfoScreenNode {
|
|||
items.append(.separator)
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Displayed, icon: { theme in
|
||||
return filter.contains(.displayed) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return filter.contains(.displayed) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
toggleFilter(.displayed)
|
||||
}, longPressAction: { _, f in
|
||||
switchToVisiblityFilter(.displayed)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Hidden, icon: { theme in
|
||||
return filter.contains(.hidden) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return filter.contains(.hidden) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
toggleFilter(.hidden)
|
||||
}, longPressAction: { _, f in
|
||||
|
|
|
|||
|
|
@ -381,28 +381,28 @@ public final class AddGiftsScreen: ViewControllerComponentContainer {
|
|||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Unlimited, icon: { theme in
|
||||
return filter.contains(.unlimited) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return filter.contains(.unlimited) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
toggleFilter(.unlimited)
|
||||
}, longPressAction: { _, f in
|
||||
switchToFilter(.unlimited)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Limited, icon: { theme in
|
||||
return filter.contains(.limitedNonUpgradable) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return filter.contains(.limitedNonUpgradable) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
toggleFilter(.limitedNonUpgradable)
|
||||
}, longPressAction: { _, f in
|
||||
switchToFilter(.limitedNonUpgradable)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Upgradable, icon: { theme in
|
||||
return filter.contains(.limitedUpgradable) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return filter.contains(.limitedUpgradable) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
toggleFilter(.limitedUpgradable)
|
||||
}, longPressAction: { _, f in
|
||||
switchToFilter(.limitedUpgradable)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Unique, icon: { theme in
|
||||
return filter.contains(.unique) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return filter.contains(.unique) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
toggleFilter(.unique)
|
||||
}, longPressAction: { _, f in
|
||||
|
|
@ -412,14 +412,14 @@ public final class AddGiftsScreen: ViewControllerComponentContainer {
|
|||
items.append(.separator)
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Displayed, icon: { theme in
|
||||
return filter.contains(.displayed) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return filter.contains(.displayed) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
toggleFilter(.displayed)
|
||||
}, longPressAction: { _, f in
|
||||
switchToVisiblityFilter(.displayed)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Hidden, icon: { theme in
|
||||
return filter.contains(.hidden) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
|
||||
return filter.contains(.hidden) ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
|
||||
}, action: { _, f in
|
||||
toggleFilter(.hidden)
|
||||
}, longPressAction: { _, f in
|
||||
|
|
|
|||
|
|
@ -1033,7 +1033,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||
let isAdded = gift.collectionIds?.contains(collection.id) ?? false
|
||||
|
||||
subItems.append(.action(ContextMenuActionItem(text: title, entities: entities, entityFiles: entityFiles, enableEntityAnimations: false, icon: { theme in
|
||||
return entities.isEmpty ? generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/Collection"), color: theme.contextMenu.primaryColor) : (isAdded ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil)
|
||||
return entities.isEmpty ? generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/Collection"), color: theme.contextMenu.primaryColor) : (isAdded ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage())
|
||||
}, iconPosition: collection.icon == nil ? .left : .right, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ private func commitChannelOwnershipTransferController(
|
|||
applyImpl = {
|
||||
doneInProgressPromise.set(true)
|
||||
|
||||
let signal: Signal<EnginePeer.Id?, ChannelOwnershipTransferError>
|
||||
let signal: Signal<EnginePeer.Id?, ChatOwnershipTransferError>
|
||||
if case let .channel(peer) = peer {
|
||||
signal = context.peerChannelMemberCategoriesContextsManager.transferOwnership(engine: context.engine, peerId: peer.id, memberId: member.id, password: inputState.value) |> mapToSignal { _ in
|
||||
return .complete()
|
||||
|
|
@ -97,7 +97,7 @@ private func commitChannelOwnershipTransferController(
|
|||
} else if case let .legacyGroup(peer) = peer {
|
||||
signal = context.engine.peers.convertGroupToSupergroup(peerId: peer.id)
|
||||
|> map(Optional.init)
|
||||
|> mapError { error -> ChannelOwnershipTransferError in
|
||||
|> mapError { error -> ChatOwnershipTransferError in
|
||||
switch error {
|
||||
case .tooManyChannels:
|
||||
return .tooMuchJoined
|
||||
|
|
@ -106,7 +106,7 @@ private func commitChannelOwnershipTransferController(
|
|||
}
|
||||
}
|
||||
|> deliverOnMainQueue
|
||||
|> mapToSignal { upgradedPeerId -> Signal<EnginePeer.Id?, ChannelOwnershipTransferError> in
|
||||
|> mapToSignal { upgradedPeerId -> Signal<EnginePeer.Id?, ChatOwnershipTransferError> in
|
||||
guard let upgradedPeerId = upgradedPeerId else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
|
@ -213,7 +213,7 @@ public func channelOwnershipTransferController(
|
|||
peer: EnginePeer,
|
||||
member: TelegramUser,
|
||||
onLeave: Bool,
|
||||
initialError: ChannelOwnershipTransferError,
|
||||
initialError: ChatOwnershipTransferError,
|
||||
present: @escaping (ViewController, Any?) -> Void,
|
||||
push: @escaping (ViewController) -> Void,
|
||||
completion: @escaping (EnginePeer.Id?) -> Void
|
||||
|
|
|
|||
|
|
@ -228,6 +228,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
|||
replaceImpl = { [weak controller] c in
|
||||
controller?.replace(with: c)
|
||||
}
|
||||
strongSelf.peerSelectionNode.pushedController = controller
|
||||
strongSelf.push(controller)
|
||||
} else {
|
||||
strongSelf.selectTab(id: id)
|
||||
|
|
@ -306,7 +307,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
|||
return
|
||||
}
|
||||
|
||||
if mainChannel.hasPermission(.manageDirect) {
|
||||
if !mainChannel.isMonoForum || mainChannel.hasPermission(.manageDirect) {
|
||||
let displayPeer = EnginePeer(mainChannel)
|
||||
|
||||
let controller = PeerSelectionControllerImpl(
|
||||
|
|
@ -330,6 +331,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
|||
)
|
||||
)
|
||||
controller.peerSelected = self.peerSelected
|
||||
self.peerSelectionNode.pushedController = controller
|
||||
self.push(controller)
|
||||
} else {
|
||||
peerSelected(.channel(peer), threadId)
|
||||
|
|
@ -373,6 +375,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
|||
)
|
||||
)
|
||||
controller.peerSelected = strongSelf.peerSelected
|
||||
strongSelf.peerSelectionNode.pushedController = controller
|
||||
strongSelf.push(controller)
|
||||
} else {
|
||||
peerSelected(peer, threadId)
|
||||
|
|
@ -626,4 +629,16 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
override public func dismiss(completion: (() -> Void)? = nil) {
|
||||
guard let navigationController = self.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
var viewControllers = navigationController.viewControllers
|
||||
viewControllers.removeAll(where: { $0 === self })
|
||||
if let pushedController = self.peerSelectionNode.pushedController {
|
||||
viewControllers.removeAll(where: { $0 === pushedController })
|
||||
}
|
||||
navigationController.setViewControllers(viewControllers, animated: true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,8 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||
|
||||
private var countPanelNode: PeersCountPanelNode?
|
||||
|
||||
weak var pushedController: ViewController?
|
||||
|
||||
private var readyValue = Promise<Bool>()
|
||||
var ready: Signal<Bool, NoError> {
|
||||
return self.readyValue.get()
|
||||
|
|
@ -286,10 +288,12 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||
return
|
||||
}
|
||||
self.chatListNode?.clearHighlightAnimated(true)
|
||||
self.mainContainerNode?.currentItemNode.clearHighlightAnimated(true)
|
||||
self.requestOpenPeer?(mainPeer, peer.id.toInt64())
|
||||
})
|
||||
} else {
|
||||
self.chatListNode?.clearHighlightAnimated(true)
|
||||
self.mainContainerNode?.currentItemNode.clearHighlightAnimated(true)
|
||||
self.requestOpenPeer?(peer, threadId)
|
||||
}
|
||||
}
|
||||
|
|
@ -348,6 +352,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||
replaceImpl = { [weak controller] c in
|
||||
controller?.replace(with: c)
|
||||
}
|
||||
strongSelf.pushedController = controller
|
||||
strongSelf.controller?.push(controller)
|
||||
}
|
||||
self.addSubnode(mainContainerNode)
|
||||
|
|
@ -488,7 +493,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||
if canHideNames {
|
||||
items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_ShowSendersName : presentationData.strings.Conversation_ForwardOptions_ShowSendersNames, icon: { theme in
|
||||
if hideNames {
|
||||
return nil
|
||||
return UIImage()
|
||||
} else {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}
|
||||
|
|
@ -506,7 +511,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||
if hideNames {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}, action: { _, f in
|
||||
self?.interfaceInteraction?.updateForwardOptionsState({ current in
|
||||
|
|
@ -523,7 +528,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||
if hasCaptions {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_ShowCaption, icon: { theme in
|
||||
if hideCaptions {
|
||||
return nil
|
||||
return UIImage()
|
||||
} else {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}
|
||||
|
|
@ -543,7 +548,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||
if hideCaptions {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}, action: { _, f in
|
||||
self?.interfaceInteraction?.updateForwardOptionsState({ current in
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ swift_library(
|
|||
"//submodules/TelegramUI/Components/TelegramAccountAuxiliaryMethods",
|
||||
"//submodules/TelegramUI/Components/PeerSelectionController",
|
||||
"//submodules/TelegramUI/Components/ContextMenuScreen",
|
||||
"//submodules/TelegramUI/Components/NavigationBarImpl",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import TelegramUIDeclareEncodables
|
|||
import TelegramAccountAuxiliaryMethods
|
||||
import PeerSelectionController
|
||||
import ContextMenuScreen
|
||||
import NavigationBarImpl
|
||||
|
||||
private var installedSharedLogger = false
|
||||
|
||||
|
|
@ -194,6 +195,10 @@ public class ShareRootControllerImpl {
|
|||
public init(initializationData: ShareRootControllerInitializationData, getExtensionContext: @escaping () -> NSExtensionContext?) {
|
||||
self.initializationData = initializationData
|
||||
self.getExtensionContext = getExtensionContext
|
||||
|
||||
defaultNavigationBarImpl = { presentationData in
|
||||
return NavigationBarImpl(presentationData: presentationData)
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
|||
|
|
@ -958,7 +958,7 @@ final class ShareWithPeersScreenComponent: Component {
|
|||
let isSelected = self.shareToFolders.contains(where: { $0.id == folderPreview.folder.id })
|
||||
items.append(.action(ContextMenuActionItem(text: folderPreview.folder.title, icon: icon, additionalLeftIcon: { theme in
|
||||
if !isSelected {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, iconSource: iconSource, iconPosition: .left, action: { [weak self] c, f in
|
||||
|
|
|
|||
|
|
@ -3241,7 +3241,7 @@ final class StorageUsageScreenComponent: Component {
|
|||
if currentValue == value {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}, action: { _, f in
|
||||
applyValue(value)
|
||||
|
|
|
|||
|
|
@ -6388,7 +6388,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
if isSelected && value == nil {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: .white)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}), action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
|
|
|||
|
|
@ -1397,7 +1397,7 @@ public final class StoryItemSetViewListComponent: Component {
|
|||
return generateTintedImage(image: UIImage(bundleImageName: "Stories/Context Menu/Repost"), color: theme.contextMenu.primaryColor)
|
||||
}, additionalLeftIcon: { theme in
|
||||
if sortMode != .repostsFirst {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, a in
|
||||
|
|
@ -1416,7 +1416,7 @@ public final class StoryItemSetViewListComponent: Component {
|
|||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Reactions"), color: theme.contextMenu.primaryColor)
|
||||
}, additionalLeftIcon: { theme in
|
||||
if sortMode != .reactionsFirst {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, a in
|
||||
|
|
@ -1435,7 +1435,7 @@ public final class StoryItemSetViewListComponent: Component {
|
|||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Time"), color: theme.contextMenu.primaryColor)
|
||||
}, additionalLeftIcon: { theme in
|
||||
if sortMode != .recentFirst {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, a in
|
||||
|
|
|
|||
|
|
@ -167,6 +167,7 @@ public final class VideoPlaybackControlsComponent: Component {
|
|||
self.leftIconView.update(size: leftButtonFrame.size)
|
||||
transition.setAlpha(view: self.leftIconView, alpha: areSideButtonsVisible ? 1.0 : 0.0)
|
||||
transition.setBlur(layer: self.leftIconView.layer, radius: areSideButtonsVisible ? 0.0 : 10.0)
|
||||
self.leftButtonBackgroundView.isUserInteractionEnabled = areSideButtonsVisible
|
||||
|
||||
transition.setFrame(view: self.rightButtonBackgroundView, frame: rightButtonFrame)
|
||||
self.rightButtonBackgroundView.update(size: rightButtonFrame.size, cornerRadius: rightButtonFrame.height * 0.5, isDark: true, tintColor: buttonsTintColor, isInteractive: true, isVisible: areSideButtonsVisible, transition: transition)
|
||||
|
|
@ -174,6 +175,7 @@ public final class VideoPlaybackControlsComponent: Component {
|
|||
self.rightIconView.update(size: rightButtonFrame.size)
|
||||
transition.setAlpha(view: self.rightIconView, alpha: areSideButtonsVisible ? 1.0 : 0.0)
|
||||
transition.setBlur(layer: self.rightIconView.layer, radius: areSideButtonsVisible ? 0.0 : 10.0)
|
||||
self.rightButtonBackgroundView.isUserInteractionEnabled = areSideButtonsVisible
|
||||
|
||||
transition.setFrame(view: self.centerButtonBackgroundView, frame: centerButtonFrame)
|
||||
self.centerButtonBackgroundView.update(size: centerButtonFrame.size, cornerRadius: centerButtonFrame.height * 0.5, isDark: true, tintColor: buttonsTintColor, isInteractive: true, isVisible: component.isVisible, transition: transition)
|
||||
|
|
|
|||
|
|
@ -379,6 +379,9 @@ extension ChatControllerImpl {
|
|||
if previousState.chatTitleContent != contentData.state.chatTitleContent {
|
||||
animated = true
|
||||
}
|
||||
if previousState.slowmodeState != contentData.state.slowmodeState || previousState.boostsToUnrestrict != contentData.state.boostsToUnrestrict {
|
||||
animated = true
|
||||
}
|
||||
|
||||
var transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.4, curve: .spring) : .immediate
|
||||
if let forceAnimationTransition {
|
||||
|
|
|
|||
|
|
@ -743,6 +743,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
if !self.presentationData.theme.overallDarkAppearance {
|
||||
preferredGlassType = .default
|
||||
}
|
||||
if self.context.sharedContext.immediateExperimentalUISettings.forceClearGlass {
|
||||
preferredGlassType = .clear
|
||||
}
|
||||
if self.presentationInterfaceState.preferredGlassType != preferredGlassType {
|
||||
self.updateChatPresentationInterfaceState(transition: .immediate, interactive: false, { state in
|
||||
return state.updatedPreferredGlassType(preferredGlassType)
|
||||
|
|
@ -6411,6 +6414,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
if !self.presentationData.theme.overallDarkAppearance {
|
||||
preferredGlassType = .default
|
||||
}
|
||||
if self.context.sharedContext.immediateExperimentalUISettings.forceClearGlass {
|
||||
preferredGlassType = .clear
|
||||
}
|
||||
self.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in
|
||||
var state = state
|
||||
state = state.updatedPresentationReady(self.didSetPresentationData)
|
||||
|
|
|
|||
|
|
@ -2324,8 +2324,12 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
}
|
||||
|
||||
var keyboardButtonsMessage = view.topTaggedMessages.first
|
||||
if keyboardButtonsMessage != nil && keyboardButtonsMessage?.threadId != chatLocation.threadId {
|
||||
keyboardButtonsMessage = nil
|
||||
if let keyboardButtonsMessageValue = keyboardButtonsMessage {
|
||||
if keyboardButtonsMessageValue.threadId != chatLocation.threadId {
|
||||
if chatLocation.threadId != nil {
|
||||
keyboardButtonsMessage = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if let keyboardButtonsMessageValue = keyboardButtonsMessage, keyboardButtonsMessageValue.isRestricted(platform: "ios", contentSettings: context.currentContentSettings.with({ $0 })) {
|
||||
keyboardButtonsMessage = nil
|
||||
|
|
@ -3903,7 +3907,9 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
loadState = .messages
|
||||
} else if let historyView = strongSelf.historyView {
|
||||
if historyView.filteredEntries.isEmpty {
|
||||
if let firstEntry = historyView.originalView.entries.first {
|
||||
if historyView.originalView.isLoading {
|
||||
loadState = .loading(false)
|
||||
} else if let firstEntry = historyView.originalView.entries.first {
|
||||
var emptyType = ChatHistoryNodeLoadState.EmptyType.generic
|
||||
for media in firstEntry.message.media {
|
||||
if let action = media as? TelegramMediaAction {
|
||||
|
|
|
|||
|
|
@ -1185,7 +1185,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
|||
if currentValue == 0 {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}, action: { _, f in
|
||||
applyValue(0)
|
||||
|
|
@ -1208,7 +1208,7 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
|||
if currentValue == value {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}, action: { _, f in
|
||||
applyValue(value)
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ final class NotificationItemContainerNode: ASDisplayNode {
|
|||
if let contentNode = self.contentNode {
|
||||
let inset: CGFloat = 8.0
|
||||
|
||||
var contentInsets = UIEdgeInsets(top: inset, left: inset + layout.safeInsets.left, bottom: inset, right: inset + layout.safeInsets.right)
|
||||
var contentInsets = UIEdgeInsets(top: inset + layout.safeInsets.left, left: inset, bottom: inset, right: inset + layout.safeInsets.right)
|
||||
|
||||
if let statusBarHeight = layout.statusBarHeight, statusBarHeight >= 39.0 {
|
||||
if layout.deviceMetrics.hasDynamicIsland {
|
||||
|
|
@ -109,7 +109,7 @@ final class NotificationItemContainerNode: ASDisplayNode {
|
|||
}
|
||||
}
|
||||
|
||||
let containerWidth = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: layout.safeInsets.left)
|
||||
let containerWidth = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: 0.0)
|
||||
|
||||
let contentWidth = containerWidth - contentInsets.left - contentInsets.right
|
||||
let contentHeight = contentNode.updateLayout(width: contentWidth, transition: transition)
|
||||
|
|
|
|||
|
|
@ -1310,7 +1310,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
|||
if isSelected && value == nil {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
} else {
|
||||
return nil
|
||||
return UIImage()
|
||||
}
|
||||
}), action: { [weak self] _, f in
|
||||
scheduleTooltip(nil)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
|||
public var allForumsHaveTabs: Bool
|
||||
public var debugRatingLayout: Bool
|
||||
public var enableUpdates: Bool
|
||||
public var enablePWA: Bool
|
||||
public var forceClearGlass: Bool
|
||||
|
||||
public static var defaultSettings: ExperimentalUISettings {
|
||||
return ExperimentalUISettings(
|
||||
|
|
@ -115,7 +117,9 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
|||
checkSerializedData: false,
|
||||
allForumsHaveTabs: false,
|
||||
debugRatingLayout: false,
|
||||
enableUpdates: false
|
||||
enableUpdates: false,
|
||||
enablePWA: false,
|
||||
forceClearGlass: false
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -163,7 +167,9 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
|||
checkSerializedData: Bool,
|
||||
allForumsHaveTabs: Bool,
|
||||
debugRatingLayout: Bool,
|
||||
enableUpdates: Bool
|
||||
enableUpdates: Bool,
|
||||
enablePWA: Bool,
|
||||
forceClearGlass: Bool
|
||||
) {
|
||||
self.keepChatNavigationStack = keepChatNavigationStack
|
||||
self.skipReadHistory = skipReadHistory
|
||||
|
|
@ -209,6 +215,8 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
|||
self.allForumsHaveTabs = allForumsHaveTabs
|
||||
self.debugRatingLayout = debugRatingLayout
|
||||
self.enableUpdates = enableUpdates
|
||||
self.enablePWA = enablePWA
|
||||
self.forceClearGlass = forceClearGlass
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
|
|
@ -258,6 +266,8 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
|||
self.allForumsHaveTabs = try container.decodeIfPresent(Bool.self, forKey: "allForumsHaveTabs") ?? false
|
||||
self.debugRatingLayout = try container.decodeIfPresent(Bool.self, forKey: "debugRatingLayout") ?? false
|
||||
self.enableUpdates = try container.decodeIfPresent(Bool.self, forKey: "enableUpdates") ?? false
|
||||
self.enablePWA = try container.decodeIfPresent(Bool.self, forKey: "enablePWA") ?? false
|
||||
self.forceClearGlass = try container.decodeIfPresent(Bool.self, forKey: "forceClearGlass") ?? false
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
|
|
@ -307,6 +317,8 @@ public struct ExperimentalUISettings: Codable, Equatable {
|
|||
try container.encodeIfPresent(self.allForumsHaveTabs, forKey: "allForumsHaveTabs")
|
||||
try container.encodeIfPresent(self.debugRatingLayout, forKey: "debugRatingLayout")
|
||||
try container.encodeIfPresent(self.enableUpdates, forKey: "enableUpdates")
|
||||
try container.encodeIfPresent(self.enablePWA, forKey: "enablePWA")
|
||||
try container.encodeIfPresent(self.forceClearGlass, forKey: "forceClearGlass")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -408,8 +408,8 @@ public final class PeerChannelMemberCategoriesContextsManager {
|
|||
}
|
||||
}
|
||||
|
||||
public func transferOwnership(engine: TelegramEngine, peerId: PeerId, memberId: PeerId, password: String) -> Signal<Void, ChannelOwnershipTransferError> {
|
||||
return engine.peers.updateChannelOwnership(channelId: peerId, memberId: memberId, password: password)
|
||||
public func transferOwnership(engine: TelegramEngine, peerId: PeerId, memberId: PeerId, password: String) -> Signal<Void, ChatOwnershipTransferError> {
|
||||
return engine.peers.updateChatOwnership(peerId: peerId, memberId: memberId, password: password)
|
||||
|> map(Optional.init)
|
||||
|> deliverOnMainQueue
|
||||
|> beforeNext { [weak self] results in
|
||||
|
|
@ -423,7 +423,7 @@ public final class PeerChannelMemberCategoriesContextsManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, ChannelOwnershipTransferError> in
|
||||
|> mapToSignal { _ -> Signal<Void, ChatOwnershipTransferError> in
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,13 @@ objc_library(
|
|||
"Source",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/ObjCRuntimeUtils:ObjCRuntimeUtils",
|
||||
"//submodules/AsyncDisplayKit",
|
||||
"//submodules/ObjCRuntimeUtils",
|
||||
],
|
||||
sdk_frameworks = [
|
||||
"Foundation",
|
||||
"UIKit",
|
||||
"WebKit",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, UIResponderDisableAutomaticKeyboardHandling) {
|
||||
UIResponderDisableAutomaticKeyboardHandlingForward = 1 << 0,
|
||||
|
|
@ -104,3 +105,10 @@ void snapshotViewByDrawingInContext(UIView * _Nonnull view);
|
|||
@property (nonatomic) double lumaMax;
|
||||
|
||||
@end
|
||||
|
||||
@interface WebHelpers : NSObject
|
||||
|
||||
+ (dispatch_block_t _Nonnull)addTrustedDomain:(NSString * _Nonnull)domain;
|
||||
+ (void)forceRefreshTrustedDomains:(WKWebsiteDataStore * _Nonnull)websiteDataStore;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#import "NSWeakReference.h"
|
||||
#import <UIKitRuntimeUtils/UIKitUtils.h>
|
||||
#import <dlfcn.h>
|
||||
|
||||
@interface UIViewControllerPresentingProxy : UIViewController
|
||||
|
||||
|
|
@ -405,6 +406,131 @@ static void registerEffectViewOverrides(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static NSLock *webHelpersLock() {
|
||||
static NSLock *value = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
value = [[NSLock alloc] init];
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
@interface TrustedWebRecord : NSObject
|
||||
|
||||
@property (nonatomic) NSInteger nextReference;
|
||||
@property (nonatomic, strong, readonly) NSMutableSet<NSNumber *> *references;
|
||||
|
||||
@end
|
||||
|
||||
@implementation TrustedWebRecord
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_references = [[NSMutableSet alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSInteger)addReference {
|
||||
NSInteger reference = _nextReference;
|
||||
_nextReference += 1;
|
||||
[_references addObject:@(reference)];
|
||||
return reference;
|
||||
}
|
||||
|
||||
- (void)removeReference:(NSInteger)reference {
|
||||
[_references removeObject:@(reference)];
|
||||
}
|
||||
|
||||
- (bool)isEmpty {
|
||||
return _references.count == 0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static NSMutableDictionary<NSString *, TrustedWebRecord *> *trustedWebRecords() {
|
||||
static NSMutableDictionary *value = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
value = [[NSMutableDictionary alloc] init];
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
@implementation WebHelpers
|
||||
|
||||
+ (NSArray<NSString *> * _Nonnull)threadSafeTrustedDomains {
|
||||
[webHelpersLock() lock];
|
||||
|
||||
NSMutableArray<NSString *> *result = [[NSMutableArray alloc] init];
|
||||
for (NSString *domain in trustedWebRecords()) {
|
||||
[result addObject:domain];
|
||||
}
|
||||
[result sortUsingSelector:@selector(compare:)];
|
||||
|
||||
[webHelpersLock() unlock];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (dispatch_block_t _Nonnull)addTrustedDomain:(NSString * _Nonnull)domain {
|
||||
[webHelpersLock() lock];
|
||||
|
||||
TrustedWebRecord *record = trustedWebRecords()[domain];
|
||||
if (record == nil) {
|
||||
record = [[TrustedWebRecord alloc] init];
|
||||
trustedWebRecords()[domain] = record;
|
||||
}
|
||||
NSInteger reference = [record addReference];
|
||||
__block __weak TrustedWebRecord *weakRecord = record;
|
||||
|
||||
[webHelpersLock() unlock];
|
||||
|
||||
return ^{
|
||||
[webHelpersLock() lock];
|
||||
|
||||
TrustedWebRecord *strongRecord = weakRecord;
|
||||
if (strongRecord && trustedWebRecords()[domain] == strongRecord) {
|
||||
[strongRecord removeReference:reference];
|
||||
if ([strongRecord isEmpty]) {
|
||||
[trustedWebRecords() removeObjectForKey:domain];
|
||||
}
|
||||
}
|
||||
|
||||
[webHelpersLock() unlock];
|
||||
};
|
||||
}
|
||||
|
||||
+ (void)forceRefreshTrustedDomains:(WKWebsiteDataStore * _Nonnull)websiteDataStore {
|
||||
static void (*reinitializeFunction)(CFTypeRef dataStoreRef) = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSString *nameString = [NSString stringWithFormat:@"WK%@", @"WebsiteDataStoreReinitializeAppBoundDomains"];
|
||||
reinitializeFunction = dlsym(RTLD_DEFAULT, [nameString UTF8String]);
|
||||
});
|
||||
|
||||
if (reinitializeFunction) {
|
||||
reinitializeFunction((__bridge CFTypeRef)(websiteDataStore));
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSBundle (Telegram)
|
||||
|
||||
- (id)_65087dc8_objectForInfoDictionaryKey:(NSString *)key {
|
||||
if ([key isEqualToString:@"WKAppBoundDomains"]) {
|
||||
NSArray *result = [WebHelpers threadSafeTrustedDomains];
|
||||
if (result.count != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return [self _65087dc8_objectForInfoDictionaryKey:key];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIViewController (Navigation)
|
||||
|
||||
+ (void)load
|
||||
|
|
@ -432,6 +558,8 @@ static void registerEffectViewOverrides(void) {
|
|||
|
||||
[RuntimeUtils swizzleInstanceMethodOfClass:[UIFocusSystem class] currentSelector:@selector(updateFocusIfNeeded) newSelector:@selector(_65087dc8_updateFocusIfNeeded)];
|
||||
|
||||
[RuntimeUtils swizzleInstanceMethodOfClass:[NSBundle class] currentSelector:@selector(objectForInfoDictionaryKey:) newSelector:@selector(_65087dc8_objectForInfoDictionaryKey:)];
|
||||
|
||||
if (@available(iOS 26.0, *)) {
|
||||
registerEffectViewOverrides();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,12 +162,8 @@ final class WebAppWebView: WKWebView {
|
|||
|
||||
self.isOpaque = false
|
||||
self.backgroundColor = .clear
|
||||
if #available(iOS 9.0, *) {
|
||||
self.allowsLinkPreview = false
|
||||
}
|
||||
if #available(iOS 11.0, *) {
|
||||
self.scrollView.contentInsetAdjustmentBehavior = .never
|
||||
}
|
||||
self.allowsLinkPreview = false
|
||||
self.scrollView.contentInsetAdjustmentBehavior = .never
|
||||
self.interactiveTransitionGestureRecognizerTest = { point -> Bool in
|
||||
return point.x > 30.0
|
||||
}
|
||||
|
|
|
|||
1
third-party/libyuv/BUILD
vendored
1
third-party/libyuv/BUILD
vendored
|
|
@ -25,6 +25,7 @@ arch_specific_cflags = select({
|
|||
"@build_bazel_rules_apple//apple:ios_arm64": common_flags + arm64_specific_flags,
|
||||
"//build-system:ios_sim_arm64": common_flags + arm64_specific_flags,
|
||||
"@build_bazel_rules_apple//apple:ios_x86_64": common_flags + x86_64_specific_flags,
|
||||
"//conditions:default": common_flags,
|
||||
})
|
||||
|
||||
cc_library(
|
||||
|
|
|
|||
18
third-party/opus/BUILD
vendored
18
third-party/opus/BUILD
vendored
|
|
@ -29,6 +29,10 @@ genrule(
|
|||
BUILD_ARCH="sim_arm64"
|
||||
elif [ "$(TARGET_CPU)" == "ios_x86_64" ]; then
|
||||
BUILD_ARCH="x86_64"
|
||||
elif [ "$(TARGET_CPU)" == "k8" ] || [ "$(TARGET_CPU)" == "x86_64" ]; then
|
||||
BUILD_ARCH="linux_x86_64"
|
||||
elif [ "$(TARGET_CPU)" == "aarch64" ] || [ "$(TARGET_CPU)" == "arm64" ]; then
|
||||
BUILD_ARCH="linux_arm64"
|
||||
else
|
||||
echo "Unsupported architecture $(TARGET_CPU)"
|
||||
fi
|
||||
|
|
@ -63,6 +67,20 @@ cc_library(
|
|||
srcs = [":Public/opus/lib/lib" + x + ".a" for x in libs],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "opus_cc",
|
||||
hdrs = [":Public/opus/" + x for x in headers],
|
||||
includes = [
|
||||
"Public",
|
||||
],
|
||||
deps = [
|
||||
":opus_lib",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
||||
objc_library(
|
||||
name = "opus",
|
||||
module_name = "opus",
|
||||
|
|
|
|||
24
third-party/opus/build-opus-bazel.sh
vendored
24
third-party/opus/build-opus-bazel.sh
vendored
|
|
@ -12,8 +12,6 @@ OPT_CFLAGS="-Os -g"
|
|||
OPT_LDFLAGS=""
|
||||
OPT_CONFIG_ARGS=""
|
||||
|
||||
DEVELOPER=`xcode-select -print-path`
|
||||
|
||||
OUTPUTDIR="$BUILD_DIR/Public"
|
||||
|
||||
# where we will keep our sources and build from.
|
||||
|
|
@ -28,7 +26,27 @@ mkdir -p $INTERDIR
|
|||
tar zxf "$BUILD_DIR/$SOURCE_CODE_ARCHIVE" -C $SRCDIR
|
||||
cd "${SRCDIR}/opus-"*
|
||||
|
||||
if [ "${ARCH}" == "x86_64" ]; then
|
||||
if [ "${ARCH}" = "linux_x86_64" ] || [ "${ARCH}" = "linux_arm64" ]; then
|
||||
mkdir -p "${INTERDIR}"
|
||||
|
||||
# Keep it simple and portable for container builds.
|
||||
./configure \
|
||||
--disable-shared \
|
||||
--enable-static \
|
||||
--with-pic \
|
||||
--disable-extra-programs \
|
||||
--disable-doc \
|
||||
--disable-asm \
|
||||
--enable-intrinsics \
|
||||
${OPT_CONFIG_ARGS} \
|
||||
--prefix="${INTERDIR}" \
|
||||
CFLAGS="$CFLAGS ${OPT_CFLAGS} -fPIC" \
|
||||
LDFLAGS="$LDFLAGS ${OPT_LDFLAGS}"
|
||||
|
||||
make -j"$(getconf _NPROCESSORS_ONLN || echo 4)"
|
||||
make install
|
||||
exit 0
|
||||
elif [ "${ARCH}" == "x86_64" ]; then
|
||||
PLATFORM="iphonesimulator"
|
||||
EXTRA_CFLAGS="-arch ${ARCH}"
|
||||
EXTRA_CONFIG="--host=x86_64-apple-darwin"
|
||||
|
|
|
|||
8
third-party/webrtc/absl/BUILD
vendored
8
third-party/webrtc/absl/BUILD
vendored
|
|
@ -355,9 +355,15 @@ absl_sources = [
|
|||
"absl/types/bad_variant_access.cc",
|
||||
]
|
||||
|
||||
absl_inc_files = [
|
||||
f
|
||||
for f in glob(["absl/**/*.inc"])
|
||||
if f not in absl_headers
|
||||
]
|
||||
|
||||
cc_library(
|
||||
name = "absl",
|
||||
hdrs = absl_headers,
|
||||
hdrs = absl_headers + absl_inc_files,
|
||||
srcs = absl_sources,
|
||||
cxxopts = [
|
||||
"-std=c++17",
|
||||
|
|
|
|||
1
third-party/webrtc/crc32c/BUILD
vendored
1
third-party/webrtc/crc32c/BUILD
vendored
|
|
@ -6,6 +6,7 @@ arch_specific_crc32c_sources = select({
|
|||
"//build-system:ios_sim_arm64": [
|
||||
"third_party/crc32c/src/crc32c_arm64.cc",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
})
|
||||
|
||||
crc32c_sources = ["third_party/crc32c/src/" + x for x in [
|
||||
|
|
|
|||
1
third-party/webrtc/libsrtp/BUILD
vendored
1
third-party/webrtc/libsrtp/BUILD
vendored
|
|
@ -37,6 +37,7 @@ arm64_specific_flags = [
|
|||
arch_specific_cflags = select({
|
||||
"@build_bazel_rules_apple//apple:ios_arm64": common_flags + arm64_specific_flags,
|
||||
"//build-system:ios_sim_arm64": common_flags + arm64_specific_flags,
|
||||
"//conditions:default": [],
|
||||
})
|
||||
|
||||
optimization_flags = select({
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"app": "12.4",
|
||||
"app": "12.4.1",
|
||||
"xcode": "26.2",
|
||||
"bazel": "8.4.2:45e9388abf21d1107e146ea366ad080eb93cb6a5f3a4a3b048f78de0bc3faffa",
|
||||
"macos": "26"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue