mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-03 05:03:45 +00:00
Merge branch 'beta' of gitlab.com:peter-iakovlev/telegram-ios into beta
This commit is contained in:
commit
e1ddf060f0
9
BUCK
9
BUCK
@ -432,6 +432,14 @@ apple_resource(
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
apple_resource(
|
||||
name = "WatchAppExtensionResources",
|
||||
files = glob([
|
||||
"Watch/Extension/Resources/**/*",
|
||||
], exclude = ["Watch/Extension/Resources/**/.*"]),
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
apple_binary(
|
||||
name = "WatchAppExtensionBinary",
|
||||
srcs = glob([
|
||||
@ -467,6 +475,7 @@ apple_binary(
|
||||
],
|
||||
deps = [
|
||||
":WatchAppStringResources",
|
||||
":WatchAppExtensionResources",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@ -111,7 +111,7 @@ static void reportMemory() {
|
||||
|
||||
- (void)completeWithBestAttemptContent {
|
||||
_contentReady = true;
|
||||
//_updatedUnreadCount = @(-1);
|
||||
_updatedUnreadCount = @(-1);
|
||||
if (_contentReady && _updatedUnreadCount) {
|
||||
[self _internalComplete];
|
||||
}
|
||||
@ -229,7 +229,7 @@ static void reportMemory() {
|
||||
NSData *attachmentData = nil;
|
||||
id parsedAttachment = nil;
|
||||
|
||||
if (_isLockedValue) {
|
||||
if (!_isLockedValue) {
|
||||
NSString *attachmentDataString = decryptedPayload[@"attachb64"];
|
||||
if ([attachmentDataString isKindOfClass:[NSString class]]) {
|
||||
attachmentData = parseBase64(attachmentDataString);
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.intents-service</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).IntentHandler</string>
|
||||
<string>IntentHandler</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@ -50,7 +50,8 @@ enum IntentHandlingError {
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 10.0, *)
|
||||
class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessagesIntentHandling, INSetMessageAttributeIntentHandling, INStartAudioCallIntentHandling, INSearchCallHistoryIntentHandling {
|
||||
@objc(IntentHandler)
|
||||
public class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessagesIntentHandling, INSetMessageAttributeIntentHandling, INStartAudioCallIntentHandling, INSearchCallHistoryIntentHandling {
|
||||
private let accountPromise = Promise<Account?>()
|
||||
|
||||
private let resolvePersonsDisposable = MetaDisposable()
|
||||
@ -133,7 +134,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
self.actionDisposable.dispose()
|
||||
}
|
||||
|
||||
override func handler(for intent: INIntent) -> Any {
|
||||
override public func handler(for intent: INIntent) -> Any {
|
||||
return self
|
||||
}
|
||||
|
||||
@ -264,7 +265,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|
||||
// MARK: - INSendMessageIntentHandling
|
||||
|
||||
func resolveRecipients(for intent: INSendMessageIntent, with completion: @escaping ([INPersonResolutionResult]) -> Void) {
|
||||
public func resolveRecipients(for intent: INSendMessageIntent, with completion: @escaping ([INPersonResolutionResult]) -> Void) {
|
||||
guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
|
||||
completion([INPersonResolutionResult.notRequired()])
|
||||
return
|
||||
@ -275,7 +276,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 11.0, *)
|
||||
func resolveRecipients(for intent: INSendMessageIntent, with completion: @escaping ([INSendMessageRecipientResolutionResult]) -> Void) {
|
||||
public func resolveRecipients(for intent: INSendMessageIntent, with completion: @escaping ([INSendMessageRecipientResolutionResult]) -> Void) {
|
||||
if let peerId = intent.conversationIdentifier.flatMap(Int64.init) {
|
||||
let account = self.accountPromise.get()
|
||||
|
||||
@ -318,7 +319,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
}
|
||||
}
|
||||
|
||||
func resolveContent(for intent: INSendMessageIntent, with completion: @escaping (INStringResolutionResult) -> Void) {
|
||||
public func resolveContent(for intent: INSendMessageIntent, with completion: @escaping (INStringResolutionResult) -> Void) {
|
||||
guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
|
||||
completion(INStringResolutionResult.notRequired())
|
||||
return
|
||||
@ -330,7 +331,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
}
|
||||
}
|
||||
|
||||
func confirm(intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) {
|
||||
public func confirm(intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) {
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
|
||||
guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
|
||||
let response = INSendMessageIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
@ -341,7 +342,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
completion(response)
|
||||
}
|
||||
|
||||
func handle(intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) {
|
||||
public func handle(intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) {
|
||||
self.actionDisposable.set((self.accountPromise.get()
|
||||
|> castError(IntentHandlingError.self)
|
||||
|> take(1)
|
||||
@ -387,11 +388,11 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|
||||
// MARK: - INSearchForMessagesIntentHandling
|
||||
|
||||
func resolveAttributes(for intent: INSearchForMessagesIntent, with completion: @escaping (INMessageAttributeOptionsResolutionResult) -> Void) {
|
||||
public func resolveAttributes(for intent: INSearchForMessagesIntent, with completion: @escaping (INMessageAttributeOptionsResolutionResult) -> Void) {
|
||||
completion(.success(with: .unread))
|
||||
}
|
||||
|
||||
func handle(intent: INSearchForMessagesIntent, completion: @escaping (INSearchForMessagesIntentResponse) -> Void) {
|
||||
public func handle(intent: INSearchForMessagesIntent, completion: @escaping (INSearchForMessagesIntentResponse) -> Void) {
|
||||
self.actionDisposable.set((self.accountPromise.get()
|
||||
|> take(1)
|
||||
|> castError(IntentHandlingError.self)
|
||||
@ -439,7 +440,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|
||||
// MARK: - INSetMessageAttributeIntentHandling
|
||||
|
||||
func resolveAttribute(for intent: INSetMessageAttributeIntent, with completion: @escaping (INMessageAttributeResolutionResult) -> Void) {
|
||||
public func resolveAttribute(for intent: INSetMessageAttributeIntent, with completion: @escaping (INMessageAttributeResolutionResult) -> Void) {
|
||||
let supportedAttributes: [INMessageAttribute] = [.read, .unread]
|
||||
var attribute = intent.attribute
|
||||
if attribute == .flagged {
|
||||
@ -452,7 +453,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
}
|
||||
}
|
||||
|
||||
func handle(intent: INSetMessageAttributeIntent, completion: @escaping (INSetMessageAttributeIntentResponse) -> Void) {
|
||||
public func handle(intent: INSetMessageAttributeIntent, completion: @escaping (INSetMessageAttributeIntentResponse) -> Void) {
|
||||
self.actionDisposable.set((self.accountPromise.get()
|
||||
|> castError(IntentHandlingError.self)
|
||||
|> take(1)
|
||||
@ -511,7 +512,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|
||||
// MARK: - INStartAudioCallIntentHandling
|
||||
|
||||
func resolveContacts(for intent: INStartAudioCallIntent, with completion: @escaping ([INPersonResolutionResult]) -> Void) {
|
||||
public func resolveContacts(for intent: INStartAudioCallIntent, with completion: @escaping ([INPersonResolutionResult]) -> Void) {
|
||||
guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
|
||||
completion([INPersonResolutionResult.notRequired()])
|
||||
return
|
||||
@ -522,11 +523,11 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 11.0, *)
|
||||
func resolveDestinationType(for intent: INStartAudioCallIntent, with completion: @escaping (INCallDestinationTypeResolutionResult) -> Void) {
|
||||
public func resolveDestinationType(for intent: INStartAudioCallIntent, with completion: @escaping (INCallDestinationTypeResolutionResult) -> Void) {
|
||||
completion(.success(with: .normal))
|
||||
}
|
||||
|
||||
func handle(intent: INStartAudioCallIntent, completion: @escaping (INStartAudioCallIntentResponse) -> Void) {
|
||||
public func handle(intent: INStartAudioCallIntent, completion: @escaping (INStartAudioCallIntentResponse) -> Void) {
|
||||
self.actionDisposable.set((self.accountPromise.get()
|
||||
|> castError(IntentHandlingError.self)
|
||||
|> take(1)
|
||||
@ -561,15 +562,15 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
// MARK: - INSearchCallHistoryIntentHandling
|
||||
|
||||
@available(iOSApplicationExtension 11.0, *)
|
||||
func resolveCallTypes(for intent: INSearchCallHistoryIntent, with completion: @escaping (INCallRecordTypeOptionsResolutionResult) -> Void) {
|
||||
public func resolveCallTypes(for intent: INSearchCallHistoryIntent, with completion: @escaping (INCallRecordTypeOptionsResolutionResult) -> Void) {
|
||||
completion(.success(with: .missed))
|
||||
}
|
||||
|
||||
func resolveCallType(for intent: INSearchCallHistoryIntent, with completion: @escaping (INCallRecordTypeResolutionResult) -> Void) {
|
||||
public func resolveCallType(for intent: INSearchCallHistoryIntent, with completion: @escaping (INCallRecordTypeResolutionResult) -> Void) {
|
||||
completion(.success(with: .missed))
|
||||
}
|
||||
|
||||
func handle(intent: INSearchCallHistoryIntent, completion: @escaping (INSearchCallHistoryIntentResponse) -> Void) {
|
||||
public func handle(intent: INSearchCallHistoryIntent, completion: @escaping (INSearchCallHistoryIntentResponse) -> Void) {
|
||||
self.actionDisposable.set((self.accountPromise.get()
|
||||
|> take(1)
|
||||
|> castError(IntentHandlingError.self)
|
||||
|
||||
@ -33,5 +33,7 @@
|
||||
<string>merchant.privatbank.test.telergramios</string>
|
||||
<string>merchant.privatbank.prod.telergram</string>
|
||||
</array>
|
||||
<key>com.apple.developer.pushkit.unrestricted-voip</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@ -32,5 +32,7 @@
|
||||
<array>
|
||||
<string>X834Q8SBVP.org.telegram.Telegram-iOS</string>
|
||||
</array>
|
||||
<key>com.apple.developer.pushkit.unrestricted-voip</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@ -599,6 +599,8 @@
|
||||
"UserInfo.AddContact" = "Add Contact";
|
||||
"UserInfo.ShareContact" = "Share Contact";
|
||||
"UserInfo.StartSecretChat" = "Start Secret Chat";
|
||||
"UserInfo.StartSecretChatConfirmation" = "Are you sure you want to start a secret chat with %@?";
|
||||
"UserInfo.StartSecretChatStart" = "Start";
|
||||
"UserInfo.DeleteContact" = "Delete Contact";
|
||||
"UserInfo.CreateNewContact" = "Create New Contact";
|
||||
"UserInfo.AddToExisting" = "Add to Existing";
|
||||
@ -5082,6 +5084,23 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"ClearCache.StorageFree" = "Free";
|
||||
"ClearCache.ClearCache" = "Clear Telegram Cache";
|
||||
"ClearCache.Clear" = "Clear";
|
||||
"ClearCache.Forever" = "Forever";
|
||||
|
||||
"ChatList.DeletedChats_1" = "Deleted 1 chat";
|
||||
"ChatList.DeletedChats_any" = "Deleted %@ chats";
|
||||
|
||||
"Appearance.ColorThemeNight" = "COLOR THEME — AUTO-NIGHT MODE";
|
||||
|
||||
"UserInfo.StartSecretChatConfirmation" = "Are you sure you want to start a secret chat with\n%@?";
|
||||
"UserInfo.StartSecretChatStart" = "Start";
|
||||
|
||||
"Wallet.AccessDenied.Title" = "Please Allow Access";
|
||||
"Wallet.AccessDenied.Camera" = "TON Wallet needs access to your camera to take photos and videos.\n\nPlease go to Settings > Privacy > Camera and set TON Wallet to ON.";
|
||||
"Wallet.AccessDenied.Settings" = "Settings";
|
||||
|
||||
"GroupInfo.ShowMoreMembers_0" = "%@ more";
|
||||
"GroupInfo.ShowMoreMembers_1" = "%@ more";
|
||||
"GroupInfo.ShowMoreMembers_2" = "%@ more";
|
||||
"GroupInfo.ShowMoreMembers_3_10" = "%@ more";
|
||||
"GroupInfo.ShowMoreMembers_many" = "%@ more";
|
||||
"GroupInfo.ShowMoreMembers_any" = "%@ more";
|
||||
|
||||
@ -403,15 +403,16 @@ private final class WalletContextImpl: NSObject, WalletContext, UIImagePickerCon
|
||||
|
||||
func authorizeAccessToCamera(completion: @escaping () -> Void) {
|
||||
AVCaptureDevice.requestAccess(for: AVMediaType.video) { [weak self] response in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
Queue.mainQueue().async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
if response {
|
||||
completion()
|
||||
} else {
|
||||
let presentationData = strongSelf.presentationData
|
||||
let controller = standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.Wallet_AccessDenied_Title, text: presentationData.strings.Wallet_AccessDenied_Camera, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Wallet_Intro_NotNow, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Wallet_AccessDenied_Settings, action: {
|
||||
let controller = standardTextAlertController(theme: presentationData.theme.alert, title: presentationData.strings.Wallet_AccessDenied_Title, text: presentationData.strings.Wallet_AccessDenied_Camera, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Wallet_Intro_NotNow, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Wallet_AccessDenied_Settings, action: {
|
||||
strongSelf.openPlatformSettings()
|
||||
})])
|
||||
strongSelf.window.present(controller, on: .root)
|
||||
@ -705,33 +706,46 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
self.walletContext = walletContext
|
||||
|
||||
let beginWithController: (ViewController) -> Void = { controller in
|
||||
navigationController.setViewControllers([controller], animated: false)
|
||||
|
||||
var previousBlockchainName = initialConfigBlockchainName
|
||||
|
||||
let _ = (updatedConfigValue
|
||||
|> deliverOnMainQueue).start(next: { resolved, blockchainName in
|
||||
let _ = walletContext.tonInstance.validateConfig(config: resolved.value, blockchainName: blockchainName).start(error: { _ in
|
||||
}, completed: {
|
||||
let _ = walletContext.tonInstance.updateConfig(config: resolved.value, blockchainName: blockchainName).start()
|
||||
|
||||
if previousBlockchainName != blockchainName {
|
||||
previousBlockchainName = blockchainName
|
||||
let begin: (Bool) -> Void = { animated in
|
||||
navigationController.setViewControllers([controller], animated: false)
|
||||
if animated {
|
||||
navigationController.viewControllers.last?.view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
|
||||
var previousBlockchainName = initialConfigBlockchainName
|
||||
|
||||
let _ = (updatedConfigValue
|
||||
|> deliverOnMainQueue).start(next: { resolved, blockchainName in
|
||||
let _ = walletContext.tonInstance.validateConfig(config: resolved.value, blockchainName: blockchainName).start(error: { _ in
|
||||
}, completed: {
|
||||
let _ = walletContext.tonInstance.updateConfig(config: resolved.value, blockchainName: blockchainName).start()
|
||||
|
||||
let overlayController = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
||||
mainWindow.present(overlayController, on: .root)
|
||||
|
||||
let _ = (deleteAllLocalWalletsData(storage: walletContext.storage, tonInstance: walletContext.tonInstance)
|
||||
|> deliverOnMainQueue).start(error: { [weak overlayController] _ in
|
||||
overlayController?.dismiss()
|
||||
}, completed: { [weak overlayController] in
|
||||
overlayController?.dismiss()
|
||||
if previousBlockchainName != blockchainName {
|
||||
previousBlockchainName = blockchainName
|
||||
|
||||
navigationController.setViewControllers([WalletSplashScreen(context: walletContext, mode: .intro, walletCreatedPreloadState: nil)], animated: true)
|
||||
})
|
||||
}
|
||||
let overlayController = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
||||
mainWindow.present(overlayController, on: .root)
|
||||
|
||||
let _ = (deleteAllLocalWalletsData(storage: walletContext.storage, tonInstance: walletContext.tonInstance)
|
||||
|> deliverOnMainQueue).start(error: { [weak overlayController] _ in
|
||||
overlayController?.dismiss()
|
||||
}, completed: { [weak overlayController] in
|
||||
overlayController?.dismiss()
|
||||
|
||||
navigationController.setViewControllers([WalletSplashScreen(context: walletContext, mode: .intro, walletCreatedPreloadState: nil)], animated: true)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if let splashScreen = navigationController.viewControllers.first as? WalletApplicationSplashScreen, let _ = controller as? WalletSplashScreen {
|
||||
splashScreen.animateOut(completion: {
|
||||
begin(true)
|
||||
})
|
||||
} else {
|
||||
begin(false)
|
||||
}
|
||||
}
|
||||
|
||||
let _ = (combineLatest(queue: .mainQueue(),
|
||||
|
||||
@ -219,5 +219,5 @@
|
||||
"Wallet.VoiceOver.Editing.ClearText" = "Clear text";
|
||||
"Wallet.Receive.ShareInvoiceUrlInfo" = "Share this link with other Gram wallet owners to receive %@ Grams from them.";
|
||||
"Wallet.AccessDenied.Title" = "Please Allow Access";
|
||||
"Wallet.AccessDenied.Camera" = "TON Wallet needs access to camera to scan QR codes.\n\nPlease go to Settings > Privacy > Camera and set TON Wallet to ON.";
|
||||
"Wallet.AccessDenied.Camera" = "TON Wallet needs access to your camera to take photos and videos.\n\nPlease go to Settings > Privacy > Camera and set TON Wallet to ON.";
|
||||
"Wallet.AccessDenied.Settings" = "Settings";
|
||||
|
||||
@ -131,21 +131,14 @@
|
||||
|
||||
+ (SSignal *)_requestImageWithUrl:(NSString *)url subscription:(TGBridgeSubscription *)subscription
|
||||
{
|
||||
SSignal *remoteSignal = [[[[[TGBridgeClient instance] requestSignalWithSubscription:subscription] onStart:^
|
||||
{
|
||||
SSignal *remoteSignal = [[[[TGBridgeClient instance] requestSignalWithSubscription:subscription] onStart:^
|
||||
{
|
||||
if (![[self mediaManager] hasUrl:url])
|
||||
[[self mediaManager] addUrl:url];
|
||||
}] onDispose:^
|
||||
}] then:[[self _downloadedFileWithUrl:url] onNext:^(id next)
|
||||
{
|
||||
[[self mediaManager] removeUrl:url];
|
||||
}] mapToSignal:^SSignal *(id next)
|
||||
{
|
||||
return [[self _downloadedFileWithUrl:url] onNext:^(id next)
|
||||
{
|
||||
[[self mediaManager] removeUrl:url];
|
||||
}];
|
||||
}];
|
||||
|
||||
}]];
|
||||
return [[self _cachedOrPendingWithUrl:url] catch:^SSignal *(id error)
|
||||
{
|
||||
return remoteSignal;
|
||||
|
||||
@ -146,6 +146,7 @@ REMOVE_ENTITLEMENT_KEYS=(\
|
||||
COPY_ENTITLEMENT_KEYS=(\
|
||||
"com.apple.developer.associated-domains" \
|
||||
"com.apple.developer.icloud-services" \
|
||||
"com.apple.developer.pushkit.unrestricted-voip" \
|
||||
)
|
||||
|
||||
REPLACE_TO_PRODUCTION_ENTITLEMENT_KEYS=(\
|
||||
@ -217,9 +218,12 @@ for ITEM in $APP_ITEMS_WITH_PROVISIONING_PROFILE; do
|
||||
VALUE=$(/usr/libexec/PlistBuddy -c "Print :$KEY" "$PROFILE_ENTITLEMENTS_PATH" 2>/dev/null || echo "")
|
||||
if [ ! -z "$VALUE" ]; then
|
||||
PLUTIL_KEY=$(echo "$KEY" | sed 's/\./\\\./g')
|
||||
VALUE=$(plutil -extract "$PLUTIL_KEY" xml1 -o - "${!ENTITLEMENTS_VAR}")
|
||||
/usr/libexec/PlistBuddy -c "Delete $KEY" "$PROFILE_ENTITLEMENTS_PATH" 2>/dev/null
|
||||
plutil -insert "$PLUTIL_KEY" -xml "$VALUE" "$PROFILE_ENTITLEMENTS_PATH"
|
||||
TEST_VALUE=$(plutil -extract "$PLUTIL_KEY" xml1 -o - "${!ENTITLEMENTS_VAR}" 1>/dev/null || echo "error")
|
||||
if [ "$TEST_VALUE" != "error" ]; then
|
||||
VALUE=$(plutil -extract "$PLUTIL_KEY" xml1 -o - "${!ENTITLEMENTS_VAR}")
|
||||
/usr/libexec/PlistBuddy -c "Delete $KEY" "$PROFILE_ENTITLEMENTS_PATH" 2>/dev/null
|
||||
plutil -insert "$PLUTIL_KEY" -xml "$VALUE" "$PROFILE_ENTITLEMENTS_PATH"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
@ -30,9 +30,7 @@ public final class AnimationNode : ASDisplayNode {
|
||||
view.animationSpeed = self.speed
|
||||
view.backgroundColor = .clear
|
||||
view.isOpaque = false
|
||||
|
||||
view.logHierarchyKeypaths()
|
||||
|
||||
|
||||
if let colors = colors {
|
||||
for (key, value) in colors {
|
||||
let colorCallback = LOTColorValueCallback(color: value.cgColor)
|
||||
|
||||
23
submodules/AppIntents/BUCK
Normal file
23
submodules/AppIntents/BUCK
Normal file
@ -0,0 +1,23 @@
|
||||
load("//Config:buck_rule_macros.bzl", "static_library")
|
||||
|
||||
static_library(
|
||||
name = "AppIntents",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
deps = [
|
||||
"//submodules/TelegramCore:TelegramCore#shared",
|
||||
"//submodules/SyncCore:SyncCore#shared",
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared",
|
||||
"//submodules/Display:Display#shared",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/AvatarNode:AvatarNode",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
],
|
||||
weak_frameworks = [
|
||||
"Intents",
|
||||
],
|
||||
)
|
||||
22
submodules/AppIntents/Info.plist
Normal file
22
submodules/AppIntents/Info.plist
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
</dict>
|
||||
</plist>
|
||||
67
submodules/AppIntents/Sources/AppIntents.swift
Normal file
67
submodules/AppIntents/Sources/AppIntents.swift
Normal file
@ -0,0 +1,67 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Intents
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import AvatarNode
|
||||
import AccountContext
|
||||
|
||||
public func donateSendMessageIntent(account: Account, sharedContext: SharedAccountContext, peerIds: [PeerId]) {
|
||||
if #available(iOSApplicationExtension 13.2, iOS 13.2, *) {
|
||||
let _ = (account.postbox.transaction { transaction -> [Peer] in
|
||||
var peers: [Peer] = []
|
||||
for peerId in peerIds {
|
||||
if peerId.namespace == Namespaces.Peer.CloudUser && peerId != account.peerId, let peer = transaction.getPeer(peerId) {
|
||||
peers.append(peer)
|
||||
}
|
||||
}
|
||||
return peers
|
||||
}
|
||||
|> mapToSignal { peers -> Signal<[(Peer, UIImage?)], NoError> in
|
||||
var signals: [Signal<(Peer, UIImage?), NoError>] = []
|
||||
for peer in peers {
|
||||
let peerAndAvatar = (peerAvatarImage(account: account, peer: peer, authorOfMessage: nil, representation: peer.smallProfileImage, round: false) ?? .single(nil))
|
||||
|> map { avatarImage in
|
||||
return (peer, avatarImage)
|
||||
}
|
||||
signals.append(peerAndAvatar)
|
||||
}
|
||||
return combineLatest(signals)
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { peers in
|
||||
for (peer, avatarImage) in peers {
|
||||
guard let peer = peer as? TelegramUser, peer.botInfo == nil && !peer.flags.contains(.isSupport) else {
|
||||
continue
|
||||
}
|
||||
let presentationData = sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let recipientHandle = INPersonHandle(value: "tg\(peer.id.id)", type: .unknown)
|
||||
var nameComponents = PersonNameComponents()
|
||||
nameComponents.givenName = peer.firstName
|
||||
nameComponents.familyName = peer.lastName
|
||||
|
||||
let displayTitle = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
let recipient = INPerson(personHandle: recipientHandle, nameComponents: nameComponents, displayName: displayTitle, image: nil, contactIdentifier: nil, customIdentifier: "tg\(peer.id.id)")
|
||||
|
||||
let intent = INSendMessageIntent(recipients: [recipient], content: nil, speakableGroupName: INSpeakableString(spokenPhrase: displayTitle), conversationIdentifier: "tg\(peer.id.id)", serviceName: nil, sender: nil)
|
||||
if let avatarImage = avatarImage, let avatarImageData = avatarImage.jpegData(compressionQuality: 0.8) {
|
||||
intent.setImage(INImage(imageData: avatarImageData), forParameterNamed: \.groupName)
|
||||
}
|
||||
let interaction = INInteraction(intent: intent, response: nil)
|
||||
interaction.direction = .outgoing
|
||||
interaction.groupIdentifier = "sendMessage_\(account.peerId.toInt64())"
|
||||
interaction.donate()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public func deleteAllSendMessageIntents(accountPeerId: PeerId) {
|
||||
if #available(iOS 10.0, *) {
|
||||
INInteraction.delete(with: "sendMessage_\(accountPeerId.toInt64())")
|
||||
}
|
||||
}
|
||||
@ -237,7 +237,7 @@ using AS::MutexLocker;
|
||||
UIImage *image = nil;
|
||||
|
||||
if (shouldCreateGraphicsContext && !currentContext) {
|
||||
ASDisplayNodeAssert(NO, @"Failed to create a CGContext (size: %@)", NSStringFromCGSize(bounds.size));
|
||||
//ASDisplayNodeAssert(NO, @"Failed to create a CGContext (size: %@)", NSStringFromCGSize(bounds.size));
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ public enum DeviceMetrics: CaseIterable, Equatable {
|
||||
|
||||
let additionalSize = CGSize(width: screenSize.width, height: screenSize.height + 20.0)
|
||||
for device in DeviceMetrics.allCases {
|
||||
if let _ = onScreenNavigationHeight, device.onScreenNavigationHeight(inLandscape: false) == nil {
|
||||
if let _ = onScreenNavigationHeight, device.onScreenNavigationHeight(inLandscape: false, systemOnScreenNavigationHeight: nil) == nil {
|
||||
if case .tablet = device.type {
|
||||
if screenSize.height == 1024.0 && screenSize.width == 768.0 {
|
||||
} else {
|
||||
@ -111,16 +111,22 @@ public enum DeviceMetrics: CaseIterable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
func onScreenNavigationHeight(inLandscape: Bool) -> CGFloat? {
|
||||
func onScreenNavigationHeight(inLandscape: Bool, systemOnScreenNavigationHeight: CGFloat?) -> CGFloat? {
|
||||
switch self {
|
||||
case .iPhoneX, .iPhoneXSMax:
|
||||
return inLandscape ? 21.0 : 34.0
|
||||
case .iPadPro3rdGen, .iPadPro11Inch:
|
||||
case .iPhoneX, .iPhoneXSMax:
|
||||
return inLandscape ? 21.0 : 34.0
|
||||
case .iPadPro3rdGen, .iPadPro11Inch:
|
||||
return 21.0
|
||||
case .iPad, .iPadPro, .iPadPro10Inch:
|
||||
if let systemOnScreenNavigationHeight = systemOnScreenNavigationHeight, !systemOnScreenNavigationHeight.isZero {
|
||||
return 21.0
|
||||
case let .unknown(_, _, onScreenNavigationHeight):
|
||||
return onScreenNavigationHeight
|
||||
default:
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
case let .unknown(_, _, onScreenNavigationHeight):
|
||||
return onScreenNavigationHeight
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1766,7 +1766,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
}, node: {
|
||||
assert(Queue.mainQueue().isCurrent())
|
||||
return referenceNode.syncWith({ $0 })!
|
||||
}, params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right), previousItem: index == 0 ? nil : self.items[index - 1], nextItem: index == self.items.count - 1 ? nil : self.items[index + 1], animation: updateAnimation, completion: { layout, apply in
|
||||
}, params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right, availableHeight: state.visibleSize.height - state.insets.top - state.insets.bottom), previousItem: index == 0 ? nil : self.items[index - 1], nextItem: index == self.items.count - 1 ? nil : self.items[index + 1], animation: updateAnimation, completion: { layout, apply in
|
||||
var updatedState = state
|
||||
var updatedOperations = operations
|
||||
|
||||
@ -1841,7 +1841,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
let index = insertionItemIndexAndDirection.0
|
||||
let threadId = pthread_self()
|
||||
var tailRecurse = false
|
||||
self.nodeForItem(synchronous: synchronous, synchronousLoads: synchronousLoads, item: self.items[index], previousNode: previousNodes[index], index: index, previousItem: index == 0 ? nil : self.items[index - 1], nextItem: self.items.count == index + 1 ? nil : self.items[index + 1], params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right), updateAnimation: updateAnimation, completion: { (node, layout, apply) in
|
||||
self.nodeForItem(synchronous: synchronous, synchronousLoads: synchronousLoads, item: self.items[index], previousNode: previousNodes[index], index: index, previousItem: index == 0 ? nil : self.items[index - 1], nextItem: self.items.count == index + 1 ? nil : self.items[index + 1], params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right, availableHeight: state.visibleSize.height - state.insets.top - state.insets.bottom), updateAnimation: updateAnimation, completion: { (node, layout, apply) in
|
||||
|
||||
if pthread_equal(pthread_self(), threadId) != 0 && !tailRecurse {
|
||||
tailRecurse = true
|
||||
@ -1877,7 +1877,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
} else {
|
||||
let updateItem = updateIndicesAndItems[0]
|
||||
if let previousNode = previousNodes[updateItem.index] {
|
||||
self.nodeForItem(synchronous: synchronous, synchronousLoads: synchronousLoads, item: updateItem.item, previousNode: previousNode, index: updateItem.index, previousItem: updateItem.index == 0 ? nil : self.items[updateItem.index - 1], nextItem: updateItem.index == (self.items.count - 1) ? nil : self.items[updateItem.index + 1], params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right), updateAnimation: animated ? .System(duration: insertionAnimationDuration) : .None, completion: { _, layout, apply in
|
||||
self.nodeForItem(synchronous: synchronous, synchronousLoads: synchronousLoads, item: updateItem.item, previousNode: previousNode, index: updateItem.index, previousItem: updateItem.index == 0 ? nil : self.items[updateItem.index - 1], nextItem: updateItem.index == (self.items.count - 1) ? nil : self.items[updateItem.index + 1], params: ListViewItemLayoutParams(width: state.visibleSize.width, leftInset: state.insets.left, rightInset: state.insets.right, availableHeight: state.visibleSize.height - state.insets.top - state.insets.bottom), updateAnimation: animated ? .System(duration: insertionAnimationDuration) : .None, completion: { _, layout, apply in
|
||||
state.updateNodeAtItemIndex(updateItem.index, layout: layout, direction: updateItem.directionHint, animation: animated ? .System(duration: insertionAnimationDuration) : .None, apply: apply, operations: &operations)
|
||||
|
||||
updateIndicesAndItems.remove(at: 0)
|
||||
|
||||
@ -73,11 +73,13 @@ public struct ListViewItemLayoutParams {
|
||||
public let width: CGFloat
|
||||
public let leftInset: CGFloat
|
||||
public let rightInset: CGFloat
|
||||
public let availableHeight: CGFloat
|
||||
|
||||
public init(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat) {
|
||||
public init(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, availableHeight: CGFloat) {
|
||||
self.width = width
|
||||
self.leftInset = leftInset
|
||||
self.rightInset = rightInset
|
||||
self.availableHeight = availableHeight
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -747,15 +747,19 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
case .compact:
|
||||
if visibleModalCount != 0 {
|
||||
let effectiveRootModalDismissProgress: CGFloat
|
||||
let visibleRootModalDismissProgress: CGFloat
|
||||
let additionalModalFrameProgress: CGFloat
|
||||
if visibleModalCount == 1 {
|
||||
effectiveRootModalDismissProgress = topModalIsFlat ? 1.0 : topModalDismissProgress
|
||||
visibleRootModalDismissProgress = effectiveRootModalDismissProgress
|
||||
additionalModalFrameProgress = 0.0
|
||||
} else if visibleModalCount == 2 {
|
||||
effectiveRootModalDismissProgress = 0.0
|
||||
visibleRootModalDismissProgress = topModalDismissProgress
|
||||
additionalModalFrameProgress = 1.0 - topModalDismissProgress
|
||||
} else {
|
||||
effectiveRootModalDismissProgress = 0.0
|
||||
visibleRootModalDismissProgress = effectiveRootModalDismissProgress
|
||||
additionalModalFrameProgress = 1.0
|
||||
}
|
||||
|
||||
@ -820,8 +824,8 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
maxOffset = (topInset + 10.0 - (layout.size.height - layout.size.height * maxScale) / 2.0)
|
||||
}
|
||||
|
||||
let scale = 1.0 * effectiveRootModalDismissProgress + (1.0 - effectiveRootModalDismissProgress) * maxScale
|
||||
let offset = (1.0 - effectiveRootModalDismissProgress) * maxOffset
|
||||
let scale = 1.0 * visibleRootModalDismissProgress + (1.0 - visibleRootModalDismissProgress) * maxScale
|
||||
let offset = (1.0 - visibleRootModalDismissProgress) * maxOffset
|
||||
transition.updateSublayerTransformScaleAndOffset(node: rootContainerNode, scale: scale, offset: CGPoint(x: 0.0, y: offset))
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -467,6 +467,11 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
|
||||
}
|
||||
currentParent = currentParent?.superview
|
||||
}
|
||||
if let controller = self.container.controllers.last {
|
||||
if controller.view.disablesInteractiveModalDismiss {
|
||||
enableScrolling = false
|
||||
}
|
||||
}
|
||||
self.isInteractiveDimissEnabled = enableScrolling
|
||||
if let layout = self.validLayout {
|
||||
if layout.inputHeight != nil && layout.inputHeight != 0.0 {
|
||||
|
||||
@ -310,7 +310,7 @@ public class Window1 {
|
||||
|
||||
let isLandscape = boundsSize.width > boundsSize.height
|
||||
let safeInsets = self.deviceMetrics.safeInsets(inLandscape: isLandscape)
|
||||
let onScreenNavigationHeight = self.deviceMetrics.onScreenNavigationHeight(inLandscape: isLandscape)
|
||||
let onScreenNavigationHeight = self.deviceMetrics.onScreenNavigationHeight(inLandscape: isLandscape, systemOnScreenNavigationHeight: self.hostView.onScreenNavigationHeight)
|
||||
|
||||
self.windowLayout = WindowLayout(size: boundsSize, metrics: layoutMetricsForScreenSize(boundsSize), statusBarHeight: statusBarHeight, forceInCallStatusBarText: self.forceInCallStatusBarText, inputHeight: 0.0, safeInsets: safeInsets, onScreenNavigationHeight: onScreenNavigationHeight, upperKeyboardInputPositionBound: nil, inVoiceOver: UIAccessibility.isVoiceOverRunning)
|
||||
self.updatingLayout = UpdatingLayout(layout: self.windowLayout, transition: .immediate)
|
||||
@ -950,7 +950,7 @@ public class Window1 {
|
||||
statusBarHeight = max(statusBarHeightValue, statusBarHost.statusBarFrame.size.height)
|
||||
}
|
||||
|
||||
if self.deviceMetrics.type == .tablet, let onScreenNavigationHeight = self.hostView.onScreenNavigationHeight, onScreenNavigationHeight != self.deviceMetrics.onScreenNavigationHeight(inLandscape: false) {
|
||||
if self.deviceMetrics.type == .tablet, let onScreenNavigationHeight = self.hostView.onScreenNavigationHeight, onScreenNavigationHeight != self.deviceMetrics.onScreenNavigationHeight(inLandscape: false, systemOnScreenNavigationHeight: self.hostView.onScreenNavigationHeight) {
|
||||
self.deviceMetrics = DeviceMetrics(screenSize: UIScreen.main.bounds.size, statusBarHeight: statusBarHeight ?? defaultStatusBarHeight, onScreenNavigationHeight: onScreenNavigationHeight)
|
||||
}
|
||||
|
||||
@ -967,7 +967,7 @@ public class Window1 {
|
||||
}
|
||||
let previousInputOffset = inputHeightOffsetForLayout(self.windowLayout)
|
||||
|
||||
self.windowLayout = WindowLayout(size: updatingLayout.layout.size, metrics: layoutMetricsForScreenSize(updatingLayout.layout.size), statusBarHeight: statusBarHeight, forceInCallStatusBarText: updatingLayout.layout.forceInCallStatusBarText, inputHeight: updatingLayout.layout.inputHeight, safeInsets: updatingLayout.layout.safeInsets, onScreenNavigationHeight: self.deviceMetrics.onScreenNavigationHeight(inLandscape: isLandscape), upperKeyboardInputPositionBound: updatingLayout.layout.upperKeyboardInputPositionBound, inVoiceOver: updatingLayout.layout.inVoiceOver)
|
||||
self.windowLayout = WindowLayout(size: updatingLayout.layout.size, metrics: layoutMetricsForScreenSize(updatingLayout.layout.size), statusBarHeight: statusBarHeight, forceInCallStatusBarText: updatingLayout.layout.forceInCallStatusBarText, inputHeight: updatingLayout.layout.inputHeight, safeInsets: updatingLayout.layout.safeInsets, onScreenNavigationHeight: self.deviceMetrics.onScreenNavigationHeight(inLandscape: isLandscape, systemOnScreenNavigationHeight: self.hostView.onScreenNavigationHeight), upperKeyboardInputPositionBound: updatingLayout.layout.upperKeyboardInputPositionBound, inVoiceOver: updatingLayout.layout.inVoiceOver)
|
||||
|
||||
let childLayout = containedLayoutForWindowLayout(self.windowLayout, deviceMetrics: self.deviceMetrics)
|
||||
let childLayoutUpdated = self.updatedContainerLayout != childLayout
|
||||
|
||||
@ -851,7 +851,7 @@ const CGPoint TGLocationPickerPinOffset = { 0.0f, 33.0f };
|
||||
}];
|
||||
|
||||
CLLocationCoordinate2D coordinate = _currentUserLocation.coordinate;
|
||||
searchSignal = [self.nearbyPlacesSignal(searchQuery, _currentUserLocation) deliverOn:[SQueue mainQueue]];
|
||||
searchSignal = [searchSignal then:[self.nearbyPlacesSignal(searchQuery, _currentUserLocation) deliverOn:[SQueue mainQueue]]];
|
||||
|
||||
if (_searchDisposable == nil)
|
||||
_searchDisposable = [[SMetaDisposable alloc] init];
|
||||
|
||||
@ -1221,7 +1221,7 @@
|
||||
{
|
||||
[super scrollViewDidScroll:scrollView];
|
||||
|
||||
_mapView.compassInsets = UIEdgeInsetsMake(TGLocationMapInset + 108.0f + (scrollView.contentOffset.y + scrollView.contentInset.top) / 2.0f, 0.0f, 0.0f, 10.0f + TGScreenPixel);
|
||||
_mapView.compassInsets = UIEdgeInsetsMake(TGLocationMapInset + 120.0f + (scrollView.contentOffset.y + scrollView.contentInset.top) / 2.0f, 0.0f, 0.0f, 10.0f + TGScreenPixel);
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
|
||||
|
||||
@ -18,6 +18,12 @@ private final class LegacyImagePickerController: LegacyController, TGLegacyCamer
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
self.view.disablesInteractiveModalDismiss = true
|
||||
}
|
||||
|
||||
func legacyCameraControllerCompletedWithNoResult() {
|
||||
self.completion(nil)
|
||||
}
|
||||
|
||||
@ -700,7 +700,7 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.interaction.present(SecureIdPlaintextFormController(context: strongSelf.context, secureIdContext: secureIdContext, type: type, immediatelyAvailableValue: immediatelyAvailableValue, updatedValue: { valueWithContext in
|
||||
strongSelf.interaction.push(SecureIdPlaintextFormController(context: strongSelf.context, secureIdContext: secureIdContext, type: type, immediatelyAvailableValue: immediatelyAvailableValue, updatedValue: { valueWithContext in
|
||||
if let strongSelf = self {
|
||||
strongSelf.interaction.updateState { state in
|
||||
if case let .form(form) = state, let formData = form.formData {
|
||||
@ -723,7 +723,7 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode {
|
||||
return state
|
||||
}
|
||||
}
|
||||
}), nil)
|
||||
}))
|
||||
}
|
||||
|
||||
if let currentValue = currentValue {
|
||||
@ -941,9 +941,9 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode {
|
||||
if let peer = list.accountPeer as? TelegramUser, let phone = peer.phone, !phone.isEmpty {
|
||||
immediatelyAvailableValue = .phone(SecureIdPhoneValue(phone: phone))
|
||||
}
|
||||
self.interaction.present(SecureIdPlaintextFormController(context: self.context, secureIdContext: secureIdContext, type: .phone, immediatelyAvailableValue: immediatelyAvailableValue, updatedValue: { value in
|
||||
self.interaction.push(SecureIdPlaintextFormController(context: self.context, secureIdContext: secureIdContext, type: .phone, immediatelyAvailableValue: immediatelyAvailableValue, updatedValue: { value in
|
||||
updatedValues(.phone)(value.flatMap({ [$0] }) ?? [])
|
||||
}), nil)
|
||||
}))
|
||||
}
|
||||
case .email:
|
||||
if findValue(values, key: .email) != nil {
|
||||
@ -953,9 +953,9 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode {
|
||||
if let email = list.twoStepEmail {
|
||||
immediatelyAvailableValue = .email(SecureIdEmailValue(email: email))
|
||||
}
|
||||
self.interaction.present(SecureIdPlaintextFormController(context: self.context, secureIdContext: secureIdContext, type: .email, immediatelyAvailableValue: immediatelyAvailableValue, updatedValue: { value in
|
||||
self.interaction.push(SecureIdPlaintextFormController(context: self.context, secureIdContext: secureIdContext, type: .email, immediatelyAvailableValue: immediatelyAvailableValue, updatedValue: { value in
|
||||
updatedValues(.email)(value.flatMap({ [$0] }) ?? [])
|
||||
}), nil)
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@ public final class SecureIdPlaintextFormController: FormController<SecureIdPlain
|
||||
|
||||
super.init(initParams: SecureIdPlaintextFormControllerNodeInitParams(context: context, secureIdContext: secureIdContext), presentationData: self.presentationData)
|
||||
|
||||
self.navigationPresentation = .modal
|
||||
|
||||
switch type {
|
||||
case .phone:
|
||||
self.title = self.presentationData.strings.Passport_Phone_Title
|
||||
|
||||
@ -782,11 +782,8 @@ public func channelAdminsController(context: AccountContext, peerId: PeerId, loa
|
||||
guard let controller = controller, let navigationController = controller.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(upgradedPeerId), keepStack: .never, animated: false, completion: {
|
||||
navigationController.pushViewController(channelAdminsController(context: context, peerId: upgradedPeerId, loadCompleted: {
|
||||
f()
|
||||
}), animated: false)
|
||||
}))
|
||||
|
||||
rebuildControllerStackAfterSupergroupUpgrade(controller: controller, navigationController: navigationController)
|
||||
}
|
||||
controller.visibleBottomContentOffsetChanged = { offset in
|
||||
if case let .known(value) = offset, value < 40.0 {
|
||||
@ -795,3 +792,19 @@ public func channelAdminsController(context: AccountContext, peerId: PeerId, loa
|
||||
}
|
||||
return controller
|
||||
}
|
||||
|
||||
func rebuildControllerStackAfterSupergroupUpgrade(controller: ViewController, navigationController: NavigationController) {
|
||||
var controllers = navigationController.viewControllers
|
||||
for i in 0 ..< controllers.count {
|
||||
if controllers[i] === controller {
|
||||
for j in 0 ..< i {
|
||||
if controllers[j] is ChatController {
|
||||
controllers.removeSubrange(j + 1 ... i - 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: false)
|
||||
}
|
||||
|
||||
@ -858,9 +858,7 @@ public func channelPermissionsController(context: AccountContext, peerId origina
|
||||
return
|
||||
}
|
||||
sourcePeerId.set(.single((upgradedPeerId, true)))
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(upgradedPeerId), keepStack: .never, animated: false, completion: {
|
||||
navigationController.pushViewController(controller, animated: false)
|
||||
}))
|
||||
rebuildControllerStackAfterSupergroupUpgrade(controller: controller, navigationController: navigationController)
|
||||
}
|
||||
|
||||
controller.visibleBottomContentOffsetChanged = { offset in
|
||||
|
||||
@ -465,7 +465,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
} else if let cachedChannelData = view.cachedData as? CachedChannelData, cachedChannelData.peerGeoLocation != nil {
|
||||
selectedType = .publicChannel
|
||||
} else {
|
||||
selectedType = .privateChannel
|
||||
selectedType = .publicChannel
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -512,7 +512,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
|
||||
case .publicChannel:
|
||||
var displayAvailability = false
|
||||
if peer.addressName == nil {
|
||||
displayAvailability = publicChannelsToRevoke == nil || !(publicChannelsToRevoke!.isEmpty)
|
||||
displayAvailability = publicChannelsToRevoke != nil && !(publicChannelsToRevoke!.isEmpty)
|
||||
}
|
||||
|
||||
if displayAvailability {
|
||||
|
||||
@ -40,6 +40,9 @@ import AppBundle
|
||||
import Markdown
|
||||
import LocalizedPeerData
|
||||
|
||||
private let maxParticipantsDisplayedLimit: Int32 = 50
|
||||
private let maxParticipantsDisplayedCollapseLimit: Int32 = 60
|
||||
|
||||
private final class GroupInfoArguments {
|
||||
let context: AccountContext
|
||||
|
||||
@ -71,8 +74,9 @@ private final class GroupInfoArguments {
|
||||
let openLocation: (PeerGeoLocation) -> Void
|
||||
let changeLocation: () -> Void
|
||||
let displayLocationContextMenu: (String) -> Void
|
||||
let expandParticipants: () -> Void
|
||||
|
||||
init(context: AccountContext, avatarAndNameInfoContext: ItemListAvatarAndNameInfoItemContext, tapAvatarAction: @escaping () -> Void, changeProfilePhoto: @escaping () -> Void, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, ViewControllerPresentationArguments) -> Void, changeNotificationMuteSettings: @escaping () -> Void, openPreHistory: @escaping () -> Void, openSharedMedia: @escaping () -> Void, openAdministrators: @escaping () -> Void, openPermissions: @escaping () -> Void, updateEditingName: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, updateEditingDescriptionText: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, addMember: @escaping () -> Void, promotePeer: @escaping (RenderedChannelParticipant) -> Void, restrictPeer: @escaping (RenderedChannelParticipant) -> Void, removePeer: @escaping (PeerId) -> Void, leave: @escaping () -> Void, displayUsernameShareMenu: @escaping (String) -> Void, displayUsernameContextMenu: @escaping (String) -> Void, displayAboutContextMenu: @escaping (String) -> Void, aboutLinkAction: @escaping (TextLinkItemActionType, TextLinkItem) -> Void, openStickerPackSetup: @escaping () -> Void, openGroupTypeSetup: @escaping () -> Void, openLinkedChannelSetup: @escaping () -> Void, openLocation: @escaping (PeerGeoLocation) -> Void, changeLocation: @escaping () -> Void, displayLocationContextMenu: @escaping (String) -> Void) {
|
||||
init(context: AccountContext, avatarAndNameInfoContext: ItemListAvatarAndNameInfoItemContext, tapAvatarAction: @escaping () -> Void, changeProfilePhoto: @escaping () -> Void, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, ViewControllerPresentationArguments) -> Void, changeNotificationMuteSettings: @escaping () -> Void, openPreHistory: @escaping () -> Void, openSharedMedia: @escaping () -> Void, openAdministrators: @escaping () -> Void, openPermissions: @escaping () -> Void, updateEditingName: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, updateEditingDescriptionText: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, addMember: @escaping () -> Void, promotePeer: @escaping (RenderedChannelParticipant) -> Void, restrictPeer: @escaping (RenderedChannelParticipant) -> Void, removePeer: @escaping (PeerId) -> Void, leave: @escaping () -> Void, displayUsernameShareMenu: @escaping (String) -> Void, displayUsernameContextMenu: @escaping (String) -> Void, displayAboutContextMenu: @escaping (String) -> Void, aboutLinkAction: @escaping (TextLinkItemActionType, TextLinkItem) -> Void, openStickerPackSetup: @escaping () -> Void, openGroupTypeSetup: @escaping () -> Void, openLinkedChannelSetup: @escaping () -> Void, openLocation: @escaping (PeerGeoLocation) -> Void, changeLocation: @escaping () -> Void, displayLocationContextMenu: @escaping (String) -> Void, expandParticipants: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.avatarAndNameInfoContext = avatarAndNameInfoContext
|
||||
self.tapAvatarAction = tapAvatarAction
|
||||
@ -102,6 +106,7 @@ private final class GroupInfoArguments {
|
||||
self.openLocation = openLocation
|
||||
self.changeLocation = changeLocation
|
||||
self.displayLocationContextMenu = displayLocationContextMenu
|
||||
self.expandParticipants = expandParticipants
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,6 +194,7 @@ private enum GroupInfoEntry: ItemListNodeEntry {
|
||||
case permissions(PresentationTheme, String, String)
|
||||
case addMember(PresentationTheme, String, editing: Bool)
|
||||
case member(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, index: Int, peerId: PeerId, peer: Peer, participant: RenderedChannelParticipant?, presence: PeerPresence?, memberStatus: GroupInfoMemberStatus, editing: ItemListPeerItemEditing, revealActions: [ParticipantRevealAction], enabled: Bool, selectable: Bool)
|
||||
case expand(PresentationTheme, String)
|
||||
case leave(PresentationTheme, String)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
@ -203,7 +209,7 @@ private enum GroupInfoEntry: ItemListNodeEntry {
|
||||
return GroupInfoSection.sharedMediaAndNotifications.rawValue
|
||||
case .permissions, .administrators:
|
||||
return GroupInfoSection.memberManagement.rawValue
|
||||
case .addMember, .member:
|
||||
case .addMember, .member, .expand:
|
||||
return GroupInfoSection.members.rawValue
|
||||
case .leave:
|
||||
return GroupInfoSection.leave.rawValue
|
||||
@ -213,40 +219,40 @@ private enum GroupInfoEntry: ItemListNodeEntry {
|
||||
static func ==(lhs: GroupInfoEntry, rhs: GroupInfoEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .info(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsCachedData, lhsState, lhsUpdatingAvatar):
|
||||
if case let .info(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsCachedData, rhsState, rhsUpdatingAvatar) = rhs {
|
||||
if lhsTheme !== rhsTheme {
|
||||
return false
|
||||
}
|
||||
if lhsStrings !== rhsStrings {
|
||||
return false
|
||||
}
|
||||
if lhsDateTimeFormat != rhsDateTimeFormat {
|
||||
return false
|
||||
}
|
||||
if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer {
|
||||
if !lhsPeer.isEqual(rhsPeer) {
|
||||
return false
|
||||
}
|
||||
} else if (lhsPeer == nil) != (rhsPeer != nil) {
|
||||
return false
|
||||
}
|
||||
if let lhsCachedData = lhsCachedData, let rhsCachedData = rhsCachedData {
|
||||
if !lhsCachedData.isEqual(to: rhsCachedData) {
|
||||
return false
|
||||
}
|
||||
} else if (lhsCachedData != nil) != (rhsCachedData != nil) {
|
||||
return false
|
||||
}
|
||||
if lhsState != rhsState {
|
||||
return false
|
||||
}
|
||||
if lhsUpdatingAvatar != rhsUpdatingAvatar {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
if case let .info(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsCachedData, rhsState, rhsUpdatingAvatar) = rhs {
|
||||
if lhsTheme !== rhsTheme {
|
||||
return false
|
||||
}
|
||||
if lhsStrings !== rhsStrings {
|
||||
return false
|
||||
}
|
||||
if lhsDateTimeFormat != rhsDateTimeFormat {
|
||||
return false
|
||||
}
|
||||
if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer {
|
||||
if !lhsPeer.isEqual(rhsPeer) {
|
||||
return false
|
||||
}
|
||||
} else if (lhsPeer == nil) != (rhsPeer != nil) {
|
||||
return false
|
||||
}
|
||||
if let lhsCachedData = lhsCachedData, let rhsCachedData = rhsCachedData {
|
||||
if !lhsCachedData.isEqual(to: rhsCachedData) {
|
||||
return false
|
||||
}
|
||||
} else if (lhsCachedData != nil) != (rhsCachedData != nil) {
|
||||
return false
|
||||
}
|
||||
if lhsState != rhsState {
|
||||
return false
|
||||
}
|
||||
if lhsUpdatingAvatar != rhsUpdatingAvatar {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .setGroupPhoto(lhsTheme, lhsText):
|
||||
if case let .setGroupPhoto(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
@ -419,6 +425,12 @@ private enum GroupInfoEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .expand(lhsTheme, lhsText):
|
||||
if case let .expand(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,8 +481,10 @@ private enum GroupInfoEntry: ItemListNodeEntry {
|
||||
return 16
|
||||
case let .member(_, _, _, _, index, _, _, _, _, _, _, _, _, _):
|
||||
return 20 + index
|
||||
case .leave:
|
||||
case .expand:
|
||||
return 200000 + 1
|
||||
case .leave:
|
||||
return 200000 + 2
|
||||
}
|
||||
}
|
||||
|
||||
@ -592,6 +606,10 @@ private enum GroupInfoEntry: ItemListNodeEntry {
|
||||
}, removePeer: { peerId in
|
||||
arguments.removePeer(peerId)
|
||||
})
|
||||
case let .expand(theme, title):
|
||||
return ItemListPeerActionItem(theme: theme, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: {
|
||||
arguments.expandParticipants()
|
||||
})
|
||||
case let .leave(theme, title):
|
||||
return ItemListActionItem(theme: theme, title: title, kind: .destructive, alignment: .center, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.leave()
|
||||
@ -627,6 +645,7 @@ private struct GroupInfoState: Equatable {
|
||||
let editingState: GroupInfoEditingState?
|
||||
let updatingName: ItemListAvatarAndNameInfoItemName?
|
||||
let peerIdWithRevealedOptions: PeerId?
|
||||
let expandedParticipants: Bool
|
||||
|
||||
let temporaryParticipants: [TemporaryParticipant]
|
||||
let successfullyAddedParticipantIds: Set<PeerId>
|
||||
@ -649,6 +668,9 @@ private struct GroupInfoState: Equatable {
|
||||
if lhs.peerIdWithRevealedOptions != rhs.peerIdWithRevealedOptions {
|
||||
return false
|
||||
}
|
||||
if lhs.expandedParticipants != rhs.expandedParticipants {
|
||||
return false
|
||||
}
|
||||
if lhs.temporaryParticipants != rhs.temporaryParticipants {
|
||||
return false
|
||||
}
|
||||
@ -668,39 +690,43 @@ private struct GroupInfoState: Equatable {
|
||||
}
|
||||
|
||||
func withUpdatedUpdatingAvatar(_ updatingAvatar: ItemListAvatarAndNameInfoItemUpdatingAvatar?) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedEditingState(_ editingState: GroupInfoEditingState?) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedUpdatingName(_ updatingName: ItemListAvatarAndNameInfoItemName?) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedPeerIdWithRevealedOptions(_ peerIdWithRevealedOptions: PeerId?) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedExpandedParticipants(_ expandedParticipants: Bool) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedTemporaryParticipants(_ temporaryParticipants: [TemporaryParticipant]) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedSuccessfullyAddedParticipantIds(_ successfullyAddedParticipantIds: Set<PeerId>) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedRemovingParticipantIds(_ removingParticipantIds: Set<PeerId>) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedSavingData(_ savingData: Bool) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: savingData, searchingMembers: self.searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: savingData, searchingMembers: self.searchingMembers)
|
||||
}
|
||||
|
||||
func withUpdatedSearchingMembers(_ searchingMembers: Bool) -> GroupInfoState {
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: searchingMembers)
|
||||
return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: searchingMembers)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1157,8 +1183,21 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
|
||||
sortedParticipants = updatedParticipants
|
||||
}
|
||||
|
||||
for i in 0 ..< sortedParticipants.count {
|
||||
let participant = sortedParticipants[i]
|
||||
var expanded = state.expandedParticipants
|
||||
let participants: [RenderedChannelParticipant]
|
||||
if expanded {
|
||||
participants = sortedParticipants
|
||||
} else {
|
||||
if sortedParticipants.count > maxParticipantsDisplayedCollapseLimit {
|
||||
participants = Array(sortedParticipants.prefix(Int(maxParticipantsDisplayedLimit)))
|
||||
} else {
|
||||
participants = sortedParticipants
|
||||
expanded = true
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0 ..< participants.count {
|
||||
let participant = participants[i]
|
||||
let memberStatus: GroupInfoMemberStatus
|
||||
switch participant.participant {
|
||||
case let .creator(_, rank):
|
||||
@ -1220,6 +1259,10 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
|
||||
|
||||
entries.append(GroupInfoEntry.member(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, index: i, peerId: participant.peer.id, peer: participant.peer, participant: participant, presence: participant.presences[participant.peer.id], memberStatus: memberStatus, editing: ItemListPeerItemEditing(editable: !peerActions.isEmpty, editing: state.editingState != nil && canRemoveAnyMember, revealed: state.peerIdWithRevealedOptions == participant.peer.id), revealActions: peerActions, enabled: true, selectable: participant.peer.id != account.peerId))
|
||||
}
|
||||
|
||||
if !expanded {
|
||||
entries.append(GroupInfoEntry.expand(presentationData.theme, presentationData.strings.GroupInfo_ShowMoreMembers(Int32(memberCount - maxParticipantsDisplayedLimit))))
|
||||
}
|
||||
}
|
||||
|
||||
if let group = view.peers[view.peerId] as? TelegramGroup {
|
||||
@ -1288,8 +1331,8 @@ private func valuesRequiringUpdate(state: GroupInfoState, view: PeerView) -> (ti
|
||||
}
|
||||
|
||||
public func groupInfoController(context: AccountContext, peerId originalPeerId: PeerId, membersLoaded: @escaping () -> Void = {}) -> ViewController {
|
||||
let statePromise = ValuePromise(GroupInfoState(updatingAvatar: nil, editingState: nil, updatingName: nil, peerIdWithRevealedOptions: nil, temporaryParticipants: [], successfullyAddedParticipantIds: Set(), removingParticipantIds: Set(), savingData: false, searchingMembers: false), ignoreRepeated: true)
|
||||
let stateValue = Atomic(value: GroupInfoState(updatingAvatar: nil, editingState: nil, updatingName: nil, peerIdWithRevealedOptions: nil, temporaryParticipants: [], successfullyAddedParticipantIds: Set(), removingParticipantIds: Set(), savingData: false, searchingMembers: false))
|
||||
let statePromise = ValuePromise(GroupInfoState(updatingAvatar: nil, editingState: nil, updatingName: nil, peerIdWithRevealedOptions: nil, expandedParticipants: false, temporaryParticipants: [], successfullyAddedParticipantIds: Set(), removingParticipantIds: Set(), savingData: false, searchingMembers: false), ignoreRepeated: true)
|
||||
let stateValue = Atomic(value: GroupInfoState(updatingAvatar: nil, editingState: nil, updatingName: nil, peerIdWithRevealedOptions: nil, expandedParticipants: false, temporaryParticipants: [], successfullyAddedParticipantIds: Set(), removingParticipantIds: Set(), savingData: false, searchingMembers: false))
|
||||
let updateState: ((GroupInfoState) -> GroupInfoState) -> Void = { f in
|
||||
statePromise.set(stateValue.modify { f($0) })
|
||||
}
|
||||
@ -2077,6 +2120,10 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
|
||||
})
|
||||
}, displayLocationContextMenu: { text in
|
||||
displayCopyContextMenuImpl?(text, .location)
|
||||
}, expandParticipants: {
|
||||
updateState {
|
||||
$0.withUpdatedExpandedParticipants(true)
|
||||
}
|
||||
})
|
||||
|
||||
let loadMoreControl = Atomic<(PeerId, PeerChannelMemberCategoryControl)?>(value: nil)
|
||||
@ -2453,7 +2500,9 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
|
||||
|
||||
controller.visibleBottomContentOffsetChanged = { offset in
|
||||
if let (peerId, loadMoreControl) = loadMoreControl.with({ $0 }), case let .known(value) = offset, value < 40.0 {
|
||||
context.peerChannelMemberCategoriesContextsManager.loadMore(peerId: peerId, control: loadMoreControl)
|
||||
if stateValue.with({ $0 }).expandedParticipants {
|
||||
context.peerChannelMemberCategoriesContextsManager.loadMore(peerId: peerId, control: loadMoreControl)
|
||||
}
|
||||
}
|
||||
}
|
||||
return controller
|
||||
|
||||
@ -1361,7 +1361,8 @@ public func userInfoController(context: AccountContext, peerId: PeerId, mode: Pe
|
||||
})
|
||||
}
|
||||
startSecretChatImpl = { [weak controller] in
|
||||
let _ = (context.account.postbox.transaction { transaction -> PeerId? in
|
||||
let _ = (context.account.postbox.transaction { transaction -> (Peer?, PeerId?) in
|
||||
let peer = transaction.getPeer(peerId)
|
||||
let filteredPeerIds = Array(transaction.getAssociatedPeerIds(peerId)).filter { $0.namespace == Namespaces.Peer.SecretChat }
|
||||
var activeIndices: [ChatListIndex] = []
|
||||
for associatedId in filteredPeerIds {
|
||||
@ -1378,54 +1379,57 @@ public func userInfoController(context: AccountContext, peerId: PeerId, mode: Pe
|
||||
}
|
||||
activeIndices.sort()
|
||||
if let index = activeIndices.last {
|
||||
return index.messageIndex.id.peerId
|
||||
return (peer, index.messageIndex.id.peerId)
|
||||
} else {
|
||||
return nil
|
||||
return (peer, nil)
|
||||
}
|
||||
} |> deliverOnMainQueue).start(next: { currentPeerId in
|
||||
} |> deliverOnMainQueue).start(next: { peer, currentPeerId in
|
||||
if let currentPeerId = currentPeerId {
|
||||
if let navigationController = (controller?.navigationController as? NavigationController) {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(currentPeerId)))
|
||||
}
|
||||
} else {
|
||||
var createSignal = createSecretChat(account: context.account, peerId: peerId)
|
||||
var cancelImpl: (() -> Void)?
|
||||
let progressSignal = Signal<Never, NoError> { subscriber in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
|
||||
cancelImpl?()
|
||||
}))
|
||||
presentControllerImpl?(controller, nil)
|
||||
return ActionDisposable { [weak controller] in
|
||||
Queue.mainQueue().async() {
|
||||
controller?.dismiss()
|
||||
} else if let controller = controller {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let displayTitle = peer?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) ?? ""
|
||||
controller.present(textAlertController(context: context, title: nil, text: presentationData.strings.UserInfo_StartSecretChatConfirmation(displayTitle).0, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.UserInfo_StartSecretChatStart, action: {
|
||||
var createSignal = createSecretChat(account: context.account, peerId: peerId)
|
||||
var cancelImpl: (() -> Void)?
|
||||
let progressSignal = Signal<Never, NoError> { subscriber in
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
|
||||
cancelImpl?()
|
||||
}))
|
||||
presentControllerImpl?(controller, nil)
|
||||
return ActionDisposable { [weak controller] in
|
||||
Queue.mainQueue().async() {
|
||||
controller?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
|> delay(0.15, queue: Queue.mainQueue())
|
||||
let progressDisposable = progressSignal.start()
|
||||
|
||||
createSignal = createSignal
|
||||
|> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
progressDisposable.dispose()
|
||||
|> runOn(Queue.mainQueue())
|
||||
|> delay(0.15, queue: Queue.mainQueue())
|
||||
let progressDisposable = progressSignal.start()
|
||||
|
||||
createSignal = createSignal
|
||||
|> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
progressDisposable.dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
cancelImpl = {
|
||||
createSecretChatDisposable.set(nil)
|
||||
}
|
||||
|
||||
createSecretChatDisposable.set((createSignal |> deliverOnMainQueue).start(next: { peerId in
|
||||
if let navigationController = (controller?.navigationController as? NavigationController) {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
|
||||
cancelImpl = {
|
||||
createSecretChatDisposable.set(nil)
|
||||
}
|
||||
}, error: { _ in
|
||||
if let controller = controller {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
controller.present(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
|
||||
createSecretChatDisposable.set((createSignal |> deliverOnMainQueue).start(next: { [weak controller] peerId in
|
||||
if let navigationController = (controller?.navigationController as? NavigationController) {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
|
||||
}
|
||||
}, error: { [weak controller] _ in
|
||||
if let controller = controller {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
controller.present(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
})]), in: .window(.root))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -430,14 +430,17 @@ final class AccountManagerImpl {
|
||||
}
|
||||
}
|
||||
|
||||
private let sharedQueue = Queue()
|
||||
|
||||
public final class AccountManager {
|
||||
public let basePath: String
|
||||
public let mediaBox: MediaBox
|
||||
private let queue = Queue()
|
||||
private let queue: Queue
|
||||
private let impl: QueueLocalObject<AccountManagerImpl>
|
||||
public let temporarySessionId: Int64
|
||||
|
||||
public init(basePath: String) {
|
||||
self.queue = sharedQueue
|
||||
self.basePath = basePath
|
||||
var temporarySessionId: Int64 = 0
|
||||
arc4random_buf(&temporarySessionId, 8)
|
||||
|
||||
@ -202,11 +202,16 @@ public final class MediaBox {
|
||||
return "\(self.basePath)/\(cacheString)/\(fileNameForId(id)):\(representation.uniqueId)"
|
||||
}
|
||||
|
||||
public func storeResourceData(_ id: MediaResourceId, data: Data) {
|
||||
self.dataQueue.async {
|
||||
public func storeResourceData(_ id: MediaResourceId, data: Data, synchronous: Bool = false) {
|
||||
let begin = {
|
||||
let paths = self.storePathsForId(id)
|
||||
let _ = try? data.write(to: URL(fileURLWithPath: paths.complete), options: [.atomic])
|
||||
}
|
||||
if synchronous {
|
||||
begin()
|
||||
} else {
|
||||
self.dataQueue.async(begin)
|
||||
}
|
||||
}
|
||||
|
||||
public func moveResourceData(_ id: MediaResourceId, fromTempPath: String) {
|
||||
|
||||
@ -3102,7 +3102,9 @@ public final class Postbox {
|
||||
return nil
|
||||
}
|
||||
if let messages = self.messageHistoryTable.getMessageFailedGroup(at: index, limit: 100) {
|
||||
return messages.map(self.renderIntermediateMessage)
|
||||
return messages.sorted(by: { lhs, rhs in
|
||||
return lhs.index < rhs.index
|
||||
}).map(self.renderIntermediateMessage)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import PresentationDataUtils
|
||||
|
||||
private func stringForKeepMediaTimeout(strings: PresentationStrings, timeout: Int32) -> String {
|
||||
if timeout > 1 * 31 * 24 * 60 * 60 {
|
||||
return strings.MessageTimer_Forever
|
||||
return strings.ClearCache_Forever
|
||||
} else {
|
||||
return timeIntervalString(strings: strings, value: timeout)
|
||||
}
|
||||
|
||||
@ -288,12 +288,12 @@ private func storageUsageControllerEntries(presentationData: PresentationData, c
|
||||
let totalSpaceValue = CGFloat(totalSpace)
|
||||
|
||||
if telegramCacheSize > 0 {
|
||||
categories.append(StorageUsageCategory(title: presentationData.strings.ClearCache_StorageCache, size: totalTelegramSize, fraction: CGFloat(totalTelegramSize) / totalSpaceValue, color: presentationData.theme.list.itemAccentColor))
|
||||
categories.append(StorageUsageCategory(title: presentationData.strings.ClearCache_StorageCache, size: totalTelegramSize, fraction: CGFloat(totalTelegramSize) / totalSpaceValue, color: presentationData.theme.list.itemBarChart.color1))
|
||||
} else {
|
||||
categories.append(StorageUsageCategory(title: presentationData.strings.ClearCache_StorageServiceFiles, size: totalTelegramSize, fraction: CGFloat(totalTelegramSize) / totalSpaceValue, color: presentationData.theme.list.itemAccentColor))
|
||||
categories.append(StorageUsageCategory(title: presentationData.strings.ClearCache_StorageServiceFiles, size: totalTelegramSize, fraction: CGFloat(totalTelegramSize) / totalSpaceValue, color: presentationData.theme.list.itemBarChart.color1))
|
||||
}
|
||||
categories.append(StorageUsageCategory(title: presentationData.strings.ClearCache_StorageOtherApps, size: otherAppsSpace, fraction: CGFloat(otherAppsSpace) / totalSpaceValue, color: presentationData.theme.list.itemBlocksSeparatorColor))
|
||||
categories.append(StorageUsageCategory(title: presentationData.strings.ClearCache_StorageFree, size: freeSpace, fraction: CGFloat(freeSpace) / totalSpaceValue, color: UIColor(rgb: 0xf2f1f7)))
|
||||
categories.append(StorageUsageCategory(title: presentationData.strings.ClearCache_StorageOtherApps, size: otherAppsSpace, fraction: CGFloat(otherAppsSpace) / totalSpaceValue, color: presentationData.theme.list.itemBarChart.color2))
|
||||
categories.append(StorageUsageCategory(title: presentationData.strings.ClearCache_StorageFree, size: freeSpace, fraction: CGFloat(freeSpace) / totalSpaceValue, color: presentationData.theme.list.itemBarChart.color3))
|
||||
|
||||
entries.append(.storageUsage(presentationData.theme, presentationData.dateTimeFormat, categories))
|
||||
|
||||
@ -433,11 +433,10 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
|
||||
controller?.updateItem(groupIndex: 0, itemIndex: itemIndex, { item in
|
||||
let title: String
|
||||
var filteredSize = sizeIndex.values.reduce(0, { $0 + ($1.0 ? $1.1 : 0) })
|
||||
selectedSize = filteredSize
|
||||
|
||||
if otherSize.0 {
|
||||
filteredSize += otherSize.1
|
||||
}
|
||||
selectedSize = filteredSize
|
||||
|
||||
if filteredSize == 0 {
|
||||
title = presentationData.strings.Cache_ClearNone
|
||||
@ -934,6 +933,10 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
|
||||
}
|
||||
|
||||
let controller = ItemListController(context: context, state: signal)
|
||||
if isModal {
|
||||
controller.navigationPresentation = .modal
|
||||
controller.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
}
|
||||
presentControllerImpl = { [weak controller] c, contextType, a in
|
||||
controller?.present(c, in: contextType, with: a)
|
||||
}
|
||||
|
||||
@ -180,7 +180,7 @@ private final class StorageUsageItemNode: ListViewItemNode {
|
||||
let inset: CGFloat = 16.0
|
||||
let horizontalSpacing: CGFloat = 32.0
|
||||
let verticalSpacing: CGFloat = 22.0
|
||||
var textOrigin: CGPoint = CGPoint(x: horizontalSpacing, y: 52.0)
|
||||
var textOrigin: CGPoint = CGPoint(x: params.leftInset + horizontalSpacing, y: 52.0)
|
||||
|
||||
for i in 0 ..< item.categories.count {
|
||||
let makeTextLayout = makeNodesLayout[i]
|
||||
@ -281,7 +281,7 @@ private final class StorageUsageItemNode: ListViewItemNode {
|
||||
|
||||
var categoryWidth = max(floor(lineWidth * category.fraction), 2.0)
|
||||
if i == strongSelf.lineNodes.count - 1 {
|
||||
categoryWidth = lineWidth - (lineOrigin.x - lineInset)
|
||||
categoryWidth = max(0.0, lineWidth - (lineOrigin.x - lineInset))
|
||||
}
|
||||
|
||||
let lineRect = CGRect(origin: lineOrigin, size: CGSize(width: categoryWidth, height: 21.0))
|
||||
|
||||
@ -641,14 +641,14 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
|
||||
case .set:
|
||||
break
|
||||
case let .notSet(pendingEmail):
|
||||
if pendingEmail == nil {
|
||||
break
|
||||
//intro = pendingEmail == nil
|
||||
/*if pendingEmail == nil {
|
||||
let controller = TwoFactorAuthSplashScreen(context: context, mode: .intro)
|
||||
pushControllerImpl?(controller, true)
|
||||
} else {
|
||||
|
||||
}
|
||||
//intro = pendingEmail == nil
|
||||
return
|
||||
}*/
|
||||
}
|
||||
}
|
||||
if intro {
|
||||
|
||||
@ -239,7 +239,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
let timestamp4 = timestamp + 3000
|
||||
items.append(ChatListItem(presentationData: chatListPresentationData, context: self.context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: peer4.id, namespace: 0, id: 0), timestamp: timestamp4)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer4.id, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp4, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer4, text: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), peer: RenderedPeer(peer: peer4), combinedReadState: nil, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction))
|
||||
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||
if let chatNodes = self.chatNodes {
|
||||
for i in 0 ..< items.count {
|
||||
let itemNode = chatNodes[i]
|
||||
@ -308,7 +308,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message4, theme: self.theme, strings: self.presentationData.strings, wallpaper: self.theme.chat.defaultWallpaper, fontSize: self.presentationData.fontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil))
|
||||
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||
if let messageNodes = self.messageNodes {
|
||||
for i in 0 ..< items.count {
|
||||
let itemNode = messageNodes[i]
|
||||
|
||||
@ -291,7 +291,7 @@ final class ThemeColorsGridControllerNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
let makeColorLayout = self.customColorItemNode.asyncLayout()
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: listInsets.left, rightInset: listInsets.right)
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: listInsets.left, rightInset: listInsets.right, availableHeight: layout.size.height)
|
||||
let (colorLayout, colorApply) = makeColorLayout(self.customColorItem, params, ItemListNeighbors(top: .none, bottom: .none))
|
||||
colorApply()
|
||||
|
||||
|
||||
@ -476,7 +476,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
||||
transition.updateFrame(node: strongSelf.bottomBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: gridLayout.contentSize.height), size: CGSize(width: layout.size.width, height: 500.0)))
|
||||
transition.updateFrame(node: strongSelf.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: gridLayout.contentSize.height), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
||||
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||
|
||||
let makeResetLayout = strongSelf.resetItemNode.asyncLayout()
|
||||
let makeResetDescriptionLayout = strongSelf.resetDescriptionItemNode.asyncLayout()
|
||||
@ -640,7 +640,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: listInsets.left, rightInset: listInsets.right)
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: listInsets.left, rightInset: listInsets.right, availableHeight: layout.size.height)
|
||||
let (colorLayout, colorApply) = makeColorLayout(self.colorItem, params, ItemListNeighbors(top: .none, bottom: .sameSection(alwaysPlain: false)))
|
||||
let (galleryLayout, galleryApply) = makeGalleryLayout(self.galleryItem, params, ItemListNeighbors(top: .sameSection(alwaysPlain: false), bottom: .sameSection(alwaysPlain: true)))
|
||||
let (descriptionLayout, descriptionApply) = makeDescriptionLayout(self.descriptionItem, params, ItemListNeighbors(top: .none, bottom: .none))
|
||||
|
||||
@ -372,7 +372,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
width = layout.size.width
|
||||
}
|
||||
|
||||
let params = ListViewItemLayoutParams(width: width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
let params = ListViewItemLayoutParams(width: width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||
if let chatNodes = self.chatNodes {
|
||||
for i in 0 ..< items.count {
|
||||
let itemNode = chatNodes[i]
|
||||
@ -452,7 +452,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
width = layout.size.width
|
||||
}
|
||||
|
||||
let params = ListViewItemLayoutParams(width: width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
let params = ListViewItemLayoutParams(width: width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||
if let messageNodes = self.messageNodes {
|
||||
for i in 0 ..< items.count {
|
||||
let itemNode = messageNodes[i]
|
||||
|
||||
@ -360,7 +360,8 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
private func themeSettingsControllerEntries(presentationData: PresentationData, theme: PresentationTheme, themeReference: PresentationThemeReference, themeSpecificAccentColors: [Int64: PresentationThemeAccentColor], availableThemes: [PresentationThemeReference], autoNightSettings: AutomaticThemeSwitchSetting, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, largeEmoji: Bool, disableAnimations: Bool, availableAppIcons: [PresentationAppIcon], currentAppIconName: String?) -> [ThemeSettingsControllerEntry] {
|
||||
var entries: [ThemeSettingsControllerEntry] = []
|
||||
|
||||
entries.append(.themeListHeader(presentationData.theme, strings.Appearance_ColorTheme.uppercased()))
|
||||
let title = presentationData.autoNightModeTriggered ? strings.Appearance_ColorThemeNight.uppercased() : strings.Appearance_ColorTheme.uppercased()
|
||||
entries.append(.themeListHeader(presentationData.theme, title))
|
||||
entries.append(.chatPreview(presentationData.theme, theme, wallpaper, fontSize, presentationData.strings, dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (presentationData.strings.Appearance_PreviewReplyAuthor, presentationData.strings.Appearance_PreviewReplyText), text: presentationData.strings.Appearance_PreviewIncomingText), ChatPreviewMessageItem(outgoing: true, reply: nil, text: presentationData.strings.Appearance_PreviewOutgoingText)]))
|
||||
|
||||
entries.append(.themeItem(presentationData.theme, presentationData.strings, availableThemes, themeReference, themeSpecificAccentColors, themeSpecificAccentColors[themeReference.index]))
|
||||
@ -371,22 +372,22 @@ private func themeSettingsControllerEntries(presentationData: PresentationData,
|
||||
|
||||
entries.append(.wallpaper(presentationData.theme, strings.Settings_ChatBackground))
|
||||
|
||||
let title: String
|
||||
let autoNightMode: String
|
||||
switch autoNightSettings.trigger {
|
||||
case .system:
|
||||
if #available(iOSApplicationExtension 13.0, iOS 13.0, *) {
|
||||
title = strings.AutoNightTheme_System
|
||||
autoNightMode = strings.AutoNightTheme_System
|
||||
} else {
|
||||
title = strings.AutoNightTheme_Disabled
|
||||
autoNightMode = strings.AutoNightTheme_Disabled
|
||||
}
|
||||
case .explicitNone:
|
||||
title = strings.AutoNightTheme_Disabled
|
||||
autoNightMode = strings.AutoNightTheme_Disabled
|
||||
case .timeBased:
|
||||
title = strings.AutoNightTheme_Scheduled
|
||||
autoNightMode = strings.AutoNightTheme_Scheduled
|
||||
case .brightness:
|
||||
title = strings.AutoNightTheme_Automatic
|
||||
autoNightMode = strings.AutoNightTheme_Automatic
|
||||
}
|
||||
entries.append(.autoNightTheme(presentationData.theme, strings.Appearance_AutoNightTheme, title))
|
||||
entries.append(.autoNightTheme(presentationData.theme, strings.Appearance_AutoNightTheme, autoNightMode))
|
||||
|
||||
entries.append(.fontSizeHeader(presentationData.theme, strings.Appearance_TextSize.uppercased()))
|
||||
entries.append(.fontSize(presentationData.theme, fontSize))
|
||||
@ -573,32 +574,39 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
let dateTimeFormat = presentationData.dateTimeFormat
|
||||
let largeEmoji = presentationData.largeEmoji
|
||||
let disableAnimations = presentationData.disableAnimations
|
||||
|
||||
let accentColor = settings.themeSpecificAccentColors[settings.theme.index]?.color
|
||||
let theme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: settings.theme, accentColor: accentColor, serviceBackgroundColor: defaultServiceBackgroundColor, baseColor: settings.themeSpecificAccentColors[settings.theme.index]?.baseColor ?? .blue, preview: true) ?? defaultPresentationTheme
|
||||
|
||||
let wallpaper: TelegramWallpaper
|
||||
if let themeSpecificWallpaper = settings.themeSpecificChatWallpapers[settings.theme.index] {
|
||||
wallpaper = themeSpecificWallpaper
|
||||
|
||||
let themeReference: PresentationThemeReference
|
||||
if presentationData.autoNightModeTriggered {
|
||||
themeReference = settings.automaticThemeSwitchSetting.theme
|
||||
} else {
|
||||
wallpaper = settings.chatWallpaper
|
||||
themeReference = settings.theme
|
||||
}
|
||||
|
||||
let theme = presentationData.theme
|
||||
let accentColor = settings.themeSpecificAccentColors[themeReference.index]?.color
|
||||
let wallpaper = settings.themeSpecificChatWallpapers[themeReference.index] ?? settings.chatWallpaper
|
||||
|
||||
let rightNavigationButton = ItemListNavigationButton(content: .icon(.action), style: .regular, enabled: true, action: {
|
||||
moreImpl?()
|
||||
})
|
||||
|
||||
let defaultThemes: [PresentationThemeReference] = [.builtin(.dayClassic), .builtin(.day), .builtin(.night), .builtin(.nightAccent)]
|
||||
var defaultThemes: [PresentationThemeReference] = []
|
||||
if presentationData.autoNightModeTriggered {
|
||||
} else {
|
||||
defaultThemes.append(contentsOf: [.builtin(.dayClassic), .builtin(.day)])
|
||||
}
|
||||
defaultThemes.append(contentsOf: [.builtin(.night), .builtin(.nightAccent)])
|
||||
|
||||
let cloudThemes: [PresentationThemeReference] = cloudThemes.map { .cloud(PresentationCloudTheme(theme: $0, resolvedWallpaper: nil)) }
|
||||
|
||||
var availableThemes = defaultThemes
|
||||
if defaultThemes.first(where: { $0.index == settings.theme.index }) == nil && cloudThemes.first(where: { $0.index == settings.theme.index }) == nil {
|
||||
availableThemes.append(settings.theme)
|
||||
if defaultThemes.first(where: { $0.index == themeReference.index }) == nil && cloudThemes.first(where: { $0.index == themeReference.index }) == nil {
|
||||
availableThemes.append(themeReference)
|
||||
}
|
||||
availableThemes.append(contentsOf: cloudThemes)
|
||||
|
||||
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Appearance_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||
let listState = ItemListNodeState(entries: themeSettingsControllerEntries(presentationData: presentationData, theme: theme, themeReference: settings.theme, themeSpecificAccentColors: settings.themeSpecificAccentColors, availableThemes: availableThemes, autoNightSettings: settings.automaticThemeSwitchSetting, strings: presentationData.strings, wallpaper: wallpaper, fontSize: fontSize, dateTimeFormat: dateTimeFormat, largeEmoji: largeEmoji, disableAnimations: disableAnimations, availableAppIcons: availableAppIcons, currentAppIconName: currentAppIconName), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
|
||||
let listState = ItemListNodeState(entries: themeSettingsControllerEntries(presentationData: presentationData, theme: theme, themeReference: themeReference, themeSpecificAccentColors: settings.themeSpecificAccentColors, availableThemes: availableThemes, autoNightSettings: settings.automaticThemeSwitchSetting, strings: presentationData.strings, wallpaper: wallpaper, fontSize: fontSize, dateTimeFormat: dateTimeFormat, largeEmoji: largeEmoji, disableAnimations: disableAnimations, availableAppIcons: availableAppIcons, currentAppIconName: currentAppIconName), style: .blocks, ensureVisibleItemTag: focusOnItemTag, animateChanges: false)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
@ -622,6 +630,8 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
return
|
||||
}
|
||||
|
||||
let autoNightModeTriggered = context.sharedContext.currentPresentationData.with { $0 }.autoNightModeTriggered
|
||||
|
||||
let resolvedWallpaper: Signal<TelegramWallpaper?, NoError>
|
||||
if case let .file(file) = presentationTheme.chat.defaultWallpaper, file.id == 0 {
|
||||
resolvedWallpaper = cachedWallpaper(account: context.account, slug: file.slug, settings: file.settings)
|
||||
@ -653,6 +663,14 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
current = PresentationThemeSettings.defaultSettings
|
||||
}
|
||||
|
||||
var theme = current.theme
|
||||
var automaticThemeSwitchSetting = current.automaticThemeSwitchSetting
|
||||
if autoNightModeTriggered {
|
||||
automaticThemeSwitchSetting.theme = updatedTheme
|
||||
} else {
|
||||
theme = updatedTheme
|
||||
}
|
||||
|
||||
let chatWallpaper: TelegramWallpaper
|
||||
if let themeSpecificWallpaper = current.themeSpecificChatWallpapers[updatedTheme.index] {
|
||||
chatWallpaper = themeSpecificWallpaper
|
||||
@ -660,8 +678,8 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
let presentationTheme = makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: updatedTheme, accentColor: current.themeSpecificAccentColors[updatedTheme.index]?.color, serviceBackgroundColor: .black, baseColor: nil) ?? defaultPresentationTheme
|
||||
chatWallpaper = resolvedWallpaper ?? presentationTheme.chat.defaultWallpaper
|
||||
}
|
||||
|
||||
return PresentationThemeSettings(chatWallpaper: chatWallpaper, theme: updatedTheme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
|
||||
return PresentationThemeSettings(chatWallpaper: chatWallpaper, theme: theme, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: current.themeSpecificChatWallpapers, fontSize: current.fontSize, automaticThemeSwitchSetting: automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
})
|
||||
})
|
||||
}).start()
|
||||
|
||||
@ -112,7 +112,7 @@ private func updatedFileWallpaper(id: Int64? = nil, accessHash: Int64? = nil, sl
|
||||
if let color = color {
|
||||
colorValue = Int32(bitPattern: color.rgb)
|
||||
intensityValue = intensity
|
||||
} else {
|
||||
} else if isPattern {
|
||||
colorValue = 0xd6e2ee
|
||||
intensityValue = 50
|
||||
}
|
||||
@ -384,10 +384,11 @@ public class WallpaperGalleryController: ViewController {
|
||||
let updatedSettings = WallpaperSettings(blur: options.contains(.blur), motion: options.contains(.motion), color: baseSettings?.color, intensity: baseSettings?.intensity)
|
||||
let wallpaper = wallpaper.withUpdatedSettings(updatedSettings)
|
||||
|
||||
let autoNightModeTriggered = strongSelf.presentationData.autoNightModeTriggered
|
||||
let _ = (updatePresentationThemeSettingsInteractively(accountManager: strongSelf.context.sharedContext.accountManager, { current in
|
||||
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||
var chatWallpaper = current.chatWallpaper
|
||||
if automaticThemeShouldSwitchNow(settings: current.automaticThemeSwitchSetting, systemUserInterfaceStyle: .light) {
|
||||
if autoNightModeTriggered {
|
||||
themeSpecificChatWallpapers[current.automaticThemeSwitchSetting.theme.index] = wallpaper
|
||||
} else {
|
||||
themeSpecificChatWallpapers[current.theme.index] = wallpaper
|
||||
@ -412,23 +413,41 @@ public class WallpaperGalleryController: ViewController {
|
||||
if options.contains(.blur) {
|
||||
if let resource = resource {
|
||||
let representation = CachedBlurredWallpaperRepresentation()
|
||||
let _ = strongSelf.context.account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: true, fetch: true).start()
|
||||
|
||||
var data: Data?
|
||||
if let path = strongSelf.context.account.postbox.mediaBox.completedResourcePath(resource), let maybeData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
data = maybeData
|
||||
} else if let path = strongSelf.context.sharedContext.accountManager.mediaBox.completedResourcePath(resource), let maybeData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
data = maybeData
|
||||
}
|
||||
|
||||
if let path = strongSelf.context.account.postbox.mediaBox.completedResourcePath(resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
strongSelf.context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data)
|
||||
let _ = strongSelf.context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: true, fetch: true).start(completed: {
|
||||
if let data = data {
|
||||
strongSelf.context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||
let _ = (strongSelf.context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: true, fetch: true)
|
||||
|> filter({ $0.complete })
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
completion(wallpaper)
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if case let .file(file) = wallpaper {
|
||||
} else if case let .file(file) = wallpaper, let resource = resource {
|
||||
if file.isPattern, let color = file.settings.color, let intensity = file.settings.intensity {
|
||||
let representation = CachedPatternWallpaperRepresentation(color: color, intensity: intensity)
|
||||
let _ = strongSelf.context.account.postbox.mediaBox.cachedResourceRepresentation(file.file.resource, representation: representation, complete: true, fetch: true).start()
|
||||
|
||||
if let path = strongSelf.context.account.postbox.mediaBox.completedResourcePath(file.file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
strongSelf.context.sharedContext.accountManager.mediaBox.storeResourceData(file.file.resource.id, data: data)
|
||||
let _ = strongSelf.context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(file.file.resource, representation: representation, complete: true, fetch: true).start(completed: {
|
||||
var data: Data?
|
||||
if let path = strongSelf.context.account.postbox.mediaBox.completedResourcePath(resource), let maybeData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
data = maybeData
|
||||
} else if let path = strongSelf.context.sharedContext.accountManager.mediaBox.completedResourcePath(resource), let maybeData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedRead) {
|
||||
data = maybeData
|
||||
}
|
||||
|
||||
if let data = data {
|
||||
strongSelf.context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
|
||||
let _ = (strongSelf.context.sharedContext.accountManager.mediaBox.cachedResourceRepresentation(resource, representation: representation, complete: true, fetch: true)
|
||||
|> filter({ $0.complete })
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
completion(wallpaper)
|
||||
})
|
||||
}
|
||||
@ -629,7 +648,7 @@ public class WallpaperGalleryController: ViewController {
|
||||
|
||||
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message2, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.fontSize, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil))
|
||||
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
|
||||
if let messageNodes = self.messageNodes {
|
||||
for i in 0 ..< items.count {
|
||||
let itemNode = messageNodes[i]
|
||||
|
||||
@ -292,8 +292,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
signal = wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: fileReference, representations: convertedRepresentations, alwaysShowThumbnailFirst: true, autoFetchFullSize: false)
|
||||
}
|
||||
fetchSignal = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: convertedRepresentations[convertedRepresentations.count - 1].reference)
|
||||
let account = context.account
|
||||
statusSignal = context.sharedContext.accountManager.mediaBox.resourceStatus(file.file.resource)
|
||||
let account = self.context.account
|
||||
statusSignal = self.context.sharedContext.accountManager.mediaBox.resourceStatus(file.file.resource)
|
||||
|> take(1)
|
||||
|> mapToSignal { status -> Signal<MediaResourceStatus, NoError> in
|
||||
if case .Local = status {
|
||||
|
||||
@ -23,6 +23,7 @@ static_library(
|
||||
"//submodules/ActivityIndicator:ActivityIndicator",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
|
||||
"//submodules/AppIntents:AppIntents",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
||||
@ -8,6 +8,7 @@ import TelegramCore
|
||||
import SyncCore
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import AppIntents
|
||||
|
||||
enum ShareState {
|
||||
case preparing
|
||||
@ -26,6 +27,7 @@ func openExternalShare(state: () -> Signal<ShareExternalState, NoError>) {
|
||||
|
||||
final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate {
|
||||
private let sharedContext: SharedAccountContext
|
||||
private var account: Account?
|
||||
private var presentationData: PresentationData
|
||||
private let externalShare: Bool
|
||||
private let immediateExternalShare: Bool
|
||||
@ -537,6 +539,10 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
peerIds = self.controllerInteraction!.selectedPeers.map { $0.peerId }
|
||||
}
|
||||
|
||||
if let account = self.account {
|
||||
donateSendMessageIntent(account: account, sharedContext: self.sharedContext, peerIds: peerIds)
|
||||
}
|
||||
|
||||
if let signal = self.share?(self.inputFieldNode.text, peerIds) {
|
||||
self.transitionToContentNode(ShareLoadingContainerNode(theme: self.presentationData.theme, forceNativeAppearance: true), fastOut: true)
|
||||
let timestamp = CACurrentMediaTime()
|
||||
@ -629,6 +635,8 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
|
||||
func updatePeers(account: Account, switchableAccounts: [AccountWithInfo], peers: [(RenderedPeer, PeerPresence?)], accountPeer: Peer, defaultAction: ShareControllerAction?) {
|
||||
self.account = account
|
||||
|
||||
if let peersContentNode = self.peersContentNode, peersContentNode.accountPeer.id == accountPeer.id {
|
||||
peersContentNode.peersValue.set(.single(peers))
|
||||
return
|
||||
|
||||
@ -19,18 +19,23 @@ public enum ManagedAudioSessionType: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func nativeCategoryForType(_ type: ManagedAudioSessionType, headphones: Bool) -> AVAudioSession.Category {
|
||||
private func nativeCategoryForType(_ type: ManagedAudioSessionType, headphones: Bool, outputMode: AudioSessionOutputMode) -> AVAudioSession.Category {
|
||||
switch type {
|
||||
case .play:
|
||||
case .play:
|
||||
return .playback
|
||||
case .record, .voiceCall:
|
||||
return .playAndRecord
|
||||
case .playWithPossiblePortOverride:
|
||||
if headphones {
|
||||
return .playback
|
||||
case .record, .voiceCall:
|
||||
return .playAndRecord
|
||||
case .playWithPossiblePortOverride:
|
||||
if headphones {
|
||||
return .playback
|
||||
} else {
|
||||
} else {
|
||||
switch outputMode {
|
||||
case .custom(.speaker), .system:
|
||||
return .playAndRecord
|
||||
default:
|
||||
return .playback
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -638,25 +643,29 @@ public final class ManagedAudioSession {
|
||||
self.currentTypeAndOutputMode = (type, outputMode)
|
||||
|
||||
do {
|
||||
print("ManagedAudioSession setting category for \(type)")
|
||||
let nativeCategory = nativeCategoryForType(type, headphones: self.isHeadsetPluggedInValue, outputMode: outputMode)
|
||||
|
||||
print("ManagedAudioSession setting category for \(type) (native: \(nativeCategory))")
|
||||
var options: AVAudioSession.CategoryOptions = []
|
||||
switch type {
|
||||
case .play:
|
||||
break
|
||||
case .playWithPossiblePortOverride:
|
||||
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||
options.insert(.allowBluetoothA2DP)
|
||||
} else {
|
||||
options.insert(.allowBluetooth)
|
||||
if case .playAndRecord = nativeCategory {
|
||||
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||
options.insert(.allowBluetoothA2DP)
|
||||
} else {
|
||||
options.insert(.allowBluetooth)
|
||||
}
|
||||
}
|
||||
case .record, .voiceCall:
|
||||
options.insert(.allowBluetooth)
|
||||
}
|
||||
print("ManagedAudioSession setting active true")
|
||||
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
||||
try AVAudioSession.sharedInstance().setCategory(nativeCategoryForType(type, headphones: self.isHeadsetPluggedInValue), mode: type == .voiceCall ? .voiceChat : .default, policy: .default, options: options)
|
||||
try AVAudioSession.sharedInstance().setCategory(nativeCategory, mode: type == .voiceCall ? .voiceChat : .default, policy: .default, options: options)
|
||||
} else {
|
||||
AVAudioSession.sharedInstance().perform(NSSelectorFromString("setCategory:error:"), with: nativeCategoryForType(type, headphones: self.isHeadsetPluggedInValue))
|
||||
AVAudioSession.sharedInstance().perform(NSSelectorFromString("setCategory:error:"), with: nativeCategory)
|
||||
try AVAudioSession.sharedInstance().setMode(type == .voiceCall ? .voiceChat : .default)
|
||||
}
|
||||
} catch let error {
|
||||
@ -684,43 +693,39 @@ public final class ManagedAudioSession {
|
||||
print("ManagedAudioSession setup \(outputMode) for \(type)")
|
||||
var resetToBuiltin = false
|
||||
switch outputMode {
|
||||
case .system:
|
||||
resetToBuiltin = true
|
||||
case let .custom(output):
|
||||
switch output {
|
||||
case .builtin:
|
||||
resetToBuiltin = true
|
||||
case .speaker:
|
||||
if type == .voiceCall {
|
||||
if let routes = AVAudioSession.sharedInstance().availableInputs {
|
||||
for route in routes {
|
||||
if route.portType == .builtInMic {
|
||||
let _ = try? AVAudioSession.sharedInstance().setPreferredInput(route)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
|
||||
case .headphones:
|
||||
break
|
||||
case let .port(port):
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
|
||||
case .system:
|
||||
resetToBuiltin = true
|
||||
case let .custom(output):
|
||||
switch output {
|
||||
case .builtin:
|
||||
resetToBuiltin = true
|
||||
case .speaker:
|
||||
if type == .voiceCall {
|
||||
if let routes = AVAudioSession.sharedInstance().availableInputs {
|
||||
for route in routes {
|
||||
if route.uid == port.uid {
|
||||
if route.portType == .builtInMic {
|
||||
let _ = try? AVAudioSession.sharedInstance().setPreferredInput(route)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case .speakerIfNoHeadphones:
|
||||
if !self.isHeadsetPluggedInValue {
|
||||
}
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
|
||||
} else {
|
||||
case .headphones:
|
||||
break
|
||||
case let .port(port):
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
|
||||
}
|
||||
if let routes = AVAudioSession.sharedInstance().availableInputs {
|
||||
for route in routes {
|
||||
if route.uid == port.uid {
|
||||
let _ = try? AVAudioSession.sharedInstance().setPreferredInput(route)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case .speakerIfNoHeadphones:
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
|
||||
}
|
||||
|
||||
if resetToBuiltin {
|
||||
@ -778,9 +783,11 @@ public final class ManagedAudioSession {
|
||||
|
||||
private func updateOutputMode(_ outputMode: AudioSessionOutputMode) {
|
||||
if let (type, currentOutputMode) = self.currentTypeAndOutputMode, currentOutputMode != outputMode {
|
||||
self.currentTypeAndOutputMode = (type, outputMode)
|
||||
//self.currentTypeAndOutputMode = (type, outputMode)
|
||||
do {
|
||||
try self.setupOutputMode(outputMode, type: type)
|
||||
try self.setup(type: type, outputMode: outputMode, activateNow: true)
|
||||
//try self.setupOutputMode(outputMode, type: type)
|
||||
//try self.activate()
|
||||
} catch let error {
|
||||
print("ManagedAudioSession overrideOutputAudioPort error \(error)")
|
||||
}
|
||||
|
||||
@ -179,7 +179,8 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
|
||||
mediaPlaceholderColor: UIColor(rgb: 0x1c1c1d),
|
||||
scrollIndicatorColor: UIColor(white: 1.0, alpha: 0.3),
|
||||
pageIndicatorInactiveColor: UIColor(white: 1.0, alpha: 0.3),
|
||||
inputClearButtonColor: UIColor(rgb: 0x8b9197)
|
||||
inputClearButtonColor: UIColor(rgb: 0x8b9197),
|
||||
itemBarChart: PresentationThemeItemBarChart(color1: accentColor, color2: UIColor(rgb: 0x929196), color3: UIColor(rgb: 0x333333))
|
||||
)
|
||||
|
||||
let chatList = PresentationThemeChatList(
|
||||
@ -219,8 +220,8 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
|
||||
)
|
||||
|
||||
let message = PresentationThemeChatMessage(
|
||||
incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x262628), highlightedFill: UIColor(rgb: 0x353539), stroke: UIColor(rgb: 0x262628)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x262628), highlightedFill: UIColor(rgb: 0x353539), stroke: UIColor(rgb: 0x262628))), primaryTextColor: .white, secondaryTextColor: UIColor(rgb: 0xffffff, alpha: 0.5), linkTextColor: accentColor, linkHighlightColor: accentColor.withAlphaComponent(0.5), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: accentColor, accentControlColor: accentColor, mediaActiveControlColor: accentColor, mediaInactiveControlColor: accentColor.withAlphaComponent(0.4), pendingActivityColor: UIColor(rgb: 0xffffff, alpha: 0.5), fileTitleColor: accentColor, fileDescriptionColor: UIColor(rgb: 0xffffff, alpha: 0.5), fileDurationColor: UIColor(rgb: 0xffffff, alpha: 0.5), mediaPlaceholderColor: UIColor(rgb: 0x1f1f1f).mixedWith(.white, alpha: 0.05), polls: PresentationThemeChatBubblePolls(radioButton: UIColor(rgb: 0x737373), radioProgress: accentColor, highlight: accentColor.withAlphaComponent(0.12), separator: UIColor(rgb: 0x000000), bar: accentColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0x000000, alpha: 0.5), withoutWallpaper: UIColor(rgb: 0x000000, alpha: 0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xb2b2b2, alpha: 0.18)), actionButtonsTextColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xffffff)), textSelectionColor: accentColor.withAlphaComponent(0.2), textSelectionKnobColor: accentColor),
|
||||
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, highlightedFill: outgoingBubbleHighlightedFillColor, stroke: outgoingBubbleFillColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, highlightedFill: outgoingBubbleHighlightedFillColor, stroke: outgoingBubbleFillColor)), primaryTextColor: outgoingPrimaryTextColor, secondaryTextColor: outgoingSecondaryTextColor, linkTextColor: outgoingLinkTextColor, linkHighlightColor: UIColor.white.withAlphaComponent(0.5), scamColor: outgoingScamColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: outgoingPrimaryTextColor, accentControlColor: outgoingPrimaryTextColor, mediaActiveControlColor: outgoingPrimaryTextColor, mediaInactiveControlColor: outgoingSecondaryTextColor, pendingActivityColor: outgoingSecondaryTextColor, fileTitleColor: outgoingPrimaryTextColor, fileDescriptionColor: outgoingSecondaryTextColor, fileDurationColor: outgoingSecondaryTextColor, mediaPlaceholderColor: UIColor(rgb: 0x313131).mixedWith(.white, alpha: 0.05), polls: PresentationThemeChatBubblePolls(radioButton: outgoingPrimaryTextColor, radioProgress: outgoingPrimaryTextColor, highlight: outgoingPrimaryTextColor.withAlphaComponent(0.12), separator: outgoingSecondaryTextColor, bar: outgoingPrimaryTextColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0x000000, alpha: 0.5), withoutWallpaper: UIColor(rgb: 0x000000, alpha: 0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xb2b2b2, alpha: 0.18)), actionButtonsTextColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xffffff)), textSelectionColor: UIColor.white.withAlphaComponent(0.2), textSelectionKnobColor: UIColor.white),
|
||||
incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x262628), highlightedFill: UIColor(rgb: 0x353539), stroke: UIColor(rgb: 0x262628)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x262628), highlightedFill: UIColor(rgb: 0x353539), stroke: UIColor(rgb: 0x262628))), primaryTextColor: .white, secondaryTextColor: UIColor(rgb: 0xffffff, alpha: 0.5), linkTextColor: accentColor, linkHighlightColor: accentColor.withAlphaComponent(0.5), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: accentColor, accentControlColor: accentColor, mediaActiveControlColor: accentColor, mediaInactiveControlColor: accentColor.withAlphaComponent(0.4), mediaControlInnerBackgroundColor: UIColor(rgb: 0x262628), pendingActivityColor: UIColor(rgb: 0xffffff, alpha: 0.5), fileTitleColor: accentColor, fileDescriptionColor: UIColor(rgb: 0xffffff, alpha: 0.5), fileDurationColor: UIColor(rgb: 0xffffff, alpha: 0.5), mediaPlaceholderColor: UIColor(rgb: 0x1f1f1f).mixedWith(.white, alpha: 0.05), polls: PresentationThemeChatBubblePolls(radioButton: UIColor(rgb: 0x737373), radioProgress: accentColor, highlight: accentColor.withAlphaComponent(0.12), separator: UIColor(rgb: 0x000000), bar: accentColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0x000000, alpha: 0.5), withoutWallpaper: UIColor(rgb: 0x000000, alpha: 0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xb2b2b2, alpha: 0.18)), actionButtonsTextColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xffffff)), textSelectionColor: accentColor.withAlphaComponent(0.2), textSelectionKnobColor: accentColor),
|
||||
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, highlightedFill: outgoingBubbleHighlightedFillColor, stroke: outgoingBubbleFillColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, highlightedFill: outgoingBubbleHighlightedFillColor, stroke: outgoingBubbleFillColor)), primaryTextColor: outgoingPrimaryTextColor, secondaryTextColor: outgoingSecondaryTextColor, linkTextColor: outgoingLinkTextColor, linkHighlightColor: UIColor.white.withAlphaComponent(0.5), scamColor: outgoingScamColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: outgoingPrimaryTextColor, accentControlColor: outgoingPrimaryTextColor, mediaActiveControlColor: outgoingPrimaryTextColor, mediaInactiveControlColor: outgoingSecondaryTextColor, mediaControlInnerBackgroundColor: outgoingBubbleFillColor, pendingActivityColor: outgoingSecondaryTextColor, fileTitleColor: outgoingPrimaryTextColor, fileDescriptionColor: outgoingSecondaryTextColor, fileDurationColor: outgoingSecondaryTextColor, mediaPlaceholderColor: UIColor(rgb: 0x313131).mixedWith(.white, alpha: 0.05), polls: PresentationThemeChatBubblePolls(radioButton: outgoingPrimaryTextColor, radioProgress: outgoingPrimaryTextColor, highlight: outgoingPrimaryTextColor.withAlphaComponent(0.12), separator: outgoingSecondaryTextColor, bar: outgoingPrimaryTextColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: UIColor(rgb: 0x000000, alpha: 0.5), withoutWallpaper: UIColor(rgb: 0x000000, alpha: 0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xb2b2b2, alpha: 0.18)), actionButtonsTextColor: PresentationThemeVariableColor(color: UIColor(rgb: 0xffffff)), textSelectionColor: UIColor.white.withAlphaComponent(0.2), textSelectionKnobColor: UIColor.white),
|
||||
freeform: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x1f1f1f), highlightedFill: UIColor(rgb: 0x2a2a2a), stroke: UIColor(rgb: 0x1f1f1f)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0x1f1f1f), highlightedFill: UIColor(rgb: 0x2a2a2a), stroke: UIColor(rgb: 0x1f1f1f))),
|
||||
infoPrimaryTextColor: .white,
|
||||
infoLinkTextColor: accentColor,
|
||||
@ -247,7 +248,7 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
|
||||
let inputPanelMediaRecordingControl = PresentationThemeChatInputPanelMediaRecordingControl(
|
||||
buttonColor: accentColor,
|
||||
micLevelColor: accentColor.withAlphaComponent(0.2),
|
||||
activeIconColor: .white
|
||||
activeIconColor: secondaryBadgeTextColor
|
||||
)
|
||||
|
||||
let inputPanel = PresentationThemeChatInputPanel(
|
||||
|
||||
@ -155,7 +155,8 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
|
||||
mediaPlaceholderColor: accentColor.withMultiplied(hue: 1.019, saturation: 0.585, brightness: 0.23),
|
||||
scrollIndicatorColor: UIColor(white: 1.0, alpha: 0.3),
|
||||
pageIndicatorInactiveColor: mainSecondaryTextColor.withAlphaComponent(0.4),
|
||||
inputClearButtonColor: mainSecondaryColor
|
||||
inputClearButtonColor: mainSecondaryColor,
|
||||
itemBarChart: PresentationThemeItemBarChart(color1: accentColor, color2: mainSecondaryTextColor.withAlphaComponent(0.5), color3: accentColor.withMultiplied(hue: 1.038, saturation: 0.329, brightness: 0.33))
|
||||
)
|
||||
|
||||
let chatList = PresentationThemeChatList(
|
||||
@ -197,8 +198,8 @@ private func makeDarkPresentationTheme(accentColor: UIColor, baseColor: Presenta
|
||||
let buttonStrokeColor = accentColor.withMultiplied(hue: 1.014, saturation: 0.56, brightness: 0.64).withAlphaComponent(0.15)
|
||||
|
||||
let message = PresentationThemeChatMessage(
|
||||
incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: mainBackgroundColor, highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: mainBackgroundColor, highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor)), primaryTextColor: .white, secondaryTextColor: mainSecondaryTextColor.withAlphaComponent(0.5), linkTextColor: accentColor, linkHighlightColor: accentColor.withAlphaComponent(0.5), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: accentColor, accentControlColor: accentColor, mediaActiveControlColor: accentColor, mediaInactiveControlColor: accentColor.withAlphaComponent(0.5), pendingActivityColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileTitleColor: accentColor, fileDescriptionColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileDurationColor: mainSecondaryTextColor.withAlphaComponent(0.5), mediaPlaceholderColor: accentColor.withMultiplied(hue: 1.019, saturation: 0.585, brightness: 0.23), polls: PresentationThemeChatBubblePolls(radioButton: accentColor.withMultiplied(hue: 0.995, saturation: 0.317, brightness: 0.51), radioProgress: accentColor, highlight: accentColor.withAlphaComponent(0.12), separator: mainSeparatorColor, bar: accentColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: additionalBackgroundColor.withAlphaComponent(0.5), withoutWallpaper: additionalBackgroundColor.withAlphaComponent(0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: buttonStrokeColor), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: accentColor.withAlphaComponent(0.2), textSelectionKnobColor: accentColor),
|
||||
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleColor, highlightedFill: highlightedOutgoingBubbleColor, stroke: outgoingBubbleColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleColor, highlightedFill: highlightedOutgoingBubbleColor, stroke: outgoingBubbleColor)), primaryTextColor: .white, secondaryTextColor: mainSecondaryTextColor.withAlphaComponent(0.5), linkTextColor: accentColor, linkHighlightColor: accentColor.withAlphaComponent(0.5), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: .white, accentControlColor: .white, mediaActiveControlColor: .white, mediaInactiveControlColor: UIColor(rgb: 0xffffff, alpha: 0.5), pendingActivityColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileTitleColor: .white, fileDescriptionColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileDurationColor: mainSecondaryTextColor.withAlphaComponent(0.5), mediaPlaceholderColor: accentColor.withMultiplied(hue: 1.019, saturation: 0.804, brightness: 0.51), polls: PresentationThemeChatBubblePolls(radioButton: .white, radioProgress: accentColor.withMultiplied(hue: 0.99, saturation: 0.56, brightness: 1.0), highlight: accentColor.withMultiplied(hue: 0.99, saturation: 0.56, brightness: 1.0).withAlphaComponent(0.12), separator: mainSeparatorColor, bar: .white), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: additionalBackgroundColor.withAlphaComponent(0.5), withoutWallpaper: additionalBackgroundColor.withAlphaComponent(0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: buttonStrokeColor), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: UIColor.white.withAlphaComponent(0.2), textSelectionKnobColor: UIColor.white),
|
||||
incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: mainBackgroundColor, highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: mainBackgroundColor, highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor)), primaryTextColor: .white, secondaryTextColor: mainSecondaryTextColor.withAlphaComponent(0.5), linkTextColor: accentColor, linkHighlightColor: accentColor.withAlphaComponent(0.5), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: accentColor, accentControlColor: accentColor, mediaActiveControlColor: accentColor, mediaInactiveControlColor: accentColor.withAlphaComponent(0.5), mediaControlInnerBackgroundColor: mainBackgroundColor, pendingActivityColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileTitleColor: accentColor, fileDescriptionColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileDurationColor: mainSecondaryTextColor.withAlphaComponent(0.5), mediaPlaceholderColor: accentColor.withMultiplied(hue: 1.019, saturation: 0.585, brightness: 0.23), polls: PresentationThemeChatBubblePolls(radioButton: accentColor.withMultiplied(hue: 0.995, saturation: 0.317, brightness: 0.51), radioProgress: accentColor, highlight: accentColor.withAlphaComponent(0.12), separator: mainSeparatorColor, bar: accentColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: additionalBackgroundColor.withAlphaComponent(0.5), withoutWallpaper: additionalBackgroundColor.withAlphaComponent(0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: buttonStrokeColor), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: accentColor.withAlphaComponent(0.2), textSelectionKnobColor: accentColor),
|
||||
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleColor, highlightedFill: highlightedOutgoingBubbleColor, stroke: outgoingBubbleColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleColor, highlightedFill: highlightedOutgoingBubbleColor, stroke: outgoingBubbleColor)), primaryTextColor: .white, secondaryTextColor: mainSecondaryTextColor.withAlphaComponent(0.5), linkTextColor: accentColor, linkHighlightColor: accentColor.withAlphaComponent(0.5), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xf5c038), accentTextColor: .white, accentControlColor: .white, mediaActiveControlColor: .white, mediaInactiveControlColor: UIColor(rgb: 0xffffff, alpha: 0.5), mediaControlInnerBackgroundColor: outgoingBubbleColor, pendingActivityColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileTitleColor: .white, fileDescriptionColor: mainSecondaryTextColor.withAlphaComponent(0.5), fileDurationColor: mainSecondaryTextColor.withAlphaComponent(0.5), mediaPlaceholderColor: accentColor.withMultiplied(hue: 1.019, saturation: 0.804, brightness: 0.51), polls: PresentationThemeChatBubblePolls(radioButton: .white, radioProgress: accentColor.withMultiplied(hue: 0.99, saturation: 0.56, brightness: 1.0), highlight: accentColor.withMultiplied(hue: 0.99, saturation: 0.56, brightness: 1.0).withAlphaComponent(0.12), separator: mainSeparatorColor, bar: .white), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: additionalBackgroundColor.withAlphaComponent(0.5), withoutWallpaper: additionalBackgroundColor.withAlphaComponent(0.5)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: buttonStrokeColor), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: UIColor.white.withAlphaComponent(0.2), textSelectionKnobColor: UIColor.white),
|
||||
freeform: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: mainBackgroundColor, highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: mainBackgroundColor, highlightedFill: highlightedIncomingBubbleColor, stroke: mainBackgroundColor)),
|
||||
infoPrimaryTextColor: UIColor(rgb: 0xffffff),
|
||||
infoLinkTextColor: accentColor,
|
||||
|
||||
@ -163,7 +163,8 @@ private func makeDefaultDayPresentationTheme(accentColor: UIColor, serviceBackgr
|
||||
mediaPlaceholderColor: UIColor(rgb: 0xe4e4e4),
|
||||
scrollIndicatorColor: UIColor(white: 0.0, alpha: 0.3),
|
||||
pageIndicatorInactiveColor: UIColor(rgb: 0xe3e3e7),
|
||||
inputClearButtonColor: UIColor(rgb: 0xcccccc)
|
||||
inputClearButtonColor: UIColor(rgb: 0xcccccc),
|
||||
itemBarChart: PresentationThemeItemBarChart(color1: accentColor, color2: UIColor(rgb: 0xc8c7cc), color3: UIColor(rgb: 0xf2f1f7))
|
||||
)
|
||||
|
||||
let chatList = PresentationThemeChatList(
|
||||
@ -203,8 +204,8 @@ private func makeDefaultDayPresentationTheme(accentColor: UIColor, serviceBackgr
|
||||
)
|
||||
|
||||
let message = PresentationThemeChatMessage(
|
||||
incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xffffff), highlightedFill: UIColor(rgb: 0xd9f4ff), stroke: UIColor(rgb: 0x86A9C9, alpha: 0.5)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xffffff), highlightedFill: UIColor(rgb: 0xd9f4ff), stroke: UIColor(rgb: 0x86A9C9, alpha: 0.5))), primaryTextColor: .black, secondaryTextColor: UIColor(rgb: 0x525252, alpha: 0.6), linkTextColor: UIColor(rgb: 0x004bad), linkHighlightColor: accentColor.withAlphaComponent(0.3), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xffe438), accentTextColor: UIColor(rgb: 0x007ee5), accentControlColor: UIColor(rgb: 0x007ee5), mediaActiveControlColor: UIColor(rgb: 0x007ee5), mediaInactiveControlColor: UIColor(rgb: 0xcacaca), pendingActivityColor: UIColor(rgb: 0x525252, alpha: 0.6), fileTitleColor: UIColor(rgb: 0x0b8bed), fileDescriptionColor: UIColor(rgb: 0x999999), fileDurationColor: UIColor(rgb: 0x525252, alpha: 0.6), mediaPlaceholderColor: UIColor(rgb: 0xe8ecf0), polls: PresentationThemeChatBubblePolls(radioButton: UIColor(rgb: 0xc8c7cc), radioProgress: UIColor(rgb: 0x007ee5), highlight: UIColor(rgb: 0x007ee5).withAlphaComponent(0.08), separator: UIColor(rgb: 0xc8c7cc), bar: UIColor(rgb: 0x007ee5)), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: serviceBackgroundColor, withoutWallpaper: UIColor(rgb: 0x596e89, alpha: 0.35)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: .clear), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: accentColor.withAlphaComponent(0.2), textSelectionKnobColor: accentColor),
|
||||
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xE1FFC7), highlightedFill: UIColor(rgb: 0xc8ffa6), stroke: UIColor(rgb: 0x86a9c9, alpha: 0.5)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xe1ffc7), highlightedFill: UIColor(rgb: 0xc8ffa6), stroke: UIColor(rgb: 0x86a9c9, alpha: 0.5))), primaryTextColor: .black, secondaryTextColor: UIColor(rgb: 0x008c09, alpha: 0.8), linkTextColor: UIColor(rgb: 0x004bad), linkHighlightColor: accentColor.withAlphaComponent(0.3), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xffe438), accentTextColor: UIColor(rgb: 0x00a700), accentControlColor: UIColor(rgb: 0x3fc33b), mediaActiveControlColor: UIColor(rgb: 0x3fc33b), mediaInactiveControlColor: UIColor(rgb: 0x93d987), pendingActivityColor: UIColor(rgb: 0x42b649), fileTitleColor: UIColor(rgb: 0x3faa3c), fileDescriptionColor: UIColor(rgb: 0x6fb26a), fileDurationColor: UIColor(rgb: 0x008c09, alpha: 0.8), mediaPlaceholderColor: UIColor(rgb: 0xd2f2b6), polls: PresentationThemeChatBubblePolls(radioButton: UIColor(rgb: 0x93d987), radioProgress: UIColor(rgb: 0x3fc33b), highlight: UIColor(rgb: 0x3fc33b).withAlphaComponent(0.08), separator: UIColor(rgb: 0x93d987), bar: UIColor(rgb: 0x3fc33b)), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: serviceBackgroundColor, withoutWallpaper: UIColor(rgb: 0x596e89, alpha: 0.35)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: .clear), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: UIColor(rgb: 0xBBDE9F), textSelectionKnobColor: UIColor(rgb: 0x3FC33B)),
|
||||
incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xffffff), highlightedFill: UIColor(rgb: 0xd9f4ff), stroke: UIColor(rgb: 0x86A9C9, alpha: 0.5)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xffffff), highlightedFill: UIColor(rgb: 0xd9f4ff), stroke: UIColor(rgb: 0x86A9C9, alpha: 0.5))), primaryTextColor: .black, secondaryTextColor: UIColor(rgb: 0x525252, alpha: 0.6), linkTextColor: UIColor(rgb: 0x004bad), linkHighlightColor: accentColor.withAlphaComponent(0.3), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xffe438), accentTextColor: UIColor(rgb: 0x007ee5), accentControlColor: UIColor(rgb: 0x007ee5), mediaActiveControlColor: UIColor(rgb: 0x007ee5), mediaInactiveControlColor: UIColor(rgb: 0xcacaca), mediaControlInnerBackgroundColor: UIColor(rgb: 0xffffff), pendingActivityColor: UIColor(rgb: 0x525252, alpha: 0.6), fileTitleColor: UIColor(rgb: 0x0b8bed), fileDescriptionColor: UIColor(rgb: 0x999999), fileDurationColor: UIColor(rgb: 0x525252, alpha: 0.6), mediaPlaceholderColor: UIColor(rgb: 0xe8ecf0), polls: PresentationThemeChatBubblePolls(radioButton: UIColor(rgb: 0xc8c7cc), radioProgress: UIColor(rgb: 0x007ee5), highlight: UIColor(rgb: 0x007ee5).withAlphaComponent(0.08), separator: UIColor(rgb: 0xc8c7cc), bar: UIColor(rgb: 0x007ee5)), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: serviceBackgroundColor, withoutWallpaper: UIColor(rgb: 0x596e89, alpha: 0.35)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: .clear), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: accentColor.withAlphaComponent(0.2), textSelectionKnobColor: accentColor),
|
||||
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xe1ffc7), highlightedFill: UIColor(rgb: 0xc8ffa6), stroke: UIColor(rgb: 0x86a9c9, alpha: 0.5)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xe1ffc7), highlightedFill: UIColor(rgb: 0xc8ffa6), stroke: UIColor(rgb: 0x86a9c9, alpha: 0.5))), primaryTextColor: .black, secondaryTextColor: UIColor(rgb: 0x008c09, alpha: 0.8), linkTextColor: UIColor(rgb: 0x004bad), linkHighlightColor: accentColor.withAlphaComponent(0.3), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xffe438), accentTextColor: UIColor(rgb: 0x00a700), accentControlColor: UIColor(rgb: 0x3fc33b), mediaActiveControlColor: UIColor(rgb: 0x3fc33b), mediaInactiveControlColor: UIColor(rgb: 0x93d987), mediaControlInnerBackgroundColor: UIColor(rgb: 0xe1ffc7), pendingActivityColor: UIColor(rgb: 0x42b649), fileTitleColor: UIColor(rgb: 0x3faa3c), fileDescriptionColor: UIColor(rgb: 0x6fb26a), fileDurationColor: UIColor(rgb: 0x008c09, alpha: 0.8), mediaPlaceholderColor: UIColor(rgb: 0xd2f2b6), polls: PresentationThemeChatBubblePolls(radioButton: UIColor(rgb: 0x93d987), radioProgress: UIColor(rgb: 0x3fc33b), highlight: UIColor(rgb: 0x3fc33b).withAlphaComponent(0.08), separator: UIColor(rgb: 0x93d987), bar: UIColor(rgb: 0x3fc33b)), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: serviceBackgroundColor, withoutWallpaper: UIColor(rgb: 0x596e89, alpha: 0.35)), actionButtonsStrokeColor: PresentationThemeVariableColor(color: .clear), actionButtonsTextColor: PresentationThemeVariableColor(color: .white), textSelectionColor: UIColor(rgb: 0xBBDE9F), textSelectionKnobColor: UIColor(rgb: 0x3FC33B)),
|
||||
freeform: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xffffff), highlightedFill: UIColor(rgb: 0xd9f4ff), stroke: UIColor(rgb: 0x86A9C9, alpha: 0.5)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xffffff), highlightedFill: UIColor(rgb: 0xd9f4ff), stroke: UIColor(rgb: 0x86A9C9, alpha: 0.5))),
|
||||
infoPrimaryTextColor: UIColor(rgb: 0x000000),
|
||||
infoLinkTextColor: UIColor(rgb: 0x004bad),
|
||||
@ -221,8 +222,8 @@ private func makeDefaultDayPresentationTheme(accentColor: UIColor, serviceBackgr
|
||||
)
|
||||
|
||||
let messageDay = PresentationThemeChatMessage(
|
||||
incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xffffff), highlightedFill: UIColor(rgb: 0xdadade), stroke: UIColor(rgb: 0xffffff)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xf1f1f4), highlightedFill: UIColor(rgb: 0xdadade), stroke: UIColor(rgb: 0xf1f1f4))), primaryTextColor: .black, secondaryTextColor: UIColor(rgb: 0x525252, alpha: 0.6), linkTextColor: UIColor(rgb: 0x004bad), linkHighlightColor: accentColor.withAlphaComponent(0.3), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xffc738), accentTextColor: accentColor, accentControlColor: accentColor, mediaActiveControlColor: accentColor, mediaInactiveControlColor: UIColor(rgb: 0xcacaca), pendingActivityColor: UIColor(rgb: 0x525252, alpha: 0.6), fileTitleColor: accentColor, fileDescriptionColor: UIColor(rgb: 0x999999), fileDurationColor: UIColor(rgb: 0x525252, alpha: 0.6), mediaPlaceholderColor: UIColor(rgb: 0xffffff).withMultipliedBrightnessBy(0.95), polls: PresentationThemeChatBubblePolls(radioButton: UIColor(rgb: 0xc8c7cc), radioProgress: accentColor, highlight: accentColor.withAlphaComponent(0.12), separator: UIColor(rgb: 0xc8c7cc), bar: accentColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: serviceBackgroundColor, withoutWallpaper: UIColor(rgb: 0xffffff, alpha: 0.8)), actionButtonsStrokeColor: PresentationThemeVariableColor(withWallpaper: .clear, withoutWallpaper: accentColor), actionButtonsTextColor: PresentationThemeVariableColor(withWallpaper: .white, withoutWallpaper: accentColor), textSelectionColor: accentColor.withAlphaComponent(0.3), textSelectionKnobColor: accentColor),
|
||||
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, highlightedFill: outgoingBubbleFillColor.withMultipliedBrightnessBy(0.7), stroke: outgoingBubbleFillColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, highlightedFill: outgoingBubbleFillColor.withMultipliedBrightnessBy(0.7), stroke: outgoingBubbleStrokeColor)), primaryTextColor: outgoingPrimaryTextColor, secondaryTextColor: outgoingSecondaryTextColor, linkTextColor: outgoingLinkTextColor, linkHighlightColor: UIColor(rgb: 0xffffff, alpha: 0.3), scamColor: outgoingPrimaryTextColor, textHighlightColor: UIColor(rgb: 0xffc738), accentTextColor: outgoingPrimaryTextColor, accentControlColor: outgoingPrimaryTextColor, mediaActiveControlColor: outgoingPrimaryTextColor, mediaInactiveControlColor: outgoingSecondaryTextColor, pendingActivityColor: outgoingSecondaryTextColor, fileTitleColor: outgoingPrimaryTextColor, fileDescriptionColor: outgoingSecondaryTextColor, fileDurationColor: outgoingSecondaryTextColor, mediaPlaceholderColor: accentColor.withMultipliedBrightnessBy(0.95), polls: PresentationThemeChatBubblePolls(radioButton: outgoingSecondaryTextColor, radioProgress: outgoingPrimaryTextColor, highlight: outgoingPrimaryTextColor.withAlphaComponent(0.12), separator: outgoingSecondaryTextColor, bar: outgoingPrimaryTextColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: serviceBackgroundColor, withoutWallpaper: UIColor(rgb: 0xffffff, alpha: 0.8)), actionButtonsStrokeColor: PresentationThemeVariableColor(withWallpaper: .clear, withoutWallpaper: accentColor), actionButtonsTextColor: PresentationThemeVariableColor(withWallpaper: .white, withoutWallpaper: accentColor), textSelectionColor: outgoingSelectionBaseColor.withAlphaComponent(0.2), textSelectionKnobColor: outgoingSelectionBaseColor),
|
||||
incoming: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xffffff), highlightedFill: UIColor(rgb: 0xdadade), stroke: UIColor(rgb: 0xffffff)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xf1f1f4), highlightedFill: UIColor(rgb: 0xdadade), stroke: UIColor(rgb: 0xf1f1f4))), primaryTextColor: .black, secondaryTextColor: UIColor(rgb: 0x525252, alpha: 0.6), linkTextColor: UIColor(rgb: 0x004bad), linkHighlightColor: accentColor.withAlphaComponent(0.3), scamColor: destructiveColor, textHighlightColor: UIColor(rgb: 0xffc738), accentTextColor: accentColor, accentControlColor: accentColor, mediaActiveControlColor: accentColor, mediaInactiveControlColor: UIColor(rgb: 0xcacaca), mediaControlInnerBackgroundColor: UIColor(rgb: 0xffffff), pendingActivityColor: UIColor(rgb: 0x525252, alpha: 0.6), fileTitleColor: accentColor, fileDescriptionColor: UIColor(rgb: 0x999999), fileDurationColor: UIColor(rgb: 0x525252, alpha: 0.6), mediaPlaceholderColor: UIColor(rgb: 0xffffff).withMultipliedBrightnessBy(0.95), polls: PresentationThemeChatBubblePolls(radioButton: UIColor(rgb: 0xc8c7cc), radioProgress: accentColor, highlight: accentColor.withAlphaComponent(0.12), separator: UIColor(rgb: 0xc8c7cc), bar: accentColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: serviceBackgroundColor, withoutWallpaper: UIColor(rgb: 0xffffff, alpha: 0.8)), actionButtonsStrokeColor: PresentationThemeVariableColor(withWallpaper: .clear, withoutWallpaper: accentColor), actionButtonsTextColor: PresentationThemeVariableColor(withWallpaper: .white, withoutWallpaper: accentColor), textSelectionColor: accentColor.withAlphaComponent(0.3), textSelectionKnobColor: accentColor),
|
||||
outgoing: PresentationThemePartedColors(bubble: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, highlightedFill: outgoingBubbleFillColor.withMultipliedBrightnessBy(0.7), stroke: outgoingBubbleFillColor), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: outgoingBubbleFillColor, highlightedFill: outgoingBubbleFillColor.withMultipliedBrightnessBy(0.7), stroke: outgoingBubbleStrokeColor)), primaryTextColor: outgoingPrimaryTextColor, secondaryTextColor: outgoingSecondaryTextColor, linkTextColor: outgoingLinkTextColor, linkHighlightColor: UIColor(rgb: 0xffffff, alpha: 0.3), scamColor: outgoingPrimaryTextColor, textHighlightColor: UIColor(rgb: 0xffc738), accentTextColor: outgoingPrimaryTextColor, accentControlColor: outgoingPrimaryTextColor, mediaActiveControlColor: outgoingPrimaryTextColor, mediaInactiveControlColor: outgoingSecondaryTextColor, mediaControlInnerBackgroundColor: outgoingBubbleFillColor, pendingActivityColor: outgoingSecondaryTextColor, fileTitleColor: outgoingPrimaryTextColor, fileDescriptionColor: outgoingSecondaryTextColor, fileDurationColor: outgoingSecondaryTextColor, mediaPlaceholderColor: accentColor.withMultipliedBrightnessBy(0.95), polls: PresentationThemeChatBubblePolls(radioButton: outgoingSecondaryTextColor, radioProgress: outgoingPrimaryTextColor, highlight: outgoingPrimaryTextColor.withAlphaComponent(0.12), separator: outgoingSecondaryTextColor, bar: outgoingPrimaryTextColor), actionButtonsFillColor: PresentationThemeVariableColor(withWallpaper: serviceBackgroundColor, withoutWallpaper: UIColor(rgb: 0xffffff, alpha: 0.8)), actionButtonsStrokeColor: PresentationThemeVariableColor(withWallpaper: .clear, withoutWallpaper: accentColor), actionButtonsTextColor: PresentationThemeVariableColor(withWallpaper: .white, withoutWallpaper: accentColor), textSelectionColor: outgoingSelectionBaseColor.withAlphaComponent(0.2), textSelectionKnobColor: outgoingSelectionBaseColor),
|
||||
freeform: PresentationThemeBubbleColor(withWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xE5E5EA), highlightedFill: UIColor(rgb: 0xDADADE), stroke: UIColor(rgb: 0xE5E5EA)), withoutWallpaper: PresentationThemeBubbleColorComponents(fill: UIColor(rgb: 0xE5E5EA), highlightedFill: UIColor(rgb: 0xdadade), stroke: UIColor(rgb: 0xE5E5EA))),
|
||||
infoPrimaryTextColor: UIColor(rgb: 0x000000),
|
||||
infoLinkTextColor: UIColor(rgb: 0x004bad),
|
||||
|
||||
@ -26,16 +26,6 @@ public struct PresentationDateTimeFormat: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct PresentationVolumeControlStatusBarIcons: Equatable {
|
||||
public let offIcon: UIImage
|
||||
public let halfIcon: UIImage
|
||||
public let fullIcon: UIImage
|
||||
|
||||
public var images: (UIImage, UIImage, UIImage) {
|
||||
return (self.offIcon, self.halfIcon, self.fullIcon)
|
||||
}
|
||||
}
|
||||
|
||||
public struct PresentationAppIcon: Equatable {
|
||||
public let name: String
|
||||
public let imageName: String
|
||||
@ -61,8 +51,8 @@ public enum PresentationDateFormat {
|
||||
public final class PresentationData: Equatable {
|
||||
public let strings: PresentationStrings
|
||||
public let theme: PresentationTheme
|
||||
public let autoNightModeTriggered: Bool
|
||||
public let chatWallpaper: TelegramWallpaper
|
||||
public let volumeControlStatusBarIcons: PresentationVolumeControlStatusBarIcons
|
||||
public let fontSize: PresentationFontSize
|
||||
public let dateTimeFormat: PresentationDateTimeFormat
|
||||
public let nameDisplayOrder: PresentationPersonNameOrder
|
||||
@ -70,11 +60,11 @@ public final class PresentationData: Equatable {
|
||||
public let disableAnimations: Bool
|
||||
public let largeEmoji: Bool
|
||||
|
||||
public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, volumeControlStatusBarIcons: PresentationVolumeControlStatusBarIcons, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder, disableAnimations: Bool, largeEmoji: Bool) {
|
||||
public init(strings: PresentationStrings, theme: PresentationTheme, autoNightModeTriggered: Bool, chatWallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder, disableAnimations: Bool, largeEmoji: Bool) {
|
||||
self.strings = strings
|
||||
self.theme = theme
|
||||
self.autoNightModeTriggered = autoNightModeTriggered
|
||||
self.chatWallpaper = chatWallpaper
|
||||
self.volumeControlStatusBarIcons = volumeControlStatusBarIcons
|
||||
self.fontSize = fontSize
|
||||
self.dateTimeFormat = dateTimeFormat
|
||||
self.nameDisplayOrder = nameDisplayOrder
|
||||
@ -84,7 +74,7 @@ public final class PresentationData: Equatable {
|
||||
}
|
||||
|
||||
public static func ==(lhs: PresentationData, rhs: PresentationData) -> Bool {
|
||||
return lhs.strings === rhs.strings && lhs.theme === rhs.theme && lhs.chatWallpaper == rhs.chatWallpaper && lhs.volumeControlStatusBarIcons == rhs.volumeControlStatusBarIcons && lhs.fontSize == rhs.fontSize && lhs.dateTimeFormat == rhs.dateTimeFormat && lhs.disableAnimations == rhs.disableAnimations && lhs.largeEmoji == rhs.largeEmoji
|
||||
return lhs.strings === rhs.strings && lhs.theme === rhs.theme && lhs.autoNightModeTriggered == rhs.autoNightModeTriggered && lhs.chatWallpaper == rhs.chatWallpaper && lhs.fontSize == rhs.fontSize && lhs.dateTimeFormat == rhs.dateTimeFormat && lhs.disableAnimations == rhs.disableAnimations && lhs.largeEmoji == rhs.largeEmoji
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,11 +106,6 @@ public func dictFromLocalization(_ value: Localization) -> [String: String] {
|
||||
return dict
|
||||
}
|
||||
|
||||
private func volumeControlStatusBarIcons() -> PresentationVolumeControlStatusBarIcons {
|
||||
let bundle = getAppBundle()
|
||||
return PresentationVolumeControlStatusBarIcons(offIcon: UIImage(named: "Components/Volume/VolumeOff", in: bundle, compatibleWith: nil)!, halfIcon: UIImage(named: "Components/Volume/VolumeHalf", in: bundle, compatibleWith: nil)!, fullIcon: UIImage(named: "Components/Volume/VolumeFull", in: bundle, compatibleWith: nil)!)
|
||||
}
|
||||
|
||||
private func currentDateTimeFormat() -> PresentationDateTimeFormat {
|
||||
let locale = Locale.current
|
||||
let dateFormatter = DateFormatter()
|
||||
@ -249,10 +234,13 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager, s
|
||||
var effectiveChatWallpaper: TelegramWallpaper = themeSettings.chatWallpaper
|
||||
|
||||
let parameters = AutomaticThemeSwitchParameters(settings: themeSettings.automaticThemeSwitchSetting)
|
||||
let autoNightModeTriggered: Bool
|
||||
if automaticThemeShouldSwitchNow(parameters, systemUserInterfaceStyle: systemUserInterfaceStyle) {
|
||||
effectiveTheme = themeSettings.automaticThemeSwitchSetting.theme
|
||||
autoNightModeTriggered = true
|
||||
} else {
|
||||
effectiveTheme = themeSettings.theme
|
||||
autoNightModeTriggered = false
|
||||
}
|
||||
|
||||
let effectiveAccentColor = themeSettings.themeSpecificAccentColors[effectiveTheme.index]?.color
|
||||
@ -276,7 +264,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager, s
|
||||
}
|
||||
let nameDisplayOrder = contactSettings.nameDisplayOrder
|
||||
let nameSortOrder = currentPersonNameSortOrder()
|
||||
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, volumeControlStatusBarIcons: volumeControlStatusBarIcons(), fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations, largeEmoji: themeSettings.largeEmoji), automaticMediaDownloadSettings: automaticMediaDownloadSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, experimentalUISettings: experimentalUISettings)
|
||||
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: themeValue, autoNightModeTriggered: autoNightModeTriggered, chatWallpaper: effectiveChatWallpaper, fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations, largeEmoji: themeSettings.largeEmoji), automaticMediaDownloadSettings: automaticMediaDownloadSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, experimentalUISettings: experimentalUISettings)
|
||||
}
|
||||
}
|
||||
|
||||
@ -499,11 +487,11 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI
|
||||
if inForeground {
|
||||
return automaticThemeShouldSwitch(themeSettings.automaticThemeSwitchSetting, systemUserInterfaceStyle: systemUserInterfaceStyle)
|
||||
|> distinctUntilChanged
|
||||
|> map { shouldSwitch in
|
||||
|> map { autoNightModeTriggered in
|
||||
var effectiveTheme: PresentationThemeReference
|
||||
var effectiveChatWallpaper: TelegramWallpaper = currentWallpaper
|
||||
|
||||
if shouldSwitch {
|
||||
if autoNightModeTriggered {
|
||||
let automaticTheme = themeSettings.automaticThemeSwitchSetting.theme
|
||||
if let themeSpecificWallpaper = themeSettings.themeSpecificChatWallpapers[automaticTheme.index] {
|
||||
effectiveChatWallpaper = themeSpecificWallpaper
|
||||
@ -546,7 +534,7 @@ public func updatedPresentationData(accountManager: AccountManager, applicationI
|
||||
let nameDisplayOrder = contactSettings.nameDisplayOrder
|
||||
let nameSortOrder = currentPersonNameSortOrder()
|
||||
|
||||
return PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, volumeControlStatusBarIcons: volumeControlStatusBarIcons(), fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations, largeEmoji: themeSettings.largeEmoji)
|
||||
return PresentationData(strings: stringsValue, theme: themeValue, autoNightModeTriggered: autoNightModeTriggered, chatWallpaper: effectiveChatWallpaper, fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations, largeEmoji: themeSettings.largeEmoji)
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
@ -562,5 +550,5 @@ public func defaultPresentationData() -> PresentationData {
|
||||
let nameSortOrder = currentPersonNameSortOrder()
|
||||
|
||||
let themeSettings = PresentationThemeSettings.defaultSettings
|
||||
return PresentationData(strings: defaultPresentationStrings, theme: defaultPresentationTheme, chatWallpaper: .builtin(WallpaperSettings()), volumeControlStatusBarIcons: volumeControlStatusBarIcons(), fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations, largeEmoji: themeSettings.largeEmoji)
|
||||
return PresentationData(strings: defaultPresentationStrings, theme: defaultPresentationTheme, autoNightModeTriggered: false, chatWallpaper: .builtin(WallpaperSettings()), fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations, largeEmoji: themeSettings.largeEmoji)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -289,6 +289,18 @@ public final class PresentationThemeItemDisclosureActions {
|
||||
}
|
||||
}
|
||||
|
||||
public final class PresentationThemeItemBarChart {
|
||||
public let color1: UIColor
|
||||
public let color2: UIColor
|
||||
public let color3: UIColor
|
||||
|
||||
public init(color1: UIColor, color2: UIColor, color3: UIColor) {
|
||||
self.color1 = color1
|
||||
self.color2 = color2
|
||||
self.color3 = color3
|
||||
}
|
||||
}
|
||||
|
||||
public final class PresentationThemeFillStrokeForeground {
|
||||
public let fillColor: UIColor
|
||||
public let strokeColor: UIColor
|
||||
@ -346,8 +358,9 @@ public final class PresentationThemeList {
|
||||
public let scrollIndicatorColor: UIColor
|
||||
public let pageIndicatorInactiveColor: UIColor
|
||||
public let inputClearButtonColor: UIColor
|
||||
public let itemBarChart: PresentationThemeItemBarChart
|
||||
|
||||
public init(blocksBackgroundColor: UIColor, plainBackgroundColor: UIColor, itemPrimaryTextColor: UIColor, itemSecondaryTextColor: UIColor, itemDisabledTextColor: UIColor, itemAccentColor: UIColor, itemHighlightedColor: UIColor, itemDestructiveColor: UIColor, itemPlaceholderTextColor: UIColor, itemBlocksBackgroundColor: UIColor, itemHighlightedBackgroundColor: UIColor, itemBlocksSeparatorColor: UIColor, itemPlainSeparatorColor: UIColor, disclosureArrowColor: UIColor, sectionHeaderTextColor: UIColor, freeTextColor: UIColor, freeTextErrorColor: UIColor, freeTextSuccessColor: UIColor, freeMonoIconColor: UIColor, itemSwitchColors: PresentationThemeSwitch, itemDisclosureActions: PresentationThemeItemDisclosureActions, itemCheckColors: PresentationThemeFillStrokeForeground, controlSecondaryColor: UIColor, freeInputField: PresentationInputFieldTheme, mediaPlaceholderColor: UIColor, scrollIndicatorColor: UIColor, pageIndicatorInactiveColor: UIColor, inputClearButtonColor: UIColor) {
|
||||
public init(blocksBackgroundColor: UIColor, plainBackgroundColor: UIColor, itemPrimaryTextColor: UIColor, itemSecondaryTextColor: UIColor, itemDisabledTextColor: UIColor, itemAccentColor: UIColor, itemHighlightedColor: UIColor, itemDestructiveColor: UIColor, itemPlaceholderTextColor: UIColor, itemBlocksBackgroundColor: UIColor, itemHighlightedBackgroundColor: UIColor, itemBlocksSeparatorColor: UIColor, itemPlainSeparatorColor: UIColor, disclosureArrowColor: UIColor, sectionHeaderTextColor: UIColor, freeTextColor: UIColor, freeTextErrorColor: UIColor, freeTextSuccessColor: UIColor, freeMonoIconColor: UIColor, itemSwitchColors: PresentationThemeSwitch, itemDisclosureActions: PresentationThemeItemDisclosureActions, itemCheckColors: PresentationThemeFillStrokeForeground, controlSecondaryColor: UIColor, freeInputField: PresentationInputFieldTheme, mediaPlaceholderColor: UIColor, scrollIndicatorColor: UIColor, pageIndicatorInactiveColor: UIColor, inputClearButtonColor: UIColor, itemBarChart: PresentationThemeItemBarChart) {
|
||||
self.blocksBackgroundColor = blocksBackgroundColor
|
||||
self.plainBackgroundColor = plainBackgroundColor
|
||||
self.itemPrimaryTextColor = itemPrimaryTextColor
|
||||
@ -376,6 +389,7 @@ public final class PresentationThemeList {
|
||||
self.scrollIndicatorColor = scrollIndicatorColor
|
||||
self.pageIndicatorInactiveColor = pageIndicatorInactiveColor
|
||||
self.inputClearButtonColor = inputClearButtonColor
|
||||
self.itemBarChart = itemBarChart
|
||||
}
|
||||
}
|
||||
|
||||
@ -551,6 +565,7 @@ public final class PresentationThemePartedColors {
|
||||
public let accentControlColor: UIColor
|
||||
public let mediaActiveControlColor: UIColor
|
||||
public let mediaInactiveControlColor: UIColor
|
||||
public let mediaControlInnerBackgroundColor: UIColor
|
||||
public let pendingActivityColor: UIColor
|
||||
public let fileTitleColor: UIColor
|
||||
public let fileDescriptionColor: UIColor
|
||||
@ -563,7 +578,7 @@ public final class PresentationThemePartedColors {
|
||||
public let textSelectionColor: UIColor
|
||||
public let textSelectionKnobColor: UIColor
|
||||
|
||||
public init(bubble: PresentationThemeBubbleColor, primaryTextColor: UIColor, secondaryTextColor: UIColor, linkTextColor: UIColor, linkHighlightColor: UIColor, scamColor: UIColor, textHighlightColor: UIColor, accentTextColor: UIColor, accentControlColor: UIColor, mediaActiveControlColor: UIColor, mediaInactiveControlColor: UIColor, pendingActivityColor: UIColor, fileTitleColor: UIColor, fileDescriptionColor: UIColor, fileDurationColor: UIColor, mediaPlaceholderColor: UIColor, polls: PresentationThemeChatBubblePolls, actionButtonsFillColor: PresentationThemeVariableColor, actionButtonsStrokeColor: PresentationThemeVariableColor, actionButtonsTextColor: PresentationThemeVariableColor, textSelectionColor: UIColor, textSelectionKnobColor: UIColor) {
|
||||
public init(bubble: PresentationThemeBubbleColor, primaryTextColor: UIColor, secondaryTextColor: UIColor, linkTextColor: UIColor, linkHighlightColor: UIColor, scamColor: UIColor, textHighlightColor: UIColor, accentTextColor: UIColor, accentControlColor: UIColor, mediaActiveControlColor: UIColor, mediaInactiveControlColor: UIColor, mediaControlInnerBackgroundColor: UIColor, pendingActivityColor: UIColor, fileTitleColor: UIColor, fileDescriptionColor: UIColor, fileDurationColor: UIColor, mediaPlaceholderColor: UIColor, polls: PresentationThemeChatBubblePolls, actionButtonsFillColor: PresentationThemeVariableColor, actionButtonsStrokeColor: PresentationThemeVariableColor, actionButtonsTextColor: PresentationThemeVariableColor, textSelectionColor: UIColor, textSelectionKnobColor: UIColor) {
|
||||
self.bubble = bubble
|
||||
self.primaryTextColor = primaryTextColor
|
||||
self.secondaryTextColor = secondaryTextColor
|
||||
@ -575,6 +590,7 @@ public final class PresentationThemePartedColors {
|
||||
self.accentControlColor = accentControlColor
|
||||
self.mediaActiveControlColor = mediaActiveControlColor
|
||||
self.mediaInactiveControlColor = mediaInactiveControlColor
|
||||
self.mediaControlInnerBackgroundColor = mediaControlInnerBackgroundColor
|
||||
self.pendingActivityColor = pendingActivityColor
|
||||
self.fileTitleColor = fileTitleColor
|
||||
self.fileDescriptionColor = fileDescriptionColor
|
||||
|
||||
@ -5,7 +5,12 @@ import TelegramCore
|
||||
import SyncCore
|
||||
import TelegramUIPreferences
|
||||
|
||||
private func decodeColor<Key>(_ values: KeyedDecodingContainer<Key>, _ key: Key) throws -> UIColor {
|
||||
private func decodeColor<Key>(_ values: KeyedDecodingContainer<Key>, _ key: Key, decoder: Decoder? = nil, fallbackKey: String? = nil) throws -> UIColor {
|
||||
if let decoder = decoder as? PresentationThemeDecoding, let fallbackKey = fallbackKey {
|
||||
let key = (decoder.codingPath.map { $0.stringValue } + [key.stringValue]).joined(separator: ".")
|
||||
decoder.fallbackKeys[key] = fallbackKey
|
||||
}
|
||||
|
||||
let value = try values.decode(String.self, forKey: key)
|
||||
if value.lowercased() == "clear" {
|
||||
return UIColor.clear
|
||||
@ -347,6 +352,7 @@ extension PresentationThemeRootNavigationBar: Codable {
|
||||
|
||||
public convenience init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.init(buttonColor: try decodeColor(values, .button),
|
||||
disabledButtonColor: try decodeColor(values, .disabledButton),
|
||||
primaryTextColor: try decodeColor(values, .primaryText),
|
||||
@ -358,10 +364,10 @@ extension PresentationThemeRootNavigationBar: Codable {
|
||||
badgeBackgroundColor: try decodeColor(values, .badgeFill),
|
||||
badgeStrokeColor: try decodeColor(values, .badgeStroke),
|
||||
badgeTextColor: try decodeColor(values, .badgeText),
|
||||
segmentedBackgroundColor: try decodeColor(values, .segmentedBg),
|
||||
segmentedForegroundColor: try decodeColor(values, .segmentedFg),
|
||||
segmentedTextColor: try decodeColor(values, .segmentedText),
|
||||
segmentedDividerColor: try decodeColor(values, .segmentedDivider))
|
||||
segmentedBackgroundColor: try decodeColor(values, .segmentedBg, decoder: decoder, fallbackKey: "root.searchBar.inputFill"),
|
||||
segmentedForegroundColor: try decodeColor(values, .segmentedFg, decoder: decoder, fallbackKey: "root.navBar.background"),
|
||||
segmentedTextColor: try decodeColor(values, .segmentedText, decoder: decoder, fallbackKey: "root.navBar.primaryText"),
|
||||
segmentedDividerColor: try decodeColor(values, .segmentedDivider, decoder: decoder, fallbackKey: "root.list.freeInputField.stroke"))
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -603,6 +609,29 @@ extension PresentationThemeItemDisclosureActions: Codable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension PresentationThemeItemBarChart: Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case color1
|
||||
case color2
|
||||
case color3
|
||||
}
|
||||
|
||||
public convenience init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.init(color1: try decodeColor(values, .color1),
|
||||
color2: try decodeColor(values, .color2),
|
||||
color3: try decodeColor(values, .color3))
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var values = encoder.container(keyedBy: CodingKeys.self)
|
||||
try encodeColor(&values, self.color1, .color1)
|
||||
try encodeColor(&values, self.color2, .color2)
|
||||
try encodeColor(&values, self.color3, .color3)
|
||||
}
|
||||
}
|
||||
|
||||
extension PresentationThemeFillStrokeForeground: Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case bg
|
||||
@ -683,6 +712,7 @@ extension PresentationThemeList: Codable {
|
||||
case scrollIndicator
|
||||
case pageIndicatorInactive
|
||||
case inputClearButton
|
||||
case itemBarChart
|
||||
}
|
||||
|
||||
public convenience init(from decoder: Decoder) throws {
|
||||
@ -714,7 +744,8 @@ extension PresentationThemeList: Codable {
|
||||
mediaPlaceholderColor: try decodeColor(values, .mediaPlaceholder),
|
||||
scrollIndicatorColor: try decodeColor(values, .scrollIndicator),
|
||||
pageIndicatorInactiveColor: try decodeColor(values, .pageIndicatorInactive),
|
||||
inputClearButtonColor: try decodeColor(values, .inputClearButton))
|
||||
inputClearButtonColor: try decodeColor(values, .inputClearButton),
|
||||
itemBarChart: try values.decode(PresentationThemeItemBarChart.self, forKey: .itemBarChart))
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -747,6 +778,7 @@ extension PresentationThemeList: Codable {
|
||||
try encodeColor(&values, self.scrollIndicatorColor, .scrollIndicator)
|
||||
try encodeColor(&values, self.pageIndicatorInactiveColor, .pageIndicatorInactive)
|
||||
try encodeColor(&values, self.inputClearButtonColor, .inputClearButton)
|
||||
try values.encode(self.itemBarChart, forKey: .itemBarChart)
|
||||
}
|
||||
}
|
||||
|
||||
@ -982,6 +1014,7 @@ extension PresentationThemePartedColors: Codable {
|
||||
case accentControl
|
||||
case mediaActiveControl
|
||||
case mediaInactiveControl
|
||||
case mediaControlInnerBg
|
||||
case pendingActivity
|
||||
case fileTitle
|
||||
case fileDescription
|
||||
@ -997,6 +1030,7 @@ extension PresentationThemePartedColors: Codable {
|
||||
|
||||
public convenience init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let codingPath = decoder.codingPath.map { $0.stringValue }.joined(separator: ".")
|
||||
self.init(
|
||||
bubble: try values.decode(PresentationThemeBubbleColor.self, forKey: .bubble),
|
||||
primaryTextColor: try decodeColor(values, .primaryText),
|
||||
@ -1009,6 +1043,7 @@ extension PresentationThemePartedColors: Codable {
|
||||
accentControlColor: try decodeColor(values, .accentControl),
|
||||
mediaActiveControlColor: try decodeColor(values, .mediaActiveControl),
|
||||
mediaInactiveControlColor: try decodeColor(values, .mediaInactiveControl),
|
||||
mediaControlInnerBackgroundColor: try decodeColor(values, .mediaControlInnerBg, decoder: decoder, fallbackKey: codingPath + ".bubble.withWp.bg"),
|
||||
pendingActivityColor: try decodeColor(values, .pendingActivity),
|
||||
fileTitleColor: try decodeColor(values, .fileTitle),
|
||||
fileDescriptionColor: try decodeColor(values, .fileDescription),
|
||||
@ -1036,6 +1071,7 @@ extension PresentationThemePartedColors: Codable {
|
||||
try encodeColor(&values, self.accentControlColor, .accentControl)
|
||||
try encodeColor(&values, self.mediaActiveControlColor, .mediaActiveControl)
|
||||
try encodeColor(&values, self.mediaInactiveControlColor, .mediaInactiveControl)
|
||||
try encodeColor(&values, self.mediaControlInnerBackgroundColor, .mediaControlInnerBg)
|
||||
try encodeColor(&values, self.pendingActivityColor, .pendingActivity)
|
||||
try encodeColor(&values, self.fileTitleColor, .fileTitle)
|
||||
try encodeColor(&values, self.fileDescriptionColor, .fileDescription)
|
||||
|
||||
@ -113,6 +113,23 @@ fileprivate class PresentationThemeEncoding: Encoder {
|
||||
return container
|
||||
}
|
||||
|
||||
private func dictionaryForNodes(_ nodes: [Node]) -> [String: Any] {
|
||||
var dictionary: [String: Any] = [:]
|
||||
for node in nodes {
|
||||
var value: Any?
|
||||
switch node.value {
|
||||
case let .string(string):
|
||||
value = string
|
||||
case let .subnode(subnodes):
|
||||
value = dictionaryForNodes(subnodes)
|
||||
}
|
||||
if let key = node.key {
|
||||
dictionary[key] = value
|
||||
}
|
||||
}
|
||||
return dictionary
|
||||
}
|
||||
|
||||
func entry(for codingKey: [String]) -> Any? {
|
||||
var currentNode: Node = self.data.rootNode
|
||||
for component in codingKey {
|
||||
@ -123,8 +140,8 @@ fileprivate class PresentationThemeEncoding: Encoder {
|
||||
if component == codingKey.last {
|
||||
if case let .string(string) = node.value {
|
||||
return string
|
||||
} else {
|
||||
return nil
|
||||
} else if case let .subnode(nodes) = node.value {
|
||||
return dictionaryForNodes(nodes)
|
||||
}
|
||||
} else {
|
||||
currentNode = node
|
||||
@ -404,6 +421,7 @@ class PresentationThemeDecoding: Decoder {
|
||||
var referenceTheme: PresentationTheme?
|
||||
var serviceBackgroundColor: UIColor?
|
||||
var resolvedWallpaper: TelegramWallpaper?
|
||||
var fallbackKeys: [String: String] = [:]
|
||||
|
||||
private var _referenceCoding: PresentationThemeEncoding?
|
||||
fileprivate var referenceCoding: PresentationThemeEncoding? {
|
||||
@ -510,14 +528,43 @@ fileprivate struct PresentationThemeKeyedDecodingContainer<K : CodingKey>: Keyed
|
||||
|
||||
return entry is NSNull
|
||||
}
|
||||
|
||||
public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool {
|
||||
|
||||
private func storageEntry(forKey key: [String]) -> Any? {
|
||||
if let container = self.decoder.storage.containers.first as? [String: Any] {
|
||||
func entry(container: [String: Any], forKey key: [String]) -> Any? {
|
||||
if let keyComponent = key.first, let value = container[keyComponent] {
|
||||
if key.count == 1 {
|
||||
return value
|
||||
} else if let subContainer = value as? [String: Any] {
|
||||
return entry(container: subContainer, forKey: Array(key.suffix(from: 1)))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return entry(container: container, forKey: key)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private func containerEntry(forKey key: Key) -> Any? {
|
||||
var containerEntry: Any? = self.container[key.stringValue]
|
||||
if containerEntry == nil {
|
||||
containerEntry = self.decoder.referenceCoding?.entry(for: self.codingPath.map { $0.stringValue } + [key.stringValue])
|
||||
let initialKey = self.codingPath.map { $0.stringValue } + [key.stringValue]
|
||||
let initialKeyString = initialKey.joined(separator: ".")
|
||||
if let fallbackKeyString = self.decoder.fallbackKeys[initialKeyString] {
|
||||
let fallbackKey = fallbackKeyString.components(separatedBy: ".")
|
||||
containerEntry = self.storageEntry(forKey: fallbackKey)
|
||||
}
|
||||
if containerEntry == nil {
|
||||
containerEntry = self.decoder.referenceCoding?.entry(for: initialKey)
|
||||
}
|
||||
}
|
||||
|
||||
guard let entry = containerEntry else {
|
||||
return containerEntry
|
||||
}
|
||||
|
||||
public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool {
|
||||
guard let entry = self.containerEntry(forKey: key) else {
|
||||
throw PresentationThemeDecodingError.keyNotFound
|
||||
}
|
||||
|
||||
@ -532,12 +579,7 @@ fileprivate struct PresentationThemeKeyedDecodingContainer<K : CodingKey>: Keyed
|
||||
}
|
||||
|
||||
public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 {
|
||||
var containerEntry: Any? = self.container[key.stringValue]
|
||||
if containerEntry == nil {
|
||||
containerEntry = self.decoder.referenceCoding?.entry(for: self.codingPath.map { $0.stringValue } + [key.stringValue])
|
||||
}
|
||||
|
||||
guard let entry = containerEntry else {
|
||||
guard let entry = self.containerEntry(forKey: key) else {
|
||||
throw PresentationThemeDecodingError.keyNotFound
|
||||
}
|
||||
|
||||
@ -552,12 +594,7 @@ fileprivate struct PresentationThemeKeyedDecodingContainer<K : CodingKey>: Keyed
|
||||
}
|
||||
|
||||
public func decode(_ type: String.Type, forKey key: Key) throws -> String {
|
||||
var containerEntry: Any? = self.container[key.stringValue]
|
||||
if containerEntry == nil {
|
||||
containerEntry = self.decoder.referenceCoding?.entry(for: self.codingPath.map { $0.stringValue } + [key.stringValue])
|
||||
}
|
||||
|
||||
guard let entry = containerEntry else {
|
||||
guard let entry = self.containerEntry(forKey: key) else {
|
||||
throw PresentationThemeDecodingError.keyNotFound
|
||||
}
|
||||
|
||||
@ -572,12 +609,7 @@ fileprivate struct PresentationThemeKeyedDecodingContainer<K : CodingKey>: Keyed
|
||||
}
|
||||
|
||||
public func decode<T : Decodable>(_ type: T.Type, forKey key: Key) throws -> T {
|
||||
var containerEntry: Any? = self.container[key.stringValue]
|
||||
if containerEntry == nil {
|
||||
containerEntry = self.decoder.referenceCoding?.entry(for: self.codingPath.map { $0.stringValue } + [key.stringValue])
|
||||
}
|
||||
|
||||
guard let entry = containerEntry else {
|
||||
guard let entry = self.containerEntry(forKey: key) else {
|
||||
throw PresentationThemeDecodingError.keyNotFound
|
||||
}
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ public enum PresentationResourceKey: Int32 {
|
||||
case navigationPlayerMaximizedRateActiveIcon
|
||||
case navigationPlayerMaximizedRateInactiveIcon
|
||||
|
||||
case itemListDownArrow
|
||||
case itemListDisclosureArrow
|
||||
case itemListCheckIcon
|
||||
case itemListSecondaryCheckIcon
|
||||
|
||||
@ -21,6 +21,12 @@ public func generateItemListPlusIcon(_ color: UIColor) -> UIImage? {
|
||||
}
|
||||
|
||||
public struct PresentationResourcesItemList {
|
||||
public static func downArrowImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.itemListDownArrow.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Search/DownButton"), color: theme.list.itemAccentColor)
|
||||
})
|
||||
}
|
||||
|
||||
public static func disclosureArrowImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.itemListDisclosureArrow.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Item List/DisclosureArrow"), color: theme.list.disclosureArrowColor)
|
||||
|
||||
@ -197,13 +197,13 @@ framework(
|
||||
"//submodules/AppLock:AppLock",
|
||||
"//submodules/NotificationsPresentationData:NotificationsPresentationData",
|
||||
"//submodules/UrlWhitelist:UrlWhitelist",
|
||||
"//submodules/AppIntents:AppIntents",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/CoreAudio.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/WebKit.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/Intents.framework",
|
||||
],
|
||||
weak_frameworks = [
|
||||
"Vision",
|
||||
@ -211,5 +211,6 @@ framework(
|
||||
"CallKit",
|
||||
"PassKit",
|
||||
"Contacts",
|
||||
"Intents",
|
||||
],
|
||||
)
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
},
|
||||
"properties" : {
|
||||
"provides-namespace" : true
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "vol_full@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "vol_full@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 562 B |
Binary file not shown.
|
Before Width: | Height: | Size: 538 B |
@ -1,22 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "vol_half@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "vol_half@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 553 B |
Binary file not shown.
|
Before Width: | Height: | Size: 522 B |
@ -1,22 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "vol_off@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "vol_off@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 492 B |
Binary file not shown.
|
Before Width: | Height: | Size: 500 B |
@ -33,6 +33,7 @@ import WalletCore
|
||||
import OpenSSLEncryptionProvider
|
||||
import AppLock
|
||||
import PresentationDataUtils
|
||||
import AppIntents
|
||||
|
||||
#if canImport(BackgroundTasks)
|
||||
import BackgroundTasks
|
||||
@ -179,6 +180,8 @@ final class SharedApplicationContext {
|
||||
private let authContext = Promise<UnauthorizedApplicationContext?>()
|
||||
private let authContextDisposable = MetaDisposable()
|
||||
|
||||
private let logoutDisposable = MetaDisposable()
|
||||
|
||||
private let openChatWhenReadyDisposable = MetaDisposable()
|
||||
private let openUrlWhenReadyDisposable = MetaDisposable()
|
||||
|
||||
@ -1155,7 +1158,8 @@ final class SharedApplicationContext {
|
||||
}
|
||||
|> take(1)
|
||||
|> timeout(4.0, queue: .mainQueue(), alternate: .complete())
|
||||
|> deliverOnMainQueue).start(completed: { authContextValue.rootController.view.endEditing(true)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
authContextValue.rootController.view.endEditing(true)
|
||||
authContextValue.rootController.dismiss()
|
||||
})
|
||||
} else {
|
||||
@ -1174,12 +1178,32 @@ final class SharedApplicationContext {
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
statusController.dismiss()
|
||||
self.mainWindow.present(context.rootController, on: .root) }))
|
||||
self.mainWindow.present(context.rootController, on: .root)
|
||||
}))
|
||||
} else {
|
||||
authContextReadyDisposable.set(nil)
|
||||
}
|
||||
}))
|
||||
|
||||
self.logoutDisposable.set((self.sharedContextPromise.get()
|
||||
|> take(1)
|
||||
|> mapToSignal { sharedContext -> Signal<Set<PeerId>, NoError> in
|
||||
return sharedContext.sharedContext.activeAccounts
|
||||
|> map { _, accounts, _ -> Set<PeerId> in
|
||||
return Set(accounts.map { $0.1.peerId })
|
||||
}
|
||||
|> reduceLeft(value: Set<PeerId>()) { current, updated, emit in
|
||||
if !current.isEmpty {
|
||||
emit(current.subtracting(current.intersection(updated)))
|
||||
}
|
||||
return updated
|
||||
}
|
||||
}).start(next: { loggedOutAccountPeerIds in
|
||||
for peerId in loggedOutAccountPeerIds {
|
||||
deleteAllSendMessageIntents(accountPeerId: peerId)
|
||||
}
|
||||
}))
|
||||
|
||||
self.watchCommunicationManagerPromise.set(watchCommunicationManager(context: self.context.get() |> flatMap { WatchCommunicationManagerContext(context: $0.context) }, allowBackgroundTimeExtension: { timeout in
|
||||
let _ = (self.sharedContextPromise.get()
|
||||
|> take(1)).start(next: { sharedContext in
|
||||
@ -1542,6 +1566,50 @@ final class SharedApplicationContext {
|
||||
let _ = (self.sharedContextPromise.get()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { sharedApplicationContext in
|
||||
if var encryptedPayload = payload.dictionaryPayload["p"] as? String {
|
||||
encryptedPayload = encryptedPayload.replacingOccurrences(of: "-", with: "+")
|
||||
encryptedPayload = encryptedPayload.replacingOccurrences(of: "_", with: "/")
|
||||
while encryptedPayload.count % 4 != 0 {
|
||||
encryptedPayload.append("=")
|
||||
}
|
||||
if let data = Data(base64Encoded: encryptedPayload) {
|
||||
let _ = (sharedApplicationContext.sharedContext.activeAccounts
|
||||
|> take(1)
|
||||
|> mapToSignal { activeAccounts -> Signal<[(Account, MasterNotificationKey)], NoError> in
|
||||
return combineLatest(activeAccounts.accounts.map { account -> Signal<(Account, MasterNotificationKey), NoError> in
|
||||
return masterNotificationsKey(account: account.1, ignoreDisabled: true)
|
||||
|> map { key -> (Account, MasterNotificationKey) in
|
||||
return (account.1, key)
|
||||
}
|
||||
})
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { accountsAndKeys in
|
||||
var accountAndDecryptedPayload: (Account, Data)?
|
||||
for (account, key) in accountsAndKeys {
|
||||
if let decryptedData = decryptedNotificationPayload(key: key, data: data) {
|
||||
accountAndDecryptedPayload = (account, decryptedData)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if let (account, decryptedData) = accountAndDecryptedPayload {
|
||||
if let decryptedDict = (try? JSONSerialization.jsonObject(with: decryptedData, options: [])) as? [AnyHashable: Any] {
|
||||
if var updateString = decryptedDict["updates"] as? String {
|
||||
updateString = updateString.replacingOccurrences(of: "-", with: "+")
|
||||
updateString = updateString.replacingOccurrences(of: "_", with: "/")
|
||||
while updateString.count % 4 != 0 {
|
||||
updateString.append("=")
|
||||
}
|
||||
if let updateData = Data(base64Encoded: updateString) {
|
||||
account.stateManager.processIncomingCallUpdate(data: updateData, completion: { _ in
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
sharedApplicationContext.wakeupManager.allowBackgroundTimeExtension(timeout: 2.0)
|
||||
|
||||
if case PKPushType.voIP = type {
|
||||
@ -1811,7 +1879,7 @@ final class SharedApplicationContext {
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue
|
||||
|> mapToSignal { sharedContext -> Signal<Void, NoError> in
|
||||
sharedContext.wakeupManager.allowBackgroundTimeExtension(timeout: 2.0)
|
||||
sharedContext.wakeupManager.allowBackgroundTimeExtension(timeout: 2.0, extendNow: true)
|
||||
return sharedContext.sharedContext.activeAccounts
|
||||
|> mapToSignal { _, accounts, _ -> Signal<Account, NoError> in
|
||||
for account in accounts {
|
||||
@ -1915,6 +1983,10 @@ final class SharedApplicationContext {
|
||||
var carPlayOptions = options
|
||||
carPlayOptions.insert(.allowInCarPlay)
|
||||
|
||||
//if #available(iOS 13.2, *) {
|
||||
// carPlayOptions.insert(.allowAnnouncement)
|
||||
//}
|
||||
|
||||
unknownMessageCategory = UNNotificationCategory(identifier: "unknown", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
|
||||
replyMessageCategory = UNNotificationCategory(identifier: "withReply", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: carPlayOptions)
|
||||
replyLegacyMessageCategory = UNNotificationCategory(identifier: "r", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: carPlayOptions)
|
||||
|
||||
@ -55,6 +55,7 @@ import LocalizedPeerData
|
||||
import PhoneNumberFormat
|
||||
import SettingsUI
|
||||
import UrlWhitelist
|
||||
import AppIntents
|
||||
|
||||
public enum ChatControllerPeekActions {
|
||||
case standard
|
||||
@ -1429,7 +1430,38 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Message] in
|
||||
return transaction.getMessageFailedGroup(id) ?? []
|
||||
} |> deliverOnMainQueue).start(next: { messages in
|
||||
guard let strongSelf = self, let message = messages.filter({ $0.id == id }).first else {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var groups: [UInt32: [Message]] = [:]
|
||||
var notGrouped: [Message] = []
|
||||
for message in messages {
|
||||
if let groupInfo = message.groupInfo {
|
||||
if groups[groupInfo.stableId] == nil {
|
||||
groups[groupInfo.stableId] = []
|
||||
}
|
||||
groups[groupInfo.stableId]?.append(message)
|
||||
} else {
|
||||
notGrouped.append(message)
|
||||
}
|
||||
}
|
||||
|
||||
let totalGroupCount = notGrouped.count + groups.count
|
||||
|
||||
var maybeSelectedGroup: [Message]?
|
||||
for (_, group) in groups {
|
||||
if group.contains(where: { $0.id == id}) {
|
||||
maybeSelectedGroup = group
|
||||
break
|
||||
}
|
||||
}
|
||||
for message in notGrouped {
|
||||
if message.id == id {
|
||||
maybeSelectedGroup = [message]
|
||||
}
|
||||
}
|
||||
|
||||
guard let selectedGroup = maybeSelectedGroup, let topMessage = selectedGroup.first else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -1438,12 +1470,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Resend"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { [weak self] _, f in
|
||||
if let strongSelf = self {
|
||||
let _ = resendMessages(account: strongSelf.context.account, messageIds: [id]).start()
|
||||
let _ = resendMessages(account: strongSelf.context.account, messageIds: selectedGroup.map({ $0.id })).start()
|
||||
}
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
if messages.count != 1 {
|
||||
actions.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_MessageDialogRetryAll(messages.count).0, icon: { theme in
|
||||
if totalGroupCount != 1 {
|
||||
actions.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_MessageDialogRetryAll(totalGroupCount).0, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Resend"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { [weak self] _, f in
|
||||
if let strongSelf = self {
|
||||
@ -1461,7 +1493,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
|
||||
let controller = ContextController(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, message: message)), items: .single(actions), reactionItems: [], recognizer: nil)
|
||||
let controller = ContextController(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: .extracted(ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, message: topMessage)), items: .single(actions), reactionItems: [], recognizer: nil)
|
||||
strongSelf.currentContextController = controller
|
||||
strongSelf.window?.presentInGlobalOverlay(controller)
|
||||
})
|
||||
@ -1702,7 +1734,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
})
|
||||
}, displaySwipeToReplyHint: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let strongSelf = self, let validLayout = strongSelf.validLayout, min(validLayout.size.width, validLayout.size.height) > 320.0 {
|
||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .swipeToReply(title: strongSelf.presentationData.strings.Conversation_SwipeToReplyHintTitle, text: strongSelf.presentationData.strings.Conversation_SwipeToReplyHintText), elevatedLayout: true, action: { _ in }), in: .window(.root))
|
||||
}
|
||||
}, requestMessageUpdate: { [weak self] id in
|
||||
@ -2798,7 +2830,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
})
|
||||
|
||||
strongSelf.donateSendMessageIntent()
|
||||
donateSendMessageIntent(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, peerIds: [peerId])
|
||||
}
|
||||
}
|
||||
|
||||
@ -5461,7 +5493,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if editMediaOptions != nil {
|
||||
strongSelf.editMessageMediaWithLegacySignals(signals!)
|
||||
} else {
|
||||
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime)
|
||||
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime > 0 ? scheduleTime : nil)
|
||||
}
|
||||
if !inputText.string.isEmpty {
|
||||
//strongSelf.clearInputText()
|
||||
@ -5673,6 +5705,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
legacyController.statusBar.statusBarStyle = strongSelf.presentationData.theme.rootController.statusBarStyle.style
|
||||
legacyController.controllerLoaded = { [weak legacyController] in
|
||||
legacyController?.view.disablesInteractiveTransitionGestureRecognizer = true
|
||||
legacyController?.view.disablesInteractiveModalDismiss = true
|
||||
}
|
||||
let controller = generator(legacyController.context)
|
||||
legacyController.bind(controller: controller)
|
||||
@ -5994,7 +6027,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
})
|
||||
|
||||
self.donateSendMessageIntent()
|
||||
donateSendMessageIntent(account: self.context.account, sharedContext: self.context.sharedContext, peerIds: [peerId])
|
||||
} else {
|
||||
let mode: ChatScheduleTimeControllerMode
|
||||
if peerId == self.context.account.peerId {
|
||||
@ -7772,23 +7805,22 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: self.context, peer: peer, chatPeer: peer, action: .clearCacheSuggestion, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder))
|
||||
|
||||
var presented = false
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ClearCache_FreeSpace, color: .accent, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let strongSelf = self {
|
||||
let controller = storageUsageController(context: strongSelf.context, isModal: true)
|
||||
strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
if let strongSelf = self, !presented {
|
||||
presented = true
|
||||
strongSelf.push(storageUsageController(context: strongSelf.context, isModal: true))
|
||||
}
|
||||
}))
|
||||
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
})
|
||||
])])
|
||||
self.chatDisplayNode.dismissInput()
|
||||
self.presentInGlobalOverlay(actionSheet)
|
||||
//self.present(actionSheet, in: .window(.root))
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 11.0, iOS 11.0, *)
|
||||
@ -8067,44 +8099,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
}
|
||||
|
||||
private func donateSendMessageIntent() {
|
||||
guard case let .peer(peerId) = self.chatLocation, peerId.namespace == Namespaces.Peer.CloudUser && peerId != self.context.account.peerId else {
|
||||
return
|
||||
}
|
||||
if #available(iOSApplicationExtension 13.2, iOS 13.2, *) {
|
||||
let _ = (self.context.account.postbox.loadedPeerWithId(peerId)
|
||||
|> mapToSignal { peer -> Signal<(Peer, UIImage?), NoError> in
|
||||
let avatarImage = peerAvatarImage(account: self.context.account, peer: peer, authorOfMessage: nil, representation: peer.smallProfileImage, round: false) ?? .single(nil)
|
||||
return avatarImage
|
||||
|> map { avatarImage in
|
||||
return (peer, avatarImage)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer, avatarImage in
|
||||
if let strongSelf = self, let peer = peer as? TelegramUser, peer.botInfo == nil && !peer.flags.contains(.isSupport) {
|
||||
let recipientHandle = INPersonHandle(value: "tg\(peerId.id)", type: .unknown)
|
||||
var nameComponents = PersonNameComponents()
|
||||
nameComponents.givenName = peer.firstName
|
||||
nameComponents.familyName = peer.lastName
|
||||
let displayTitle = peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)
|
||||
let recipient = INPerson(personHandle: recipientHandle, nameComponents: nameComponents, displayName: displayTitle, image: nil, contactIdentifier: nil, customIdentifier: "tg\(peerId.id)")
|
||||
let intent = INSendMessageIntent(recipients: [recipient], content: nil, speakableGroupName: INSpeakableString(spokenPhrase: displayTitle), conversationIdentifier: "tg\(peerId.id)", serviceName: nil, sender: nil)
|
||||
if #available(iOS 12.0, *), let avatarImage = avatarImage, let avatarImageData = avatarImage.jpegData(compressionQuality: 0.8) {
|
||||
intent.setImage(INImage(imageData: avatarImageData), forParameterNamed: \.groupName)
|
||||
}
|
||||
let interaction = INInteraction(intent: intent, response: nil)
|
||||
interaction.direction = .outgoing
|
||||
interaction.groupIdentifier = "sendMessage_\(strongSelf.context.account.peerId.toInt64())"
|
||||
interaction.donate { error in
|
||||
if let error = error {
|
||||
print(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private func updateReminderActivity() {
|
||||
if self.isReminderActivityEnabled && false {
|
||||
if #available(iOS 9.0, *) {
|
||||
|
||||
@ -11,13 +11,17 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
||||
}
|
||||
var entries: [ChatHistoryEntry] = []
|
||||
var adminRanks: [PeerId: CachedChannelAdminRank] = [:]
|
||||
var stickersEnabled = true
|
||||
if case let .peer(peerId) = location, peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
for additionalEntry in view.additionalData {
|
||||
if case let .cacheEntry(id, data) = additionalEntry {
|
||||
if id == cachedChannelAdminRanksEntryId(peerId: peerId), let data = data as? CachedChannelAdminRanks {
|
||||
adminRanks = data.ranks
|
||||
}
|
||||
break
|
||||
} else if case let .peer(_, peer) = additionalEntry, let channel = peer as? TelegramChannel {
|
||||
if let defaultBannedRights = channel.defaultBannedRights, defaultBannedRights.flags.contains(.banSendStickers) {
|
||||
stickersEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -42,7 +46,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
||||
|
||||
var contentTypeHint: ChatMessageEntryContentType = .generic
|
||||
if presentationData.largeEmoji, entry.message.media.isEmpty {
|
||||
if entry.message.text.count == 1, let _ = associatedData.animatedEmojiStickers[entry.message.text.basicEmoji.0] {
|
||||
if stickersEnabled && entry.message.text.count == 1, let _ = associatedData.animatedEmojiStickers[entry.message.text.basicEmoji.0] {
|
||||
contentTypeHint = .animatedEmoji
|
||||
} else if messageIsElligibleForLargeEmoji(entry.message) {
|
||||
contentTypeHint = .largeEmoji
|
||||
|
||||
@ -790,7 +790,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
return view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue
|
||||
}
|
||||
|
||||
self.presentationDataDisposable = (combineLatest(context.sharedContext.presentationData, appConfiguration)
|
||||
self.presentationDataDisposable = (
|
||||
combineLatest(queue: .mainQueue(),
|
||||
context.sharedContext.presentationData,
|
||||
appConfiguration)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData, appConfiguration in
|
||||
if let strongSelf = self {
|
||||
let previousTheme = strongSelf.currentPresentationData.theme
|
||||
|
||||
@ -96,6 +96,32 @@ final class ChatMediaInputGifPane: ChatMediaInputPane, UIScrollViewDelegate {
|
||||
let emptySize = self.emptyNode.updateLayout(size)
|
||||
transition.updateFrame(node: self.emptyNode, frame: CGRect(origin: CGPoint(x: floor(size.width - emptySize.width) / 2.0, y: topInset + floor(size.height - topInset - emptySize.height) / 2.0), size: emptySize))
|
||||
|
||||
self.updateMultiplexedNodeLayout(changedIsExpanded: changedIsExpanded, transition: transition)
|
||||
}
|
||||
|
||||
func fileAt(point: CGPoint) -> (FileMediaReference, CGRect)? {
|
||||
if let multiplexedNode = self.multiplexedNode {
|
||||
return multiplexedNode.fileAt(point: point.offsetBy(dx: -multiplexedNode.frame.minX, dy: -multiplexedNode.frame.minY))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
override var isEmpty: Bool {
|
||||
return self.multiplexedNode?.files.isEmpty ?? true
|
||||
}
|
||||
|
||||
override func willEnterHierarchy() {
|
||||
super.willEnterHierarchy()
|
||||
|
||||
self.initializeIfNeeded()
|
||||
}
|
||||
|
||||
private func updateMultiplexedNodeLayout(changedIsExpanded: Bool, transition: ContainedViewLayoutTransition) {
|
||||
guard let (size, topInset, bottomInset, isExpanded, isVisible, deviceMetrics) = self.validLayout else {
|
||||
return
|
||||
}
|
||||
|
||||
if let multiplexedNode = self.multiplexedNode {
|
||||
let previousBounds = multiplexedNode.scrollNode.layer.bounds
|
||||
multiplexedNode.topInset = topInset + 60.0
|
||||
@ -122,24 +148,6 @@ final class ChatMediaInputGifPane: ChatMediaInputPane, UIScrollViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func fileAt(point: CGPoint) -> (FileMediaReference, CGRect)? {
|
||||
if let multiplexedNode = self.multiplexedNode {
|
||||
return multiplexedNode.fileAt(point: point.offsetBy(dx: -multiplexedNode.frame.minX, dy: -multiplexedNode.frame.minY))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
override var isEmpty: Bool {
|
||||
return self.multiplexedNode?.files.isEmpty ?? true
|
||||
}
|
||||
|
||||
override func willEnterHierarchy() {
|
||||
super.willEnterHierarchy()
|
||||
|
||||
self.initializeIfNeeded()
|
||||
}
|
||||
|
||||
func initializeIfNeeded() {
|
||||
if self.multiplexedNode == nil {
|
||||
self.trendingPromise.set(paneGifSearchForQuery(account: account, query: "", updateActivity: nil))
|
||||
@ -215,6 +223,8 @@ final class ChatMediaInputGifPane: ChatMediaInputPane, UIScrollViewDelegate {
|
||||
fixListScrolling(multiplexedNode)
|
||||
}
|
||||
}
|
||||
|
||||
self.updateMultiplexedNodeLayout(changedIsExpanded: false, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -757,7 +757,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
if self.iconNode != nil {
|
||||
statusForegroundColor = presentationData.theme.chat.message.mediaOverlayControlColors.foregroundColor
|
||||
} else {
|
||||
statusForegroundColor = bubbleColorComponents(theme: presentationData.theme, incoming: incoming, wallpaper: !presentationData.wallpaper.isEmpty).fill
|
||||
statusForegroundColor = incoming ? presentationData.theme.chat.message.incoming.mediaControlInnerBackgroundColor : presentationData.theme.chat.message.outgoing.mediaControlInnerBackgroundColor
|
||||
}
|
||||
switch resourceStatus.mediaStatus {
|
||||
case var .fetchStatus(fetchStatus):
|
||||
|
||||
@ -405,10 +405,15 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
||||
}
|
||||
|
||||
if viewClassName == ChatMessageBubbleItemNode.self && self.presentationData.largeEmoji && self.message.media.isEmpty {
|
||||
if self.message.text.count == 1, let _ = self.associatedData.animatedEmojiStickers[self.message.text.basicEmoji.0] {
|
||||
viewClassName = ChatMessageAnimatedStickerItemNode.self
|
||||
} else if messageIsElligibleForLargeEmoji(self.message) {
|
||||
viewClassName = ChatMessageStickerItemNode.self
|
||||
if case let .message(_, _, _, attributes) = self.content {
|
||||
switch attributes.contentTypeHint {
|
||||
case .largeEmoji:
|
||||
viewClassName = ChatMessageStickerItemNode.self
|
||||
case .animatedEmoji:
|
||||
viewClassName = ChatMessageAnimatedStickerItemNode.self
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
||||
private var actions: ChatAvailableMessageActions?
|
||||
|
||||
private var theme: PresentationTheme
|
||||
private let peerMedia: Bool
|
||||
|
||||
private let canDeleteMessagesDisposable = MetaDisposable()
|
||||
|
||||
@ -50,8 +51,9 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
||||
}
|
||||
}
|
||||
|
||||
init(theme: PresentationTheme, strings: PresentationStrings) {
|
||||
init(theme: PresentationTheme, strings: PresentationStrings, peerMedia: Bool = false) {
|
||||
self.theme = theme
|
||||
self.peerMedia = peerMedia
|
||||
|
||||
self.deleteButton = HighlightableButtonNode()
|
||||
self.deleteButton.isEnabled = false
|
||||
@ -143,24 +145,34 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
||||
self.forwardButton.isEnabled = actions.options.contains(.forward)
|
||||
self.shareButton.isEnabled = false
|
||||
|
||||
self.deleteButton.isEnabled = true
|
||||
if self.peerMedia {
|
||||
self.deleteButton.isEnabled = !actions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty
|
||||
} else {
|
||||
self.deleteButton.isEnabled = true
|
||||
}
|
||||
self.shareButton.isEnabled = !actions.options.intersection([.forward]).isEmpty
|
||||
self.reportButton.isEnabled = !actions.options.intersection([.report]).isEmpty
|
||||
|
||||
self.deleteButton.isHidden = false
|
||||
if self.peerMedia {
|
||||
self.deleteButton.isHidden = !self.deleteButton.isEnabled
|
||||
} else {
|
||||
self.deleteButton.isHidden = false
|
||||
}
|
||||
self.reportButton.isHidden = !self.reportButton.isEnabled
|
||||
} else {
|
||||
self.deleteButton.isEnabled = false
|
||||
self.deleteButton.isHidden = false
|
||||
self.deleteButton.isHidden = self.peerMedia
|
||||
self.reportButton.isEnabled = false
|
||||
self.reportButton.isHidden = true
|
||||
self.forwardButton.isEnabled = false
|
||||
self.shareButton.isEnabled = false
|
||||
}
|
||||
|
||||
if self.reportButton.isHidden {
|
||||
if self.reportButton.isHidden || (self.peerMedia && self.deleteButton.isHidden && self.reportButton.isHidden) {
|
||||
if let peer = interfaceState.renderedPeer?.peer as? TelegramChannel, case .broadcast = peer.info {
|
||||
self.reportButton.isHidden = false
|
||||
} else if self.peerMedia {
|
||||
self.deleteButton.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -61,7 +61,9 @@ final class MultiplexedVideoNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
var files: [FileMediaReference] = [] {
|
||||
didSet {
|
||||
let startTime = CFAbsoluteTimeGetCurrent()
|
||||
self.updateVisibleItems()
|
||||
print("MultiplexedVideoNode files updateVisibleItems: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms")
|
||||
}
|
||||
}
|
||||
private var displayItems: [VisibleVideoItem] = []
|
||||
@ -219,7 +221,9 @@ final class MultiplexedVideoNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.validSize = size
|
||||
self.contextContainerNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
self.scrollNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
let startTime = CFAbsoluteTimeGetCurrent()
|
||||
self.updateVisibleItems(transition: transition)
|
||||
print("MultiplexedVideoNode layout updateVisibleItems: \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms")
|
||||
}
|
||||
}
|
||||
|
||||
@ -465,7 +469,7 @@ final class MultiplexedVideoNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
@objc func tapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||
if case .ended = recognizer.state {
|
||||
let point = recognizer.location(in: self.view)
|
||||
if let (file, rect) = self.offsetFileAt(point: point) {
|
||||
if let (file, rect) = self.fileAt(point: point) {
|
||||
self.fileSelected?(file, self, rect)
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,8 +224,6 @@ final class OverlayMediaControllerNode: ASDisplayNode, UIGestureRecognizerDelega
|
||||
}
|
||||
}
|
||||
|
||||
shouldHide = false
|
||||
|
||||
return (result, shouldHide)
|
||||
}
|
||||
|
||||
@ -323,13 +321,13 @@ final class OverlayMediaControllerNode: ASDisplayNode, UIGestureRecognizerDelega
|
||||
let translation = recognizer.translation(in: self.view)
|
||||
var nodeFrame = draggingNode.frame
|
||||
nodeFrame.origin = self.draggingStartPosition.offsetBy(dx: translation.x, dy: translation.y)
|
||||
// if nodeFrame.midX < 0.0 {
|
||||
// draggingNode.updateMinimizedEdge(.left, adjusting: true)
|
||||
// } else if nodeFrame.midX > validLayout.size.width {
|
||||
// draggingNode.updateMinimizedEdge(.right, adjusting: true)
|
||||
// } else {
|
||||
if nodeFrame.midX < 0.0 {
|
||||
draggingNode.updateMinimizedEdge(.left, adjusting: true)
|
||||
} else if nodeFrame.midX > validLayout.size.width {
|
||||
draggingNode.updateMinimizedEdge(.right, adjusting: true)
|
||||
} else {
|
||||
draggingNode.updateMinimizedEdge(nil, adjusting: true)
|
||||
// }
|
||||
}
|
||||
draggingNode.frame = nodeFrame
|
||||
}
|
||||
case .ended, .cancelled:
|
||||
@ -339,13 +337,13 @@ final class OverlayMediaControllerNode: ASDisplayNode, UIGestureRecognizerDelega
|
||||
|
||||
let (updatedLocation, shouldDismiss) = self.nodeLocationForPosition(layout: validLayout, position: CGPoint(x: previousFrame.midX, y: previousFrame.midY), velocity: recognizer.velocity(in: self.view), size: nodeSize, tempExtendedTopInset: draggingNode.tempExtendedTopInset)
|
||||
|
||||
// if shouldDismiss && draggingNode.isMinimizeable {
|
||||
// draggingNode.updateMinimizedEdge(updatedLocation.x.isZero ? .left : .right, adjusting: false)
|
||||
// self.videoNodes[index].isMinimized = true
|
||||
// } else {
|
||||
if shouldDismiss && draggingNode.isMinimizeable {
|
||||
draggingNode.updateMinimizedEdge(updatedLocation.x.isZero ? .left : .right, adjusting: false)
|
||||
self.videoNodes[index].isMinimized = true
|
||||
} else {
|
||||
draggingNode.updateMinimizedEdge(nil, adjusting: true)
|
||||
self.videoNodes[index].isMinimized = false
|
||||
// }
|
||||
}
|
||||
|
||||
if let group = draggingNode.group {
|
||||
self.locationByGroup[group] = updatedLocation
|
||||
|
||||
@ -273,7 +273,7 @@ class PeerMediaCollectionControllerNode: ASDisplayNode {
|
||||
self.addSubnode(selectionPanelBackgroundNode)
|
||||
self.selectionPanelBackgroundNode = selectionPanelBackgroundNode
|
||||
|
||||
let selectionPanel = ChatMessageSelectionInputPanelNode(theme: self.chatPresentationInterfaceState.theme, strings: self.chatPresentationInterfaceState.strings)
|
||||
let selectionPanel = ChatMessageSelectionInputPanelNode(theme: self.chatPresentationInterfaceState.theme, strings: self.chatPresentationInterfaceState.strings, peerMedia: true)
|
||||
selectionPanel.context = self.context
|
||||
selectionPanel.backgroundColor = self.presentationData.theme.chat.inputPanel.panelBackgroundColor
|
||||
selectionPanel.interfaceInteraction = self.interfaceInteraction
|
||||
|
||||
Binary file not shown.
@ -164,11 +164,12 @@ public class ShareRootControllerImpl {
|
||||
|
||||
let internalContext: InternalContext
|
||||
|
||||
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
|
||||
|
||||
if let globalInternalContext = globalInternalContext {
|
||||
internalContext = globalInternalContext
|
||||
} else {
|
||||
initializeAccountManagement()
|
||||
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
|
||||
var initialPresentationDataAndSettings: InitialPresentationDataAndSettings?
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
let systemUserInterfaceStyle: WindowUserInterfaceStyle
|
||||
@ -205,16 +206,28 @@ public class ShareRootControllerImpl {
|
||||
|
||||
Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData
|
||||
|
||||
return sharedContext.activeAccountsWithInfo
|
||||
return combineLatest(sharedContext.activeAccountsWithInfo, accountManager.transaction { transaction -> Set<AccountRecordId> in
|
||||
return Set(transaction.getRecords().map { record in
|
||||
return record.id
|
||||
})
|
||||
})
|
||||
|> castError(ShareAuthorizationError.self)
|
||||
|> take(1)
|
||||
|> mapToSignal { primary, accounts -> Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> in
|
||||
guard let primary = primary else {
|
||||
|> mapToSignal { primaryAndAccounts, validAccountIds -> Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> in
|
||||
var (maybePrimary, accounts) = primaryAndAccounts
|
||||
for i in (0 ..< accounts.count).reversed() {
|
||||
if !validAccountIds.contains(accounts[i].account.id) {
|
||||
accounts.remove(at: i)
|
||||
}
|
||||
}
|
||||
|
||||
guard let primary = maybePrimary, validAccountIds.contains(primary) else {
|
||||
return .fail(.unauthorized)
|
||||
}
|
||||
guard let info = accounts.first(where: { $0.account.id == primary }) else {
|
||||
return .fail(.unauthorized)
|
||||
}
|
||||
|
||||
return .single((sharedContext, info.account, Array(accounts)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ final class StickerPanePeerSpecificSetupGridItem: GridItem {
|
||||
self.dismiss = dismiss
|
||||
self.fillsRowWithDynamicHeight = { width in
|
||||
let makeDescriptionLayout = TextNode.asyncLayout(nil)
|
||||
let params = ListViewItemLayoutParams(width: width, leftInset: 0.0, rightInset: 0.0)
|
||||
let params = ListViewItemLayoutParams(width: width, leftInset: 0.0, rightInset: 0.0, availableHeight: 0.0)
|
||||
let leftInset: CGFloat = 12.0
|
||||
let rightInset: CGFloat = 16.0
|
||||
let (descriptionLayout, _) = makeDescriptionLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: strings.Stickers_GroupStickersHelp, font: statusFont, textColor: .black), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - leftInset - rightInset - 20.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
@ -127,7 +127,7 @@ class StickerPanePeerSpecificSetupGridItemNode: GridItemNode {
|
||||
return
|
||||
}
|
||||
|
||||
let params = ListViewItemLayoutParams(width: self.bounds.size.width, leftInset: 0.0, rightInset: 0.0)
|
||||
let params = ListViewItemLayoutParams(width: self.bounds.size.width, leftInset: 0.0, rightInset: 0.0, availableHeight: self.bounds.size.height)
|
||||
|
||||
let makeInstallLayout = TextNode.asyncLayout(self.installTextNode)
|
||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||
|
||||
@ -191,7 +191,7 @@ class StickerPaneSearchGlobalItemNode: GridItemNode {
|
||||
return
|
||||
}
|
||||
|
||||
let params = ListViewItemLayoutParams(width: self.bounds.size.width, leftInset: 0.0, rightInset: 0.0)
|
||||
let params = ListViewItemLayoutParams(width: self.bounds.size.width, leftInset: 0.0, rightInset: 0.0, availableHeight: self.bounds.height)
|
||||
|
||||
let makeInstallLayout = TextNode.asyncLayout(self.installTextNode)
|
||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||
|
||||
@ -51,7 +51,7 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti
|
||||
let string = NSMutableAttributedString(string: text, attributes: [NSAttributedString.Key.font: baseFont, NSAttributedString.Key.foregroundColor: baseColor])
|
||||
var skipEntity = false
|
||||
var underlineAllLinks = false
|
||||
if linkColor.isEqual(baseColor) {
|
||||
if linkColor.argb == baseColor.argb {
|
||||
underlineAllLinks = true
|
||||
}
|
||||
var fontAttributes: [NSRange: ChatTextFontAttributes] = [:]
|
||||
|
||||
@ -31,7 +31,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
private let effectView: UIView
|
||||
|
||||
private let animationBackgroundColor: UIColor
|
||||
|
||||
|
||||
private var originalRemainingSeconds: Int
|
||||
private var remainingSeconds: Int
|
||||
private var timer: SwiftSignalKit.Timer?
|
||||
@ -261,7 +261,12 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
let firstLayout = self.validLayout == nil
|
||||
self.validLayout = layout
|
||||
|
||||
let leftInset: CGFloat = 50.0
|
||||
var leftInset: CGFloat = 50.0
|
||||
if let animationNode = self.animationNode, let iconSize = animationNode.preferredSize() {
|
||||
if iconSize.width > leftInset {
|
||||
leftInset = iconSize.width - 8.0
|
||||
}
|
||||
}
|
||||
let rightInset: CGFloat = 16.0
|
||||
var contentHeight: CGFloat = 20.0
|
||||
|
||||
|
||||
Binary file not shown.
@ -78,7 +78,7 @@ class WalletAmountItemNode: ListViewItemNode, UITextFieldDelegate, ItemListItemN
|
||||
private let measureNode: TextNode
|
||||
|
||||
private var item: WalletAmountItem?
|
||||
private var validLayout: (CGFloat, CGFloat, CGFloat)?
|
||||
private var validLayout: (CGFloat, CGFloat, CGFloat, CGFloat)?
|
||||
|
||||
var tag: ItemListItemTag? {
|
||||
return self.item?.tag
|
||||
@ -166,7 +166,7 @@ class WalletAmountItemNode: ListViewItemNode, UITextFieldDelegate, ItemListItemN
|
||||
return
|
||||
}
|
||||
let makeInputFieldLayout = self.inputFieldAsyncLayout()
|
||||
let (_, _, inputFieldApply) = makeInputFieldLayout(item, ListViewItemLayoutParams(width: validLayout.0, leftInset: validLayout.1, rightInset: validLayout.2))
|
||||
let (_, _, inputFieldApply) = makeInputFieldLayout(item, ListViewItemLayoutParams(width: validLayout.0, leftInset: validLayout.1, rightInset: validLayout.2, availableHeight: validLayout.3))
|
||||
inputFieldApply()
|
||||
}
|
||||
|
||||
@ -196,7 +196,7 @@ class WalletAmountItemNode: ListViewItemNode, UITextFieldDelegate, ItemListItemN
|
||||
return (layout, { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.item = item
|
||||
strongSelf.validLayout = (params.width, params.leftInset, params.rightInset)
|
||||
strongSelf.validLayout = (params.width, params.leftInset, params.rightInset, params.availableHeight)
|
||||
|
||||
if let _ = updatedTheme {
|
||||
strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
|
||||
|
||||
@ -216,7 +216,7 @@ func walletCreateInvoiceScreen(context: WalletContext, address: String) -> ViewC
|
||||
}
|
||||
return state
|
||||
}
|
||||
ensureItemVisibleImpl?(tag, false)
|
||||
ensureItemVisibleImpl?(tag, true)
|
||||
}, dismissInput: {
|
||||
dismissInputImpl?()
|
||||
}, scrollToBottom: {
|
||||
|
||||
@ -118,21 +118,16 @@ final class WalletInfoEmptyItemNode: ListViewItemNode {
|
||||
}
|
||||
|
||||
func asyncLayout() -> (_ item: WalletInfoEmptyItem, _ params: ListViewItemLayoutParams) -> (ListViewItemNodeLayout, () -> Void) {
|
||||
let sideInset: CGFloat = 32.0
|
||||
let buttonSideInset: CGFloat = 48.0
|
||||
let iconSpacing: CGFloat = 5.0
|
||||
let titleSpacing: CGFloat = 19.0
|
||||
let termsSpacing: CGFloat = 11.0
|
||||
let buttonHeight: CGFloat = 50.0
|
||||
|
||||
let iconSize = CGSize(width: 140.0, height: 140.0)
|
||||
self.animationNode.updateLayout(size: iconSize)
|
||||
|
||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||
let makeTextLayout = TextNode.asyncLayout(self.textNode)
|
||||
let makeAddressLayout = TextNode.asyncLayout(self.addressNode)
|
||||
|
||||
return { [weak self] item, params in
|
||||
var iconSpacing: CGFloat = 5.0
|
||||
var titleSpacing: CGFloat = 19.0
|
||||
var iconSize = CGSize(width: 140.0, height: 140.0)
|
||||
let contentVerticalOrigin: CGFloat = 10.0
|
||||
|
||||
let sideInset: CGFloat = 16.0
|
||||
var iconOffset = CGPoint()
|
||||
|
||||
@ -149,14 +144,25 @@ final class WalletInfoEmptyItemNode: ListViewItemNode {
|
||||
addressString.insert("\n", at: addressString.index(addressString.startIndex, offsetBy: addressString.count / 2))
|
||||
let (addressLayout, addressApply) = makeAddressLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: addressString, font: Font.monospace(16.0), textColor: textColor), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - sideInset * 2.0, height: .greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.1, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let contentVerticalOrigin: CGFloat = 32.0
|
||||
let availableHeight = params.availableHeight - contentVerticalOrigin * 2.0
|
||||
|
||||
let rawContentHeight: CGFloat = iconSize.height + titleLayout.size.height + textLayout.size.height + addressLayout.size.height
|
||||
let contentSpacing = iconSpacing + titleSpacing + titleSpacing
|
||||
let contentSpacingFactor = max(0.2, min(1.0, (availableHeight - rawContentHeight) / contentSpacing))
|
||||
|
||||
if contentSpacingFactor < 0.25 {
|
||||
iconSize = CGSize(width: 90.0, height: 90.0)
|
||||
}
|
||||
|
||||
iconSpacing = floor(iconSpacing * contentSpacingFactor)
|
||||
titleSpacing = floor(titleSpacing * contentSpacingFactor)
|
||||
|
||||
let iconFrame = CGRect(origin: CGPoint(x: floor((params.width - iconSize.width) / 2.0), y: contentVerticalOrigin), size: iconSize).offsetBy(dx: iconOffset.x, dy: iconOffset.y)
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((params.width - titleLayout.size.width) / 2.0), y: iconFrame.maxY + iconSpacing), size: titleLayout.size)
|
||||
let textFrame = CGRect(origin: CGPoint(x: floor((params.width - textLayout.size.width) / 2.0), y: titleFrame.maxY + titleSpacing), size: textLayout.size)
|
||||
let addressFrame = CGRect(origin: CGPoint(x: floor((params.width - addressLayout.size.width) / 2.0), y: textFrame.maxY + titleSpacing), size: addressLayout.size)
|
||||
|
||||
let layout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: (item.loading ? iconFrame.maxY : addressFrame.maxY) + 32.0), insets: UIEdgeInsets())
|
||||
let layout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: (item.loading ? iconFrame.maxY : addressFrame.maxY) + contentVerticalOrigin), insets: UIEdgeInsets())
|
||||
|
||||
return (layout, {
|
||||
guard let strongSelf = self else {
|
||||
@ -179,6 +185,8 @@ final class WalletInfoEmptyItemNode: ListViewItemNode {
|
||||
|
||||
strongSelf.item = item
|
||||
|
||||
strongSelf.animationNode.updateLayout(size: iconSize)
|
||||
|
||||
strongSelf.offsetContainer.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||
|
||||
let _ = titleApply()
|
||||
|
||||
@ -1117,6 +1117,10 @@ private final class WalletApplicationSplashScreenNode: ASDisplayNode {
|
||||
private let headerBackgroundNode: ASDisplayNode
|
||||
private let headerCornerNode: ASImageNode
|
||||
|
||||
private var isDismissed = false
|
||||
|
||||
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
||||
|
||||
init(theme: WalletTheme) {
|
||||
self.headerBackgroundNode = ASDisplayNode()
|
||||
self.headerBackgroundNode.backgroundColor = .black
|
||||
@ -1141,11 +1145,32 @@ private final class WalletApplicationSplashScreenNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
if self.isDismissed {
|
||||
return
|
||||
}
|
||||
self.validLayout = (layout, navigationHeight)
|
||||
|
||||
let headerHeight = navigationHeight + 260.0
|
||||
|
||||
transition.updateFrame(node: self.headerBackgroundNode, frame: CGRect(origin: CGPoint(x: -1.0, y: 0), size: CGSize(width: layout.size.width + 2.0, height: headerHeight)))
|
||||
transition.updateFrame(node: self.headerCornerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: headerHeight), size: CGSize(width: layout.size.width, height: 10.0)))
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
guard let (layout, navigationHeight) = self.validLayout else {
|
||||
completion()
|
||||
return
|
||||
}
|
||||
self.isDismissed = true
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.4, curve: .spring)
|
||||
|
||||
let headerHeight = navigationHeight + 260.0
|
||||
|
||||
transition.updateFrame(node: self.headerBackgroundNode, frame: CGRect(origin: CGPoint(x: -1.0, y: -headerHeight - 10.0), size: CGSize(width: layout.size.width + 2.0, height: headerHeight)), completion: { _ in
|
||||
completion()
|
||||
})
|
||||
transition.updateFrame(node: self.headerCornerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -10.0), size: CGSize(width: layout.size.width, height: 10.0)))
|
||||
}
|
||||
}
|
||||
|
||||
public final class WalletApplicationSplashScreen: ViewController {
|
||||
@ -1174,4 +1199,9 @@ public final class WalletApplicationSplashScreen: ViewController {
|
||||
|
||||
(self.displayNode as! WalletApplicationSplashScreenNode).containerLayoutUpdated(layout: layout, navigationHeight: self.navigationHeight, transition: transition)
|
||||
}
|
||||
|
||||
public func animateOut(completion: @escaping () -> Void) {
|
||||
self.statusBar.statusBarStyle = .Black
|
||||
(self.displayNode as! WalletApplicationSplashScreenNode).animateOut(completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
case address(WalletTheme, String, String)
|
||||
case addressInfo(WalletTheme, String)
|
||||
case commentHeader(WalletTheme, String)
|
||||
case comment(WalletTheme, String, String)
|
||||
case comment(WalletTheme, String, String, Bool)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
@ -131,8 +131,8 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .comment(lhsTheme, lhsPlaceholder, lhsText):
|
||||
if case let .comment(rhsTheme, rhsPlaceholder, rhsText) = rhs, lhsTheme === rhsTheme, lhsPlaceholder == rhsPlaceholder, lhsText == rhsText {
|
||||
case let .comment(lhsTheme, lhsPlaceholder, lhsText, lhsSendEnabled):
|
||||
if case let .comment(rhsTheme, rhsPlaceholder, rhsText, rhsSendEnabled) = rhs, lhsTheme === rhsTheme, lhsPlaceholder == rhsPlaceholder, lhsText == rhsText, lhsSendEnabled == rhsSendEnabled {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -245,7 +245,7 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
return ItemListTextItem(theme: theme, text: .markdown(text), sectionId: self.section)
|
||||
case let .commentHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
|
||||
case let .comment(theme, placeholder, value):
|
||||
case let .comment(theme, placeholder, value, sendEnabled):
|
||||
return ItemListMultilineInputItem(theme: theme, text: value, placeholder: placeholder, maxLength: ItemListMultilineInputItemTextLimit(value: walletTextLimit, display: true, mode: .bytes), sectionId: self.section, style: .blocks, returnKeyType: .send, textUpdated: { text in
|
||||
arguments.updateText(WalletSendScreenEntryTag.comment, text)
|
||||
}, updatedFocus: { focus in
|
||||
@ -253,7 +253,9 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
arguments.scrollToBottom()
|
||||
}
|
||||
}, tag: WalletSendScreenEntryTag.comment, action: {
|
||||
arguments.proceed()
|
||||
if sendEnabled {
|
||||
arguments.proceed()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -265,7 +267,7 @@ private struct WalletSendScreenState: Equatable {
|
||||
var comment: String
|
||||
}
|
||||
|
||||
private func walletSendScreenEntries(presentationData: WalletPresentationData, balance: Int64?, state: WalletSendScreenState) -> [WalletSendScreenEntry] {
|
||||
private func walletSendScreenEntries(presentationData: WalletPresentationData, balance: Int64?, state: WalletSendScreenState, sendEnabled: Bool) -> [WalletSendScreenEntry] {
|
||||
if balance == nil {
|
||||
return []
|
||||
}
|
||||
@ -281,7 +283,7 @@ private func walletSendScreenEntries(presentationData: WalletPresentationData, b
|
||||
entries.append(.addressInfo(presentationData.theme, presentationData.strings.Wallet_Send_AddressInfo))
|
||||
|
||||
entries.append(.commentHeader(presentationData.theme, presentationData.strings.Wallet_Receive_CommentHeader))
|
||||
entries.append(.comment(presentationData.theme, presentationData.strings.Wallet_Receive_CommentInfo, state.comment))
|
||||
entries.append(.comment(presentationData.theme, presentationData.strings.Wallet_Receive_CommentInfo, state.comment, sendEnabled))
|
||||
return entries
|
||||
}
|
||||
|
||||
@ -374,6 +376,10 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
let presentationData = context.presentationData
|
||||
let state = stateValue.with { $0 }
|
||||
let amount = amountValue(state.amount)
|
||||
guard amount > 0 else {
|
||||
return
|
||||
}
|
||||
|
||||
let commentData = state.comment.data(using: .utf8)
|
||||
let formattedAddress = String(state.address[state.address.startIndex..<state.address.index(state.address.startIndex, offsetBy: walletAddressLength / 2)] + " \n " + state.address[state.address.index(state.address.startIndex, offsetBy: walletAddressLength / 2)..<state.address.endIndex])
|
||||
let destinationAddress = state.address
|
||||
@ -571,7 +577,7 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
}
|
||||
|
||||
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Wallet_Send_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Wallet_Navigation_Back), animateChanges: false)
|
||||
let listState = ItemListNodeState(entries: walletSendScreenEntries(presentationData: presentationData, balance: walletState?.balance, state: state), style: .blocks, focusItemTag: focusItemTag, emptyStateItem: emptyItem, animateChanges: false)
|
||||
let listState = ItemListNodeState(entries: walletSendScreenEntries(presentationData: presentationData, balance: walletState?.balance, state: state, sendEnabled: sendEnabled), style: .blocks, focusItemTag: focusItemTag, emptyStateItem: emptyItem, animateChanges: false)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
||||
@ -187,267 +187,267 @@ public final class WalletStrings: Equatable {
|
||||
private let _s: [Int: String]
|
||||
private let _r: [Int: [(Int, NSRange)]]
|
||||
private let _ps: [Int: String]
|
||||
public var Wallet_Created_ExportErrorText: String { return self._s[0]! }
|
||||
public var Wallet_Send_ConfirmationConfirm: String { return self._s[2]! }
|
||||
public var Wallet_Month_GenJuly: String { return self._s[3]! }
|
||||
public var Wallet_Month_GenDecember: String { return self._s[4]! }
|
||||
public var Wallet_Month_ShortJanuary: String { return self._s[5]! }
|
||||
public var Wallet_WordCheck_Title: String { return self._s[6]! }
|
||||
public var Wallet_Month_ShortMarch: String { return self._s[7]! }
|
||||
public var Wallet_Month_GenSeptember: String { return self._s[8]! }
|
||||
public var Wallet_Info_Address: String { return self._s[9]! }
|
||||
public var Wallet_RestoreFailed_CreateWallet: String { return self._s[10]! }
|
||||
public var Wallet_Intro_NotNow: String { return self._s[11]! }
|
||||
public var Wallet_AccessDenied_Camera: String { return self._s[12]! }
|
||||
public var Wallet_TransactionInfo_StorageFeeInfo: String { return self._s[13]! }
|
||||
public var Wallet_Receive_ShareAddress: String { return self._s[14]! }
|
||||
public var Wallet_Sent_ViewWallet: String { return self._s[15]! }
|
||||
public var Wallet_Send_OwnAddressAlertTitle: String { return self._s[16]! }
|
||||
public var Wallet_Completed_Text: String { return self._s[17]! }
|
||||
public func Wallet_Updated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[18]!, self._r[18]!, [_0])
|
||||
public var Wallet_Updated_JustNow: String { return self._s[0]! }
|
||||
public var Wallet_WordCheck_IncorrectText: String { return self._s[1]! }
|
||||
public var Wallet_Month_ShortNovember: String { return self._s[2]! }
|
||||
public var Wallet_Configuration_BlockchainIdPlaceholder: String { return self._s[3]! }
|
||||
public var Wallet_Info_Send: String { return self._s[4]! }
|
||||
public var Wallet_TransactionInfo_SendGrams: String { return self._s[5]! }
|
||||
public func Wallet_Info_TransactionBlockchainFee(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[6]!, self._r[6]!, [_0])
|
||||
}
|
||||
public var Wallet_Receive_AmountText: String { return self._s[19]! }
|
||||
public var Wallet_TransactionInfo_CommentHeader: String { return self._s[20]! }
|
||||
public func Wallet_Sent_Text(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[21]!, self._r[21]!, [_0])
|
||||
}
|
||||
public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[22]! }
|
||||
public var Wallet_SecureStorageReset_Title: String { return self._s[23]! }
|
||||
public var Wallet_Configuration_ApplyErrorTextURLInvalidData: String { return self._s[24]! }
|
||||
public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[25]! }
|
||||
public var Wallet_Month_GenApril: String { return self._s[26]! }
|
||||
public var Wallet_AccessDenied_Settings: String { return self._s[27]! }
|
||||
public var Wallet_Configuration_BlockchainIdPlaceholder: String { return self._s[28]! }
|
||||
public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[29]! }
|
||||
public var Wallet_Qr_Title: String { return self._s[30]! }
|
||||
public var Wallet_Intro_ImportExisting: String { return self._s[31]! }
|
||||
public var Wallet_Send_OwnAddressAlertText: String { return self._s[32]! }
|
||||
public var Wallet_Month_GenAugust: String { return self._s[33]! }
|
||||
public var Wallet_Month_ShortDecember: String { return self._s[34]! }
|
||||
public var Wallet_Info_Receive: String { return self._s[35]! }
|
||||
public var Wallet_Send_Send: String { return self._s[36]! }
|
||||
public var Wallet_RestoreFailed_Text: String { return self._s[37]! }
|
||||
public var Wallet_Navigation_Cancel: String { return self._s[38]! }
|
||||
public var Wallet_CreateInvoice_Title: String { return self._s[39]! }
|
||||
public var Wallet_Sent_Title: String { return self._s[40]! }
|
||||
public var Wallet_WordCheck_Continue: String { return self._s[41]! }
|
||||
public var Wallet_Send_SyncInProgress: String { return self._s[43]! }
|
||||
public func Wallet_Send_Balance(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[44]!, self._r[44]!, [_0])
|
||||
}
|
||||
public var Wallet_Month_GenMay: String { return self._s[45]! }
|
||||
public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[46]! }
|
||||
public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[47]! }
|
||||
public var Wallet_Receive_AddressHeader: String { return self._s[48]! }
|
||||
public var Wallet_Settings_BackupWallet: String { return self._s[50]! }
|
||||
public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[51]! }
|
||||
public var Wallet_Info_Send: String { return self._s[52]! }
|
||||
public var Wallet_Intro_Title: String { return self._s[53]! }
|
||||
public var Wallet_Receive_Title: String { return self._s[54]! }
|
||||
public var Wallet_Configuration_SourceHeader: String { return self._s[55]! }
|
||||
public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[56]! }
|
||||
public var Wallet_Alert_OK: String { return self._s[57]! }
|
||||
public var Wallet_Send_NetworkErrorText: String { return self._s[58]! }
|
||||
public var Wallet_Receive_CommentInfo: String { return self._s[59]! }
|
||||
public var Wallet_TransactionInfo_Title: String { return self._s[60]! }
|
||||
public var Wallet_TransactionInfo_OtherFeeHeader: String { return self._s[61]! }
|
||||
public var Wallet_Completed_Title: String { return self._s[62]! }
|
||||
public var Wallet_Info_YourBalance: String { return self._s[63]! }
|
||||
public var Wallet_Configuration_Title: String { return self._s[64]! }
|
||||
public func Wallet_Info_TransactionDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[65]!, self._r[65]!, [_1, _2, _3])
|
||||
}
|
||||
public func Wallet_SecureStorageReset_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[66]!, self._r[66]!, [_0])
|
||||
}
|
||||
public var Wallet_Month_ShortJune: String { return self._s[67]! }
|
||||
public var Wallet_ContextMenuCopy: String { return self._s[68]! }
|
||||
public var Wallet_WordCheck_ViewWords: String { return self._s[69]! }
|
||||
public var Wallet_Send_Title: String { return self._s[70]! }
|
||||
public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[71]! }
|
||||
public var Wallet_WordImport_IncorrectText: String { return self._s[72]! }
|
||||
public var Wallet_Weekday_Yesterday: String { return self._s[73]! }
|
||||
public var Wallet_Send_AddressInfo: String { return self._s[74]! }
|
||||
public var Wallet_UnknownError: String { return self._s[75]! }
|
||||
public var Wallet_Receive_CopyAddress: String { return self._s[76]! }
|
||||
public var Wallet_Month_ShortFebruary: String { return self._s[77]! }
|
||||
public var Wallet_Intro_CreateWallet: String { return self._s[78]! }
|
||||
public var Wallet_Created_ExportErrorTitle: String { return self._s[80]! }
|
||||
public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[81]! }
|
||||
public var Wallet_Info_TransactionFrom: String { return self._s[82]! }
|
||||
public var Wallet_Month_ShortNovember: String { return self._s[83]! }
|
||||
public var Wallet_Month_ShortSeptember: String { return self._s[84]! }
|
||||
public var Wallet_Sent_Title: String { return self._s[7]! }
|
||||
public var Wallet_Receive_ShareUrlInfo: String { return self._s[8]! }
|
||||
public var Wallet_RestoreFailed_Title: String { return self._s[9]! }
|
||||
public var Wallet_TransactionInfo_CopyAddress: String { return self._s[11]! }
|
||||
public var Wallet_Settings_BackupWallet: String { return self._s[12]! }
|
||||
public var Wallet_Send_NetworkErrorTitle: String { return self._s[13]! }
|
||||
public var Wallet_Month_ShortJune: String { return self._s[14]! }
|
||||
public var Wallet_TransactionInfo_StorageFeeInfo: String { return self._s[15]! }
|
||||
public var Wallet_Created_Title: String { return self._s[16]! }
|
||||
public func Wallet_Configuration_ApplyErrorTextURLUnreachable(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[85]!, self._r[85]!, [_0])
|
||||
return formatWithArgumentRanges(self._s[17]!, self._r[17]!, [_0])
|
||||
}
|
||||
public func Wallet_Updated_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
public var Wallet_Send_SyncInProgress: String { return self._s[18]! }
|
||||
public var Wallet_Info_YourBalance: String { return self._s[19]! }
|
||||
public var Wallet_Configuration_ApplyErrorTextURLInvalidData: String { return self._s[20]! }
|
||||
public var Wallet_TransactionInfo_CommentHeader: String { return self._s[21]! }
|
||||
public var Wallet_TransactionInfo_OtherFeeHeader: String { return self._s[22]! }
|
||||
public func Wallet_Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[23]!, self._r[23]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Settings_ConfigurationInfo: String { return self._s[24]! }
|
||||
public var Wallet_WordImport_IncorrectText: String { return self._s[25]! }
|
||||
public var Wallet_Month_GenJanuary: String { return self._s[26]! }
|
||||
public var Wallet_Send_OwnAddressAlertTitle: String { return self._s[27]! }
|
||||
public var Wallet_Receive_ShareAddress: String { return self._s[28]! }
|
||||
public var Wallet_WordImport_Title: String { return self._s[29]! }
|
||||
public var Wallet_TransactionInfo_Title: String { return self._s[30]! }
|
||||
public var Wallet_Words_NotDoneText: String { return self._s[32]! }
|
||||
public var Wallet_RestoreFailed_EnterWords: String { return self._s[33]! }
|
||||
public var Wallet_WordImport_Text: String { return self._s[34]! }
|
||||
public var Wallet_RestoreFailed_Text: String { return self._s[36]! }
|
||||
public var Wallet_TransactionInfo_NoAddress: String { return self._s[37]! }
|
||||
public var Wallet_Navigation_Back: String { return self._s[38]! }
|
||||
public var Wallet_Intro_Terms: String { return self._s[39]! }
|
||||
public func Wallet_Send_Balance(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[40]!, self._r[40]!, [_0])
|
||||
}
|
||||
public func Wallet_Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[41]!, self._r[41]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_TransactionInfo_AddressCopied: String { return self._s[42]! }
|
||||
public func Wallet_Info_TransactionDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[43]!, self._r[43]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Send_NetworkErrorText: String { return self._s[44]! }
|
||||
public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[45]! }
|
||||
public var Wallet_Intro_ImportExisting: String { return self._s[46]! }
|
||||
public var Wallet_Receive_CommentInfo: String { return self._s[47]! }
|
||||
public var Wallet_WordCheck_Continue: String { return self._s[48]! }
|
||||
public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[49]! }
|
||||
public var Wallet_Completed_Text: String { return self._s[50]! }
|
||||
public var Wallet_WordCheck_IncorrectHeader: String { return self._s[52]! }
|
||||
public var Wallet_Configuration_SourceHeader: String { return self._s[53]! }
|
||||
public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[54]! }
|
||||
public var Wallet_Receive_Title: String { return self._s[55]! }
|
||||
public var Wallet_Info_WalletCreated: String { return self._s[56]! }
|
||||
public var Wallet_Navigation_Cancel: String { return self._s[57]! }
|
||||
public var Wallet_CreateInvoice_Title: String { return self._s[58]! }
|
||||
public func Wallet_WordCheck_Text(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[59]!, self._r[59]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_TransactionInfo_SenderHeader: String { return self._s[60]! }
|
||||
public func Wallet_Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[61]!, self._r[61]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Month_GenAugust: String { return self._s[62]! }
|
||||
public var Wallet_Info_UnknownTransaction: String { return self._s[63]! }
|
||||
public var Wallet_Receive_CreateInvoice: String { return self._s[64]! }
|
||||
public var Wallet_Month_GenSeptember: String { return self._s[65]! }
|
||||
public var Wallet_Month_GenJuly: String { return self._s[66]! }
|
||||
public var Wallet_Receive_AddressHeader: String { return self._s[67]! }
|
||||
public var Wallet_Send_AmountText: String { return self._s[68]! }
|
||||
public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[69]! }
|
||||
public func Wallet_Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[70]!, self._r[70]!, [_1, _2, _3])
|
||||
}
|
||||
public func Wallet_Updated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[71]!, self._r[71]!, [_0])
|
||||
}
|
||||
public var Wallet_Configuration_Title: String { return self._s[73]! }
|
||||
public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[74]! }
|
||||
public var Wallet_Words_Title: String { return self._s[75]! }
|
||||
public var Wallet_Month_ShortMay: String { return self._s[76]! }
|
||||
public var Wallet_WordCheck_Title: String { return self._s[77]! }
|
||||
public var Wallet_Words_NotDoneResponse: String { return self._s[78]! }
|
||||
public var Wallet_Configuration_SourceURL: String { return self._s[79]! }
|
||||
public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[80]! }
|
||||
public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[81]! }
|
||||
public func Wallet_Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[82]!, self._r[82]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Info_Address: String { return self._s[83]! }
|
||||
public var Wallet_Intro_CreateWallet: String { return self._s[84]! }
|
||||
public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[85]! }
|
||||
public func Wallet_SecureStorageReset_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[86]!, self._r[86]!, [_0])
|
||||
}
|
||||
public var Wallet_Send_AmountText: String { return self._s[87]! }
|
||||
public var Wallet_Info_TransactionTo: String { return self._s[88]! }
|
||||
public var Wallet_Words_Done: String { return self._s[89]! }
|
||||
public var Wallet_Created_Text: String { return self._s[90]! }
|
||||
public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[91]! }
|
||||
public var Wallet_Month_ShortJuly: String { return self._s[92]! }
|
||||
public func Wallet_Receive_ShareInvoiceUrlInfo(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[93]!, self._r[93]!, [_0])
|
||||
public var Wallet_Send_SendAnyway: String { return self._s[87]! }
|
||||
public var Wallet_UnknownError: String { return self._s[88]! }
|
||||
public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[89]! }
|
||||
public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[90]! }
|
||||
public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[92]! }
|
||||
public var Wallet_Configuration_SourceInfo: String { return self._s[93]! }
|
||||
public var Wallet_Words_NotDoneOk: String { return self._s[94]! }
|
||||
public var Wallet_Intro_Title: String { return self._s[95]! }
|
||||
public var Wallet_Info_Receive: String { return self._s[96]! }
|
||||
public var Wallet_Completed_ViewWallet: String { return self._s[97]! }
|
||||
public var Wallet_Month_ShortJuly: String { return self._s[98]! }
|
||||
public var Wallet_Month_ShortApril: String { return self._s[99]! }
|
||||
public func Wallet_Info_TransactionDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[100]!, self._r[100]!, [_1, _2])
|
||||
}
|
||||
public var Wallet_Created_Title: String { return self._s[94]! }
|
||||
public func Wallet_Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[95]!, self._r[95]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Info_RefreshErrorTitle: String { return self._s[96]! }
|
||||
public var Wallet_Info_ReceiveGrams: String { return self._s[97]! }
|
||||
public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[98]! }
|
||||
public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[99]! }
|
||||
public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[100]! }
|
||||
public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[101]! }
|
||||
public func Wallet_Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[101]! }
|
||||
public func Wallet_Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[102]!, self._r[102]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[103]! }
|
||||
public var Wallet_Send_UninitializedText: String { return self._s[104]! }
|
||||
public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[105]! }
|
||||
public var Wallet_Send_ErrorInvalidAddress: String { return self._s[106]! }
|
||||
public var Wallet_Words_NotDoneTitle: String { return self._s[107]! }
|
||||
public var Wallet_Navigation_Back: String { return self._s[108]! }
|
||||
public func Wallet_Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[109]!, self._r[109]!, [_1, _2, _3])
|
||||
public func Wallet_Sent_Text(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[105]!, self._r[105]!, [_0])
|
||||
}
|
||||
public var Wallet_Info_UnknownTransaction: String { return self._s[110]! }
|
||||
public var Wallet_RestoreFailed_Title: String { return self._s[111]! }
|
||||
public func Wallet_Updated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[112]!, self._r[112]!, [_0])
|
||||
}
|
||||
public var Wallet_TransactionInfo_CopyAddress: String { return self._s[113]! }
|
||||
public var Wallet_Navigation_Done: String { return self._s[114]! }
|
||||
public var Wallet_Send_UninitializedTitle: String { return self._s[115]! }
|
||||
public var Wallet_Send_AddressHeader: String { return self._s[117]! }
|
||||
public func Wallet_WordCheck_Text(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[118]!, self._r[118]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Alert_Cancel: String { return self._s[119]! }
|
||||
public var Wallet_Send_NetworkErrorTitle: String { return self._s[120]! }
|
||||
public var Wallet_Configuration_SourceInfo: String { return self._s[121]! }
|
||||
public var Wallet_Month_ShortAugust: String { return self._s[122]! }
|
||||
public var Wallet_Words_NotDoneResponse: String { return self._s[123]! }
|
||||
public var Wallet_WordCheck_TryAgain: String { return self._s[124]! }
|
||||
public func Wallet_Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[125]!, self._r[125]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Words_Text: String { return self._s[126]! }
|
||||
public var Wallet_Month_GenNovember: String { return self._s[106]! }
|
||||
public func Wallet_Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[127]!, self._r[127]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[107]!, self._r[107]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Month_ShortOctober: String { return self._s[128]! }
|
||||
public var Wallet_Created_Proceed: String { return self._s[129]! }
|
||||
public var Wallet_Month_GenApril: String { return self._s[108]! }
|
||||
public var Wallet_Month_ShortMarch: String { return self._s[109]! }
|
||||
public var Wallet_Month_GenFebruary: String { return self._s[110]! }
|
||||
public var Wallet_Qr_ScanCode: String { return self._s[111]! }
|
||||
public var Wallet_Receive_AddressCopied: String { return self._s[112]! }
|
||||
public var Wallet_Send_UninitializedTitle: String { return self._s[113]! }
|
||||
public var Wallet_AccessDenied_Title: String { return self._s[114]! }
|
||||
public var Wallet_AccessDenied_Settings: String { return self._s[115]! }
|
||||
public var Wallet_Send_Send: String { return self._s[116]! }
|
||||
public var Wallet_Info_RefreshErrorTitle: String { return self._s[117]! }
|
||||
public var Wallet_Month_GenJune: String { return self._s[118]! }
|
||||
public var Wallet_Send_AddressHeader: String { return self._s[119]! }
|
||||
public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[120]! }
|
||||
public var Wallet_Send_Confirmation: String { return self._s[121]! }
|
||||
public var Wallet_Completed_Title: String { return self._s[122]! }
|
||||
public var Wallet_Alert_OK: String { return self._s[123]! }
|
||||
public var Wallet_Settings_DeleteWallet: String { return self._s[124]! }
|
||||
public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[125]! }
|
||||
public var Wallet_Month_ShortSeptember: String { return self._s[126]! }
|
||||
public var Wallet_Info_TransactionTo: String { return self._s[127]! }
|
||||
public var Wallet_Send_ConfirmationConfirm: String { return self._s[128]! }
|
||||
public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[129]! }
|
||||
public var Wallet_Receive_AmountText: String { return self._s[130]! }
|
||||
public var Wallet_Receive_CopyAddress: String { return self._s[131]! }
|
||||
public var Wallet_Intro_Text: String { return self._s[133]! }
|
||||
public var Wallet_Configuration_Apply: String { return self._s[134]! }
|
||||
public func Wallet_SecureStorageChanged_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[130]!, self._r[130]!, [_0])
|
||||
return formatWithArgumentRanges(self._s[135]!, self._r[135]!, [_0])
|
||||
}
|
||||
public var Wallet_Month_ShortApril: String { return self._s[131]! }
|
||||
public var Wallet_Navigation_Close: String { return self._s[132]! }
|
||||
public var Wallet_WordCheck_IncorrectHeader: String { return self._s[133]! }
|
||||
public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[134]! }
|
||||
public func Wallet_Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[135]!, self._r[135]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Send_AddressText: String { return self._s[137]! }
|
||||
public func Wallet_Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[139]!, self._r[139]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Month_ShortMay: String { return self._s[140]! }
|
||||
public var Wallet_Intro_CreateErrorText: String { return self._s[142]! }
|
||||
public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[143]! }
|
||||
public var Wallet_Intro_Text: String { return self._s[144]! }
|
||||
public var Wallet_Month_GenJune: String { return self._s[145]! }
|
||||
public var Wallet_Receive_ShareUrlInfo: String { return self._s[146]! }
|
||||
public func Wallet_Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[147]!, self._r[147]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_AccessDenied_Title: String { return self._s[149]! }
|
||||
public var Wallet_Send_SendAnyway: String { return self._s[150]! }
|
||||
public var Wallet_Configuration_SourceJSON: String { return self._s[151]! }
|
||||
public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[152]! }
|
||||
public func Wallet_Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[153]!, self._r[153]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[136]!, self._r[136]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_TransactionInfo_SendGrams: String { return self._s[154]! }
|
||||
public var Wallet_Words_NotDoneText: String { return self._s[155]! }
|
||||
public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[156]! }
|
||||
public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[158]! }
|
||||
public var Wallet_Qr_ScanCode: String { return self._s[159]! }
|
||||
public var Wallet_WordImport_Title: String { return self._s[160]! }
|
||||
public func Wallet_Send_ConfirmationText(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
public var Wallet_RestoreFailed_CreateWallet: String { return self._s[137]! }
|
||||
public var Wallet_Weekday_Yesterday: String { return self._s[138]! }
|
||||
public var Wallet_Receive_AmountHeader: String { return self._s[139]! }
|
||||
public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[140]! }
|
||||
public var Wallet_Month_ShortFebruary: String { return self._s[141]! }
|
||||
public var Wallet_Configuration_SourceJSON: String { return self._s[142]! }
|
||||
public var Wallet_Alert_Cancel: String { return self._s[143]! }
|
||||
public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[144]! }
|
||||
public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[145]! }
|
||||
public var Wallet_Info_TransactionFrom: String { return self._s[146]! }
|
||||
public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[147]! }
|
||||
public var Wallet_Send_OwnAddressAlertText: String { return self._s[148]! }
|
||||
public var Wallet_Words_NotDoneTitle: String { return self._s[149]! }
|
||||
public var Wallet_Month_ShortOctober: String { return self._s[150]! }
|
||||
public var Wallet_Month_GenMay: String { return self._s[151]! }
|
||||
public var Wallet_Intro_CreateErrorTitle: String { return self._s[152]! }
|
||||
public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[153]! }
|
||||
public var Wallet_Month_ShortJanuary: String { return self._s[154]! }
|
||||
public var Wallet_Month_GenMarch: String { return self._s[155]! }
|
||||
public var Wallet_AccessDenied_Camera: String { return self._s[156]! }
|
||||
public var Wallet_Sending_Text: String { return self._s[157]! }
|
||||
public var Wallet_Month_GenOctober: String { return self._s[158]! }
|
||||
public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[159]! }
|
||||
public var Wallet_ContextMenuCopy: String { return self._s[160]! }
|
||||
public func Wallet_Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[161]!, self._r[161]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Intro_Terms: String { return self._s[162]! }
|
||||
public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[163]! }
|
||||
public var Wallet_Receive_CreateInvoice: String { return self._s[164]! }
|
||||
public var Wallet_Send_Confirmation: String { return self._s[165]! }
|
||||
public var Wallet_Month_GenNovember: String { return self._s[166]! }
|
||||
public func Wallet_Info_TransactionDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[167]!, self._r[167]!, [_1, _2])
|
||||
public var Wallet_Info_Updating: String { return self._s[163]! }
|
||||
public var Wallet_Created_ExportErrorTitle: String { return self._s[164]! }
|
||||
public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[165]! }
|
||||
public var Wallet_Sending_Title: String { return self._s[166]! }
|
||||
public var Wallet_Navigation_Done: String { return self._s[167]! }
|
||||
public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[168]! }
|
||||
public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[169]! }
|
||||
public var Wallet_Settings_Title: String { return self._s[170]! }
|
||||
public func Wallet_Receive_ShareInvoiceUrlInfo(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[171]!, self._r[171]!, [_0])
|
||||
}
|
||||
public func Wallet_Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[168]!, self._r[168]!, [_1, _2, _3])
|
||||
public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[172]! }
|
||||
public var Wallet_Weekday_Today: String { return self._s[174]! }
|
||||
public var Wallet_Month_ShortDecember: String { return self._s[175]! }
|
||||
public var Wallet_Words_Text: String { return self._s[176]! }
|
||||
public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[177]! }
|
||||
public var Wallet_WordCheck_ViewWords: String { return self._s[178]! }
|
||||
public var Wallet_Send_AddressInfo: String { return self._s[179]! }
|
||||
public func Wallet_Updated_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[180]!, self._r[180]!, [_0])
|
||||
}
|
||||
public var Wallet_WordCheck_IncorrectText: String { return self._s[170]! }
|
||||
public var Wallet_Completed_ViewWallet: String { return self._s[171]! }
|
||||
public var Wallet_WordImport_Text: String { return self._s[172]! }
|
||||
public var Wallet_Words_NotDoneOk: String { return self._s[173]! }
|
||||
public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[174]! }
|
||||
public var Wallet_TransactionInfo_SenderHeader: String { return self._s[175]! }
|
||||
public var Wallet_Info_WalletCreated: String { return self._s[176]! }
|
||||
public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[177]! }
|
||||
public var Wallet_Sending_Text: String { return self._s[178]! }
|
||||
public var Wallet_Words_Title: String { return self._s[179]! }
|
||||
public var Wallet_Receive_CommentHeader: String { return self._s[180]! }
|
||||
public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[181]! }
|
||||
public var Wallet_Intro_CreateErrorTitle: String { return self._s[182]! }
|
||||
public var Wallet_Intro_NotNow: String { return self._s[181]! }
|
||||
public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[182]! }
|
||||
public var Wallet_Navigation_Close: String { return self._s[183]! }
|
||||
public var Wallet_Month_GenDecember: String { return self._s[185]! }
|
||||
public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[186]! }
|
||||
public var Wallet_WordImport_IncorrectTitle: String { return self._s[187]! }
|
||||
public var Wallet_Send_AddressText: String { return self._s[188]! }
|
||||
public var Wallet_Receive_AmountInfo: String { return self._s[189]! }
|
||||
public func Wallet_Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[190]!, self._r[190]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Month_ShortAugust: String { return self._s[191]! }
|
||||
public var Wallet_Qr_Title: String { return self._s[192]! }
|
||||
public var Wallet_Settings_Configuration: String { return self._s[193]! }
|
||||
public var Wallet_WordCheck_TryAgain: String { return self._s[194]! }
|
||||
public var Wallet_Info_TransactionPendingHeader: String { return self._s[195]! }
|
||||
public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[196]! }
|
||||
public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[197]! }
|
||||
public var Wallet_Send_TransactionInProgress: String { return self._s[198]! }
|
||||
public var Wallet_Created_Text: String { return self._s[199]! }
|
||||
public var Wallet_Created_Proceed: String { return self._s[200]! }
|
||||
public var Wallet_Words_Done: String { return self._s[201]! }
|
||||
public var Wallet_WordImport_Continue: String { return self._s[202]! }
|
||||
public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[203]! }
|
||||
public var Wallet_WordImport_CanNotRemember: String { return self._s[204]! }
|
||||
public func Wallet_Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[183]!, self._r[183]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[205]!, self._r[205]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[184]! }
|
||||
public var Wallet_Configuration_Apply: String { return self._s[185]! }
|
||||
public var Wallet_WordImport_IncorrectTitle: String { return self._s[186]! }
|
||||
public var Wallet_Settings_Configuration: String { return self._s[187]! }
|
||||
public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[189]! }
|
||||
public var Wallet_Month_GenJanuary: String { return self._s[190]! }
|
||||
public var Wallet_Settings_DeleteWallet: String { return self._s[191]! }
|
||||
public var Wallet_Month_GenOctober: String { return self._s[192]! }
|
||||
public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[193]! }
|
||||
public var Wallet_Receive_AddressCopied: String { return self._s[194]! }
|
||||
public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[195]! }
|
||||
public func Wallet_Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[196]!, self._r[196]!, [_1, _2, _3])
|
||||
public func Wallet_Send_ConfirmationText(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[206]!, self._r[206]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Receive_AmountInfo: String { return self._s[197]! }
|
||||
public var Wallet_Info_TransactionPendingHeader: String { return self._s[198]! }
|
||||
public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[199]! }
|
||||
public var Wallet_Updated_JustNow: String { return self._s[200]! }
|
||||
public var Wallet_Info_RefreshErrorText: String { return self._s[201]! }
|
||||
public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[202]! }
|
||||
public var Wallet_Settings_DeleteWalletInfo: String { return self._s[203]! }
|
||||
public var Wallet_RestoreFailed_EnterWords: String { return self._s[204]! }
|
||||
public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[205]! }
|
||||
public var Wallet_Send_TransactionInProgress: String { return self._s[206]! }
|
||||
public var Wallet_Month_GenMarch: String { return self._s[207]! }
|
||||
public var Wallet_Receive_AmountHeader: String { return self._s[208]! }
|
||||
public var Wallet_TransactionInfo_NoAddress: String { return self._s[209]! }
|
||||
public var Wallet_Weekday_Today: String { return self._s[210]! }
|
||||
public var Wallet_Configuration_SourceURL: String { return self._s[211]! }
|
||||
public var Wallet_TransactionInfo_AddressCopied: String { return self._s[212]! }
|
||||
public var Wallet_WordImport_Continue: String { return self._s[213]! }
|
||||
public var Wallet_Month_GenFebruary: String { return self._s[214]! }
|
||||
public var Wallet_Settings_Title: String { return self._s[215]! }
|
||||
public var Wallet_Info_Updating: String { return self._s[216]! }
|
||||
public var Wallet_Settings_ConfigurationInfo: String { return self._s[217]! }
|
||||
public var Wallet_WordImport_CanNotRemember: String { return self._s[218]! }
|
||||
public var Wallet_Sending_Title: String { return self._s[219]! }
|
||||
public func Wallet_Info_TransactionBlockchainFee(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[220]!, self._r[220]!, [_0])
|
||||
public var Wallet_Created_ExportErrorText: String { return self._s[208]! }
|
||||
public func Wallet_Updated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[209]!, self._r[209]!, [_0])
|
||||
}
|
||||
public var Wallet_Settings_DeleteWalletInfo: String { return self._s[210]! }
|
||||
public var Wallet_Intro_CreateErrorText: String { return self._s[211]! }
|
||||
public var Wallet_Sent_ViewWallet: String { return self._s[212]! }
|
||||
public var Wallet_Send_ErrorInvalidAddress: String { return self._s[213]! }
|
||||
public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[214]! }
|
||||
public func Wallet_Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[215]!, self._r[215]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Send_Title: String { return self._s[216]! }
|
||||
public var Wallet_Info_RefreshErrorText: String { return self._s[217]! }
|
||||
public var Wallet_SecureStorageReset_Title: String { return self._s[218]! }
|
||||
public var Wallet_Receive_CommentHeader: String { return self._s[219]! }
|
||||
public var Wallet_Info_ReceiveGrams: String { return self._s[220]! }
|
||||
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
|
||||
let form = getPluralizationForm(self.lc, value)
|
||||
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
||||
|
||||
@ -402,7 +402,7 @@ final class WatchMediaHandler: WatchRequestHandler {
|
||||
if let peer = peer, let representation = peer.smallProfileImage {
|
||||
let imageData = peerAvatarImageData(account: context.account, peer: peer, authorOfMessage: nil, representation: representation, synchronousLoad: false)
|
||||
if let imageData = imageData {
|
||||
return imageData |> deliverOn(Queue.concurrentDefaultQueue())
|
||||
return imageData
|
||||
|> map { data -> UIImage? in
|
||||
if let data = data, let image = generateImage(targetSize, contextGenerator: { size, context -> Void in
|
||||
if let imageSource = CGImageSourceCreateWithData(data as CFData, nil), let dataImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) {
|
||||
@ -429,7 +429,7 @@ final class WatchMediaHandler: WatchRequestHandler {
|
||||
|
||||
let disposable = signal.start(next: { image in
|
||||
if let image = image, let imageData = image.jpegData(compressionQuality: compressionRate) {
|
||||
sendData(manager: manager, data: imageData, key: key, ext: ".jpg", type: TGBridgeIncomingFileTypeImage)
|
||||
sendData(manager: manager, data: imageData, key: key, ext: ".jpg", type: TGBridgeIncomingFileTypeImage, forceAsData: true)
|
||||
}
|
||||
subscriber?.putNext(key)
|
||||
}, completed: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user