diff --git a/WORKSPACE b/WORKSPACE index a270359be7..a41ed5cce6 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -56,3 +56,10 @@ http_file( urls = ["https://github.com/Kitware/CMake/releases/download/v3.19.2/cmake-3.19.2-macos-universal.tar.gz"], sha256 = "50afa2cb66bea6a0314ef28034f3ff1647325e30cf5940f97906a56fd9640bd8", ) + +http_archive( + name = "appcenter_sdk", + urls = ["https://github.com/microsoft/appcenter-sdk-apple/releases/download/4.1.1/AppCenter-SDK-Apple-4.1.1.zip"], + sha256 = "032907801dc7784744a1ca8fd40d3eecc34a2e27a93a4b3993f617cca204a9f3", + build_file = "@//third-party/AppCenter:AppCenter.BUILD", +) diff --git a/buildbox/deploy-appcenter.sh b/buildbox/deploy-appcenter.sh index 7519ef5b18..141a43bf48 100644 --- a/buildbox/deploy-appcenter.sh +++ b/buildbox/deploy-appcenter.sh @@ -3,84 +3,11 @@ set -e set -x -API_HOST="https://api.appcenter.ms" IPA_PATH="build/artifacts/Telegram.ipa" DSYM_PATH="build/artifacts/Telegram.DSYMs.zip" -upload_ipa() { - GROUP_DATA=$(curl \ - -X GET \ - --header "X-API-Token: $API_TOKEN" \ - "$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/distribution_groups/Internal" \ - ) - - GROUP_ID=$(echo "$GROUP_DATA" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["id"];') - - UPLOAD_TOKEN=$(curl \ - -X POST \ - --header "Content-Type: application/json" \ - --header "Accept: application/json" \ - --header "X-API-Token: $API_TOKEN" \ - "$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/release_uploads" \ - ) - - - UPLOAD_URL=$(echo "$UPLOAD_TOKEN" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["upload_url"];') - UPLOAD_ID=$(echo "$UPLOAD_TOKEN" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["upload_id"];') - - curl --progress-bar -F "ipa=@${IPA_PATH}" "$UPLOAD_URL" - - RELEASE_TOKEN=$(curl \ - -X PATCH \ - --header "Content-Type: application/json" \ - --header "Accept: application/json" \ - --header "X-API-Token: $API_TOKEN" \ - -d '{ "status": "committed" }' \ - "$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/release_uploads/$UPLOAD_ID" \ - ) - - - RELEASE_URL=$(echo "$RELEASE_TOKEN" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["release_url"];') - RELEASE_ID=$(echo "$RELEASE_TOKEN" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["release_id"];') - - curl \ - -X POST \ - --header "Content-Type: application/json" \ - --header "Accept: application/json" \ - --header "X-API-Token: $API_TOKEN" \ - -d "{ \"id\": \"$GROUP_ID\", \"mandatory_update\": false, \"notify_testers\": false }" \ - "$API_HOST/$RELEASE_URL/groups" -} - -upload_dsym() { - UPLOAD_DSYM_DATA=$(curl \ - -X POST \ - --header "Content-Type: application/json" \ - --header "Accept: application/json" \ - --header "X-API-Token: $API_TOKEN" \ - -d "{ \"symbol_type\": \"Apple\"}" \ - "$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/symbol_uploads" \ - ) - - DSYM_UPLOAD_URL=$(echo "$UPLOAD_DSYM_DATA" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["upload_url"];') - DSYM_UPLOAD_ID=$(echo "$UPLOAD_DSYM_DATA" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["symbol_upload_id"];') - - curl \ - --progress-bar \ - --header "x-ms-blob-type: BlockBlob" \ - --upload-file "${DSYM_PATH}" \ - "$DSYM_UPLOAD_URL" - - curl \ - -X PATCH \ - --header "Content-Type: application/json" \ - --header "Accept: application/json" \ - --header "X-API-Token: $API_TOKEN" \ - -d '{ "status": "committed" }' \ - "$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/symbol_uploads/$DSYM_UPLOAD_ID" -} - APPCENTER="/usr/local/bin/appcenter" $APPCENTER login --token "$API_TOKEN" $APPCENTER distribute release --app "$API_USER_NAME/$API_APP_NAME" -f "$IPA_PATH" -g Internal +$APPCENTER crashes upload-symbols --app "$API_USER_NAME/$API_APP_NAME" --symbol "$DSYM_PATH" diff --git a/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTSessionInfo.h b/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTSessionInfo.h index ec32fbbce6..a3a3f2f262 100644 --- a/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTSessionInfo.h +++ b/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTSessionInfo.h @@ -19,6 +19,8 @@ - (bool)messageProcessed:(int64_t)messageId; - (void)setMessageProcessed:(int64_t)messageId; +- (bool)wasMessageSentOnce:(int64_t)messageId; +- (void)setMessageWasSentOnce:(int64_t)messageId; - (void)scheduleMessageConfirmation:(int64_t)messageId size:(NSInteger)size; - (NSArray *)scheduledMessageConfirmations; - (bool)scheduledMessageConfirmationsExceedSize:(NSInteger)sizeLimit orCount:(NSUInteger)countLimit; diff --git a/submodules/MtProtoKit/Sources/MTProto.m b/submodules/MtProtoKit/Sources/MTProto.m index 8bd36b4857..fa9cda74f5 100644 --- a/submodules/MtProtoKit/Sources/MTProto.m +++ b/submodules/MtProtoKit/Sources/MTProto.m @@ -1148,7 +1148,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; { if (!_useUnauthorizedMode) { - NSMutableArray *currentContainerMessages = [[NSMutableArray alloc] init]; + NSMutableArray *currentContainerMessages = [[NSMutableArray alloc] init]; NSUInteger currentContainerSize = 0; for (NSUInteger j = i; j < transactionMessageList.count; j++, i++) @@ -1186,8 +1186,9 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; } } - if (currentContainerMessages.count == 1) + if (currentContainerMessages.count == 1 && ![transactionSessionInfo wasMessageSentOnce:currentContainerMessages[0].messageId]) { + [transactionSessionInfo setMessageWasSentOnce:currentContainerMessages[0].messageId]; int32_t quickAckId = 0; NSData *messageData = [self _dataForEncryptedMessage:currentContainerMessages[0] authKey:authKey sessionInfo:transactionSessionInfo quickAckId:&quickAckId address:scheme.address extendedPadding:extendedPadding]; if (messageData != nil) @@ -2116,17 +2117,12 @@ static bool isDataEqualToDataConstTime(NSData *data1, NSData *data2) { if (data1.length != data2.length) { return false; } - uint8_t const *bytes1 = data1.bytes; uint8_t const *bytes2 = data2.bytes; - int result = 0; for (int i = 0; i < data1.length; i++) { - if (bytes1[i] != bytes2[i]) { - result |= i + 1; - } + result |= bytes1[i] != bytes2[i]; } - return result == 0; } diff --git a/submodules/MtProtoKit/Sources/MTSessionInfo.m b/submodules/MtProtoKit/Sources/MTSessionInfo.m index 1691592fa0..25d8e0dd07 100644 --- a/submodules/MtProtoKit/Sources/MTSessionInfo.m +++ b/submodules/MtProtoKit/Sources/MTSessionInfo.m @@ -52,6 +52,7 @@ NSMutableSet *_processedMessageIdsSet; NSMutableArray *_scheduledMessageConfirmations; NSMutableDictionary *_containerMessagesMappingDict; + NSMutableSet *_sentMessageIdsSet; } @end @@ -76,6 +77,7 @@ _scheduledMessageConfirmations = [[NSMutableArray alloc] init]; _processedMessageIdsSet = [[NSMutableSet alloc] init]; + _sentMessageIdsSet = [[NSMutableSet alloc] init]; _containerMessagesMappingDict = [[NSMutableDictionary alloc] init]; } return self; @@ -138,6 +140,14 @@ [_processedMessageIdsSet addObject:@(messageId)]; } +- (bool)wasMessageSentOnce:(int64_t)messageId { + return [_sentMessageIdsSet containsObject:@(messageId)]; +} + +- (void)setMessageWasSentOnce:(int64_t)messageId { + [_sentMessageIdsSet addObject:@(messageId)]; +} + - (void)scheduleMessageConfirmation:(int64_t)messageId size:(NSInteger)size { bool found = false; diff --git a/submodules/SettingsUI/Sources/Themes/SettingsThemeWallpaperNode.swift b/submodules/SettingsUI/Sources/Themes/SettingsThemeWallpaperNode.swift index ee9013013f..439bc07da9 100644 --- a/submodules/SettingsUI/Sources/Themes/SettingsThemeWallpaperNode.swift +++ b/submodules/SettingsUI/Sources/Themes/SettingsThemeWallpaperNode.swift @@ -41,6 +41,11 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { private let statusNode: RadialStatusNode var pressed: (() -> Void)? + + private var isSelected: Bool = false + private var isLoaded: Bool = false + + private let isLoadedDisposable = MetaDisposable() init(overlayBackgroundColor: UIColor = UIColor(white: 0.0, alpha: 0.3)) { self.imageNode.contentAnimations = [.subsequentUpdates] @@ -59,10 +64,36 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) } + + deinit { + self.isLoadedDisposable.dispose() + } func setSelected(_ selected: Bool, animated: Bool = false) { - let state: RadialStatusNodeState = selected ? .check(.white) : .none - self.statusNode.transitionToState(state, animated: animated, completion: {}) + if self.isSelected != selected { + self.isSelected = selected + + self.updateStatus(animated: animated) + } + } + + private func updateIsLoaded(isLoaded: Bool, animated: Bool) { + if self.isLoaded != isLoaded { + self.isLoaded = isLoaded + self.updateStatus(animated: animated) + } + } + + private func updateStatus(animated: Bool) { + if self.isSelected { + if self.isLoaded { + self.statusNode.transitionToState(.check(.white), animated: animated, completion: {}) + } else { + self.statusNode.transitionToState(.progress(color: .white, lineWidth: nil, value: nil, cancelEnabled: false, animateRotation: true), animated: animated, completion: {}) + } + } else { + self.statusNode.transitionToState(.none, animated: animated, completion: {}) + } } func setOverlayBackgroundColor(_ color: UIColor) { @@ -127,9 +158,6 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { gradientNode.updateLayout(size: size, transition: .immediate) } - let state: RadialStatusNodeState = selected ? .check(.white) : .none - self.statusNode.transitionToState(state, animated: false, completion: {}) - let progressDiameter: CGFloat = 50.0 self.statusNode.frame = CGRect(x: floorToScreenPixels((size.width - progressDiameter) / 2.0), y: floorToScreenPixels((size.height - progressDiameter) / 2.0), width: progressDiameter, height: progressDiameter) @@ -143,6 +171,8 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { self.imageNode.setSignal(settingsBuiltinWallpaperImage(account: context.account)) let apply = self.imageNode.asyncLayout()(TransformImageArguments(corners: corners, imageSize: CGSize(), boundingSize: size, intrinsicInsets: UIEdgeInsets())) apply() + self.isLoadedDisposable.set(nil) + self.updateIsLoaded(isLoaded: true, animated: false) case let .image(representations, _): let convertedRepresentations: [ImageRepresentationWithReference] = representations.map({ ImageRepresentationWithReference(representation: $0, reference: .wallpaper(wallpaper: nil, resource: $0.resource)) }) self.imageNode.alpha = 1.0 @@ -150,10 +180,15 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { let apply = self.imageNode.asyncLayout()(TransformImageArguments(corners: corners, imageSize: largestImageRepresentation(representations)!.dimensions.cgSize.aspectFilled(size), boundingSize: size, intrinsicInsets: UIEdgeInsets())) apply() + self.isLoadedDisposable.set(nil) + self.updateIsLoaded(isLoaded: true, animated: false) case let .file(file): let convertedRepresentations : [ImageRepresentationWithReference] = file.file.previewRepresentations.map { ImageRepresentationWithReference(representation: $0, reference: .wallpaper(wallpaper: .slug(file.slug), resource: $0.resource)) } + + let fullDimensions = file.file.dimensions ?? PixelDimensions(width: 2000, height: 4000) + let convertedFullRepresentations = [ImageRepresentationWithReference(representation: .init(dimensions: fullDimensions, resource: file.file.resource, progressiveSizes: [], immediateThumbnailData: nil), reference: .wallpaper(wallpaper: .slug(file.slug), resource: file.file.resource))] let imageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError> if wallpaper.isPattern { @@ -180,10 +215,43 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { return .complete() } } + + let anyStatus = combineLatest(queue: .mainQueue(), + context.account.postbox.mediaBox.resourceStatus(convertedFullRepresentations[0].reference.resource, approximateSynchronousValue: true), + context.sharedContext.accountManager.mediaBox.resourceStatus(convertedFullRepresentations[0].reference.resource, approximateSynchronousValue: true) + ) + |> map { a, b -> Bool in + switch a { + case .Local: + return true + default: + break + } + switch b { + case .Local: + return true + default: + break + } + return false + } + |> distinctUntilChanged + + self.updateIsLoaded(isLoaded: false, animated: false) + self.isLoadedDisposable.set((anyStatus + |> deliverOnMainQueue).start(next: { [weak self] value in + guard let strongSelf = self else { + return + } + strongSelf.updateIsLoaded(isLoaded: value, animated: true) + })) } else { self.imageNode.alpha = 1.0 imageSignal = wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: .standalone(media: file.file), representations: convertedRepresentations, thumbnail: true, autoFetchFullSize: true, synchronousLoad: synchronousLoad) + + self.updateIsLoaded(isLoaded: true, animated: false) + self.isLoadedDisposable.set(nil) } self.imageNode.setSignal(imageSignal, attemptSynchronously: synchronousLoad) @@ -207,6 +275,8 @@ final class SettingsThemeWallpaperNode: ASDisplayNode { apply() } } + + self.setSelected(selected, animated: false) } @objc func buttonPressed() { diff --git a/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift b/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift index 3278da9ef7..54ce9f2529 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationThemeCodable.swift @@ -426,6 +426,7 @@ extension PresentationThemeRootNavigationBar: Codable { public convenience init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) + let blurredBackgroundColor = try decodeColor(values, .background) self.init( buttonColor: try decodeColor(values, .button), @@ -434,8 +435,8 @@ extension PresentationThemeRootNavigationBar: Codable { secondaryTextColor: try decodeColor(values, .secondaryText), controlColor: try decodeColor(values, .control), accentTextColor: try decodeColor(values, .accentText), - blurredBackgroundColor: try decodeColor(values, .background), - opaqueBackgroundColor: try decodeColor(values, .opaqueBackground, fallbackKey: "root.navBar.background"), + blurredBackgroundColor: blurredBackgroundColor, + opaqueBackgroundColor: (try? decodeColor(values, .opaqueBackground)) ?? blurredBackgroundColor.withAlphaComponent(1.0), separatorColor: try decodeColor(values, .separator), badgeBackgroundColor: try decodeColor(values, .badgeFill), badgeStrokeColor: try decodeColor(values, .badgeStroke), diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChat.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChat.swift index 91cbfaba3d..e44f2868b6 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChat.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChat.swift @@ -532,7 +532,14 @@ public struct PresentationResourcesChat { public static func chatInputTextFieldTimerImage(_ theme: PresentationTheme) -> UIImage? { return theme.image(PresentationResourceKey.chatInputTextFieldTimerImage.rawValue, { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/AccessoryIconTimer"), color: theme.chat.inputPanel.inputControlColor) + if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/AccessoryIconTimer"), color: theme.chat.inputPanel.inputControlColor) { + return generateImage(CGSize(width: image.size.width, height: image.size.height + 1.0), contextGenerator: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.draw(image.cgImage!, in: CGRect(origin: CGPoint(x: 0.0, y: 2.0), size: image.size)) + }) + } else { + return nil + } }) } diff --git a/submodules/TelegramUI/BUILD b/submodules/TelegramUI/BUILD index f7374f2208..6e18969ca6 100644 --- a/submodules/TelegramUI/BUILD +++ b/submodules/TelegramUI/BUILD @@ -15,6 +15,11 @@ filegroup( visibility = ["//visibility:public"], ) +appcenter_targets = [ + "@appcenter_sdk//:AppCenter", + "@appcenter_sdk//:AppCenterCrashes", +] + swift_library( name = "TelegramUI", module_name = "TelegramUI", @@ -223,7 +228,12 @@ swift_library( "//submodules/ImportStickerPackUI:ImportStickerPackUI", "//submodules/GradientBackground:GradientBackground", "//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode", - ], + ] + select({ + "@build_bazel_rules_apple//apple:ios_armv7": [], + "@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets, + "//build-system:ios_sim_arm64": [], + "@build_bazel_rules_apple//apple:ios_x86_64": [], + }), visibility = [ "//visibility:public", ], diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index 77e0fd8672..e5f3393fb2 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -34,9 +34,11 @@ import CoreSpotlight import LightweightAccountData import TelegramAudio import DebugSettingsUI - -#if canImport(BackgroundTasks) import BackgroundTasks + +#if os(iOS) +import AppCenter +import AppCenterCrashes #endif private let handleVoipNotifications = false @@ -486,14 +488,7 @@ final class SharedApplicationContext { telegramUIDeclareEncodables() GlobalExperimentalSettings.isAppStoreBuild = buildConfig.isAppStoreBuild - GlobalExperimentalSettings.enableFeed = false - #if DEBUG - //GlobalExperimentalSettings.enableFeed = true - #if targetEnvironment(simulator) - //GlobalTelegramCoreConfiguration.readMessages = false - #endif - #endif self.window?.makeKeyAndVisible() @@ -1335,6 +1330,14 @@ final class SharedApplicationContext { }*/ self.maybeCheckForUpdates() + + #if os(iOS) + if !buildConfig.isAppStoreBuild, let appCenterId = buildConfig.appCenterId, !appCenterId.isEmpty { + AppCenter.start(withAppSecret: buildConfig.appCenterId, services: [ + Crashes.self + ]) + } + #endif return true } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index f91cc612a9..24ff432d0d 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -4856,20 +4856,27 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } let interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { [weak self] messageId, completion in - if let strongSelf = self, strongSelf.isNodeLoaded, canSendMessagesToChat(strongSelf.presentationInterfaceState) { - let _ = strongSelf.presentVoiceMessageDiscardAlert(action: { - if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) { - strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState({ $0.withUpdatedReplyMessageId(message.id) }).updatedSearch(nil) }, completion: completion) - strongSelf.updateItemNodesSearchTextHighlightStates() - strongSelf.chatDisplayNode.ensureInputViewFocused() - } else { + guard let strongSelf = self, strongSelf.isNodeLoaded else { + return + } + if let messageId = messageId { + if canSendMessagesToChat(strongSelf.presentationInterfaceState) { + let _ = strongSelf.presentVoiceMessageDiscardAlert(action: { + if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) { + strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState({ $0.withUpdatedReplyMessageId(message.id) }).updatedSearch(nil) }, completion: completion) + strongSelf.updateItemNodesSearchTextHighlightStates() + strongSelf.chatDisplayNode.ensureInputViewFocused() + } else { + completion(.immediate) + } + }, alertAction: { completion(.immediate) - } - }, alertAction: { + }, delay: true) + } else { completion(.immediate) - }, delay: true) + } } else { - completion(.immediate) + strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState({ $0.withUpdatedReplyMessageId(nil) }) }, completion: completion) } }, setupEditMessage: { [weak self] messageId, completion in if let strongSelf = self, strongSelf.isNodeLoaded { diff --git a/submodules/TelegramUI/Sources/ChatInterfaceInputContexts.swift b/submodules/TelegramUI/Sources/ChatInterfaceInputContexts.swift index 7be51fa7f1..8797ad2b98 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceInputContexts.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceInputContexts.swift @@ -286,7 +286,7 @@ func inputTextPanelStateForChatPresentationInterfaceState(_ chatPresentationInte if !extendedSearchLayout { if case .scheduledMessages = chatPresentationInterfaceState.subject { } else if chatPresentationInterfaceState.renderedPeer?.peerId != context.account.peerId { - if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramSecretChat { + if let peer = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramSecretChat, chatPresentationInterfaceState.interfaceState.composeInputState.inputText.length == 0 { accessoryItems.append(.messageAutoremoveTimeout(peer.messageAutoremoveTimeout)) } else if currentAutoremoveTimeout != nil && chatPresentationInterfaceState.interfaceState.composeInputState.inputText.length == 0 { accessoryItems.append(.messageAutoremoveTimeout(currentAutoremoveTimeout)) diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 8a6e1ce63d..453b928769 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1494,7 +1494,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item { self.swipeToReplyFeedback?.impact() - let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonFillColor, wallpaper: item.presentationData.theme.wallpaper), strokeColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonStrokeColor, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) + let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) self.swipeToReplyNode = swipeToReplyNode self.addSubnode(swipeToReplyNode) animateReplyNodeIn = true diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 8aa40291dd..939afaf280 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -3647,7 +3647,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item { self.swipeToReplyFeedback?.impact() - let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonFillColor, wallpaper: item.presentationData.theme.wallpaper), strokeColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonStrokeColor, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) + let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) self.swipeToReplyNode = swipeToReplyNode self.insertSubnode(swipeToReplyNode, belowSubnode: self.messageAccessibilityArea) animateReplyNodeIn = true diff --git a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift index 6b1c9ce3f9..8fc9243c32 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift @@ -850,7 +850,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView { if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item { self.swipeToReplyFeedback?.impact() - let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonFillColor, wallpaper: item.presentationData.theme.wallpaper), strokeColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonStrokeColor, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) + let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) self.swipeToReplyNode = swipeToReplyNode self.addSubnode(swipeToReplyNode) animateReplyNodeIn = true diff --git a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift index e105a800e7..34cfaf6410 100644 --- a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift @@ -1008,7 +1008,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView { if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item { self.swipeToReplyFeedback?.impact() - let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonFillColor, wallpaper: item.presentationData.theme.wallpaper), strokeColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonStrokeColor, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) + let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) self.swipeToReplyNode = swipeToReplyNode self.addSubnode(swipeToReplyNode) animateReplyNodeIn = true diff --git a/submodules/TelegramUI/Sources/ChatMessageSwipeToReplyNode.swift b/submodules/TelegramUI/Sources/ChatMessageSwipeToReplyNode.swift index 4d9041526b..6ba2ffb591 100644 --- a/submodules/TelegramUI/Sources/ChatMessageSwipeToReplyNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageSwipeToReplyNode.swift @@ -11,25 +11,18 @@ final class ChatMessageSwipeToReplyNode: ASDisplayNode { case unlike } - private let backgroundNode: ASImageNode + private let backgroundNode: NavigationBackgroundNode + private let foregroundNode: ASImageNode - init(fillColor: UIColor, strokeColor: UIColor, foregroundColor: UIColor, action: ChatMessageSwipeToReplyNode.Action) { - self.backgroundNode = ASImageNode() - self.backgroundNode.isLayerBacked = true - self.backgroundNode.image = generateImage(CGSize(width: 33.0, height: 33.0), rotatedContext: { size, context in + init(fillColor: UIColor, enableBlur: Bool, foregroundColor: UIColor, action: ChatMessageSwipeToReplyNode.Action) { + self.backgroundNode = NavigationBackgroundNode(color: fillColor, enableBlur: enableBlur) + self.backgroundNode.isUserInteractionEnabled = false + + self.foregroundNode = ASImageNode() + self.foregroundNode.isUserInteractionEnabled = false + + self.foregroundNode.image = generateImage(CGSize(width: 33.0, height: 33.0), rotatedContext: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(fillColor.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) - - let lineWidth: CGFloat = 1.0 - let halfLineWidth = lineWidth / 2.0 - var strokeAlpha: CGFloat = 0.0 - strokeColor.getRed(nil, green: nil, blue: nil, alpha: &strokeAlpha) - if !strokeAlpha.isZero { - context.setStrokeColor(strokeColor.cgColor) - context.setLineWidth(lineWidth) - context.strokeEllipse(in: CGRect(origin: CGPoint(x: halfLineWidth, y: halfLineWidth), size: CGSize(width: size.width - lineWidth, height: size.width - lineWidth))) - } switch action { case .reply: @@ -65,7 +58,10 @@ final class ChatMessageSwipeToReplyNode: ASDisplayNode { super.init() self.addSubnode(self.backgroundNode) + self.addSubnode(self.foregroundNode) self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 33.0, height: 33.0)) + self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: self.backgroundNode.bounds.height / 2.0, transition: .immediate) + self.foregroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 33.0, height: 33.0)) } } diff --git a/submodules/TelegramUI/Sources/ChatPanelInterfaceInteraction.swift b/submodules/TelegramUI/Sources/ChatPanelInterfaceInteraction.swift index 535edc35e7..2b3d2a4a80 100644 --- a/submodules/TelegramUI/Sources/ChatPanelInterfaceInteraction.swift +++ b/submodules/TelegramUI/Sources/ChatPanelInterfaceInteraction.swift @@ -50,7 +50,7 @@ enum ChatPanelRestrictionInfoDisplayType { } final class ChatPanelInterfaceInteraction { - let setupReplyMessage: (MessageId, @escaping (ContainedViewLayoutTransition) -> Void) -> Void + let setupReplyMessage: (MessageId?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void let setupEditMessage: (MessageId?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void let beginMessageSelection: ([MessageId], @escaping (ContainedViewLayoutTransition) -> Void) -> Void let deleteSelectedMessages: () -> Void @@ -133,7 +133,7 @@ final class ChatPanelInterfaceInteraction { let statuses: ChatPanelInterfaceInteractionStatuses? init( - setupReplyMessage: @escaping (MessageId, @escaping (ContainedViewLayoutTransition) -> Void) -> Void, + setupReplyMessage: @escaping (MessageId?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void, setupEditMessage: @escaping (MessageId?, @escaping (ContainedViewLayoutTransition) -> Void) -> Void, beginMessageSelection: @escaping ([MessageId], @escaping (ContainedViewLayoutTransition) -> Void) -> Void, deleteSelectedMessages: @escaping () -> Void, diff --git a/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift index 4f39a8e005..46ecf9361b 100644 --- a/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecordingPreviewInputPanelNode.swift @@ -253,7 +253,7 @@ final class ChatRecordingPreviewInputPanelNode: ChatInputPanelNode { self.playButton.layer.animateScale(from: 0.01, to: 1.0, duration: 0.3, delay: 0.1) self.playButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, delay: 0.1) - self.durationLabel.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + self.durationLabel.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, delay: 0.1) self.waveformScubberNode.layer.animateScaleY(from: 0.1, to: 1.0, duration: 0.3, delay: 0.1) self.waveformScubberNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, delay: 0.1) diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index ec5157ccf5..804cff0daa 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -105,7 +105,7 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode { if let timeout = timeout { return (nil, shortTimeIntervalString(strings: strings, value: timeout), strings.VoiceOver_SelfDestructTimerOn(timeIntervalString(strings: strings, value: timeout)).0, 1.0, UIEdgeInsets()) } else { - return (PresentationResourcesChat.chatInputTextFieldTimerImage(theme), nil, strings.VoiceOver_SelfDestructTimerOff, 1.0, UIEdgeInsets(top: 0.0, left: 0.0, bottom: 1.0, right: 0.0)) + return (PresentationResourcesChat.chatInputTextFieldTimerImage(theme), nil, strings.VoiceOver_SelfDestructTimerOff, 1.0, UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)) } case .scheduledMessages: return (PresentationResourcesChat.chatInputTextFieldScheduleImage(theme), nil, strings.VoiceOver_ScheduledMessages, 1.0, UIEdgeInsets()) @@ -128,7 +128,9 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode { func updateLayout(size: CGSize) { if let image = self.imageNode.image { - self.imageNode.frame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0) - self.imageEdgeInsets.bottom), size: image.size) + let bottomInset: CGFloat = 0.0 + let imageFrame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0) - bottomInset), size: image.size) + self.imageNode.frame = imageFrame } } diff --git a/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift b/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift index d8da3768a1..afb5c86d93 100644 --- a/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Sources/ReplyAccessoryPanelNode.swift @@ -75,7 +75,15 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode { self.messageDisposable.set((context.account.postbox.messageView(messageId) |> deliverOnMainQueue).start(next: { [weak self] messageView in if let strongSelf = self { + if messageView.message == nil { + Queue.mainQueue().justDispatch { + strongSelf.interfaceInteraction?.setupReplyMessage(nil, { _ in }) + } + return + } + let message = messageView.message + var authorName = "" var text = "" if let forwardInfo = message?.forwardInfo, forwardInfo.flags.contains(.isImported) { diff --git a/third-party/AppCenter/AppCenter.BUILD b/third-party/AppCenter/AppCenter.BUILD new file mode 100644 index 0000000000..ce677b8e72 --- /dev/null +++ b/third-party/AppCenter/AppCenter.BUILD @@ -0,0 +1,15 @@ +load("@build_bazel_rules_apple//apple:apple.bzl", + "apple_static_framework_import", +) + +apple_static_framework_import( + name = "AppCenter", + framework_imports = glob(["AppCenter-SDK-Apple/iOS/AppCenter.framework/**"]), + visibility = ["//visibility:public"], +) + +apple_static_framework_import( + name = "AppCenterCrashes", + framework_imports = glob(["AppCenter-SDK-Apple/iOS/AppCenterCrashes.framework/**"]), + visibility = ["//visibility:public"], +) diff --git a/third-party/AppCenter/BUILD b/third-party/AppCenter/BUILD new file mode 100644 index 0000000000..e69de29bb2