diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 419435f9d3..6297a7364f 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -15132,3 +15132,19 @@ Error: %8$@"; "Notification.StarsGift.Assigned" = "You started displaying %@ on your Telegram profile page."; "Gift.View.SenderInfo" = "**%@** sent you this gift on **%@**."; + +"VideoChat.EncryptionKeyLabelShort" = "E2EE"; +"VoiceChat.MuteShort" = "mute"; + +"Stars.Intro.Transaction.GiftDropOriginalDetails" = "Gift Description Removal"; +"Stars.Intro.Transaction.PrepaidGiftUpgrade" = "Gift Upgrade"; + +"Gift.Upgrade.SeePriceDecrease" = "See how price will decrease >"; + +"ProfileColorSetup.ProfileColorPreviewInfo" = "You can also change color of your name and customize replies to you. [Change >]()"; +"ProfileColorSetup.ApplyStyle" = "Apply Style"; + +"ProfileColorSetup.MyGifts" = "My Gifts"; +"ProfileColorSetup.NoProfileGiftsPlaceholder" = "You don't have any gifts you can use as styles for your profile."; +"ProfileColorSetup.NoNameGiftsPlaceholder" = "You don't have any gifts you can use as styles for your name."; +"ProfileColorSetup.BrowseGiftsForPurchase" = "Browse gifts available for purchase >"; diff --git a/submodules/Display/Source/DeviceMetrics.swift b/submodules/Display/Source/DeviceMetrics.swift index a958e64031..ce8cddefe9 100644 --- a/submodules/Display/Source/DeviceMetrics.swift +++ b/submodules/Display/Source/DeviceMetrics.swift @@ -291,7 +291,7 @@ public enum DeviceMetrics: CaseIterable, Equatable { case .iPhone16Pro, .iPhone16ProMax: return 54.0 case .iPhoneAir: - return 54.0 + return 57.0 case .iPhoneX, .iPhoneXSMax, .iPhoneXr, .iPhone12Mini, .iPhone12, .iPhone12ProMax, .iPhone13Mini, .iPhone13, .iPhone13Pro, .iPhone13ProMax: return 44.0 case .iPadPro11Inch, .iPadPro3rdGen, .iPadMini, .iPadMini6thGen: diff --git a/submodules/TelegramCallsUI/Sources/Components/MessageListComponent.swift b/submodules/TelegramCallsUI/Sources/Components/MessageListComponent.swift index b51de73eef..f7461e267a 100644 --- a/submodules/TelegramCallsUI/Sources/Components/MessageListComponent.swift +++ b/submodules/TelegramCallsUI/Sources/Components/MessageListComponent.swift @@ -144,7 +144,7 @@ final class MessageListComponent: Component { let previousContentHeight = self.scrollView.contentSize.height let wasAtBottom = self.isAtBottom(tolerance: 1.0) - let maxWidth: CGFloat = 330.0 + let maxWidth: CGFloat = min(availableSize.width - 16.0, 330.0) var measured: [(id: AnyHashable, size: CGSize, item: MessageListComponent.Item, itemTransition: ComponentTransition)] = [] measured.reserveCapacity(component.items.count) diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index 76041ca2ad..43c5274808 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -1105,7 +1105,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { } } } - case let .call(isTerminated, _, _, _, _, _, _, _): + case let .call(isTerminated, _, _, _, _, _, _, _, _): if isTerminated { self.markAsCanBeRemoved() } diff --git a/submodules/TelegramCallsUI/Sources/VideoChatEncryptionKeyComponent.swift b/submodules/TelegramCallsUI/Sources/VideoChatEncryptionKeyComponent.swift index 769b3e0073..29f6897e0c 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatEncryptionKeyComponent.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatEncryptionKeyComponent.swift @@ -465,6 +465,7 @@ final class VideoChatEncryptionKeyComponent: Component { let theme: PresentationTheme let strings: PresentationStrings let emoji: [String] + let isShort: Bool let isExpanded: Bool let tapAction: () -> Void @@ -472,12 +473,14 @@ final class VideoChatEncryptionKeyComponent: Component { theme: PresentationTheme, strings: PresentationStrings, emoji: [String], + isShort: Bool, isExpanded: Bool, tapAction: @escaping () -> Void ) { self.theme = theme self.strings = strings self.emoji = emoji + self.isShort = isShort self.isExpanded = isExpanded self.tapAction = tapAction } @@ -492,6 +495,9 @@ final class VideoChatEncryptionKeyComponent: Component { if lhs.emoji != rhs.emoji { return false } + if lhs.isShort != rhs.isShort { + return false + } if lhs.isExpanded != rhs.isExpanded { return false } @@ -501,8 +507,7 @@ final class VideoChatEncryptionKeyComponent: Component { final class View: UIView { private let containerView: UIView private var emojiItems: [ComponentView] = [] - private let background = ComponentView() - private let backgroundShadowLayer = SimpleLayer() + private let backgroundView = GlassBackgroundView() private let collapsedText = ComponentView() private let expandedText = ComponentView() private let expandedSeparatorLayer = SimpleLayer() @@ -521,11 +526,12 @@ final class VideoChatEncryptionKeyComponent: Component { override init(frame: CGRect) { self.containerView = UIView() - self.containerView.clipsToBounds = true + //self.containerView.clipsToBounds = true super.init(frame: frame) self.addSubview(self.containerView) + self.containerView.addSubview(self.backgroundView) let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))) self.addGestureRecognizer(tapRecognizer) @@ -631,7 +637,7 @@ final class VideoChatEncryptionKeyComponent: Component { let collapsedTextSize = self.collapsedText.update( transition: .immediate, component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString(string: component.strings.VideoChat_EncryptionKeyLabel, font: Font.semibold(12.0), textColor: component.theme.list.itemPrimaryTextColor)) + text: .plain(NSAttributedString(string: component.isShort ? component.strings.VideoChat_EncryptionKeyLabelShort : component.strings.VideoChat_EncryptionKeyLabel, font: Font.semibold(12.0), textColor: component.theme.list.itemPrimaryTextColor)) )), environment: {}, containerSize: CGSize(width: 1000.0, height: 1000.0) @@ -688,36 +694,12 @@ final class VideoChatEncryptionKeyComponent: Component { let backgroundSize = component.isExpanded ? expandedSize : collapsedSize let backgroundCornerRadius: CGFloat = component.isExpanded ? 26.0 : collapsedSize.height * 0.5 - - let _ = self.background.update( - transition: transition, - component: AnyComponent(GlassBackgroundComponent(size: backgroundSize, cornerRadius: backgroundCornerRadius, isDark: true, tintColor: .init(kind: .panel, color: UIColor(rgb: 0x1f1f27)))), - environment: {}, - containerSize: backgroundSize - ) + let backgroundFrame = CGRect(origin: CGPoint(), size: backgroundSize) - if self.backgroundShadowLayer.superlayer == nil { - self.backgroundShadowLayer.backgroundColor = UIColor.clear.cgColor - self.containerView.layer.addSublayer(self.backgroundShadowLayer) - } - self.backgroundShadowLayer.shadowOpacity = 0.3 - self.backgroundShadowLayer.shadowColor = UIColor.black.cgColor - self.backgroundShadowLayer.shadowRadius = 5.0 - self.backgroundShadowLayer.shadowOffset = CGSize(width: 0.0, height: 2.0) - alphaTransition.setAlpha(layer: self.backgroundShadowLayer, alpha: component.isExpanded ? 1.0 : 0.0) - - transition.setFrame(layer: self.backgroundShadowLayer, frame: backgroundFrame) - transition.setCornerRadius(layer: self.backgroundShadowLayer, cornerRadius: backgroundCornerRadius) - transition.setShadowPath(layer: self.backgroundShadowLayer, path: UIBezierPath(roundedRect: CGRect(origin: CGPoint(), size: backgroundFrame.size), cornerRadius: backgroundCornerRadius).cgPath) - - if let backgroundView = self.background.view { - if backgroundView.superview == nil { - self.containerView.addSubview(backgroundView) - } - transition.setFrame(view: backgroundView, frame: backgroundFrame) - } - + self.backgroundView.update(size: backgroundSize, cornerRadius: backgroundCornerRadius, isDark: true, tintColor: .init(kind: .custom, color: UIColor(rgb: 0x161616, alpha: 0.6)), transition: transition) + transition.setFrame(view: self.backgroundView, frame: backgroundFrame) + var collapsedEmojiLeftOffset = collapsedSideInset var collapsedEmojiRightOffset = collapsedSize.width - collapsedSideInset diff --git a/submodules/TelegramCallsUI/Sources/VideoChatMicButtonComponent.swift b/submodules/TelegramCallsUI/Sources/VideoChatMicButtonComponent.swift index 74ec0933db..4dce36f2b3 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatMicButtonComponent.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatMicButtonComponent.swift @@ -365,7 +365,7 @@ final class VideoChatMicButtonComponent: Component { titleText = component.strings.VoiceChat_Unmute } case let .unmuted(isPushToTalk): - titleText = isPushToTalk ? component.strings.VoiceChat_Live : component.strings.VoiceChat_Mute + titleText = isPushToTalk ? component.strings.VoiceChat_Live : component.strings.VoiceChat_MuteShort case let .raiseHand(isRaised): if isRaised { titleText = component.strings.VoiceChat_AskedToSpeak diff --git a/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift b/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift index 84352b5721..b680ec4a28 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift @@ -35,6 +35,7 @@ import TextFormat import ReactionSelectionNode import EntityKeyboard import GlassBackgroundComponent +import EdgeEffect extension VideoChatCall { var myAudioLevelAndSpeaking: Signal<(Float, Bool), NoError> { @@ -255,6 +256,7 @@ final class VideoChatScreenComponent: Component { let participants = ComponentView() var scheduleInfo: ComponentView? + var inputDimView = UIButton() var inputPanelIsActive = false let inputPanel = ComponentView() let inputPanelExternalState = MessageInputPanelComponent.ExternalState() @@ -274,7 +276,7 @@ final class VideoChatScreenComponent: Component { weak var disappearingReactionContextNode: ReactionContextNode? weak var willDismissReactionContextNode: ReactionContextNode? - var messageNotifications: [(id: Int64, icon: VideoChatNotificationIcon, text: String, expiresOn: Int32)] = [] + var toastMessages: [(id: Int64, icon: VideoChatNotificationIcon, text: String, expiresOn: Int32)] = [] let messagesList = ComponentView() var messagesState: GroupCallMessagesContext.State? var messagesStateDisposable: Disposable? @@ -1433,6 +1435,7 @@ final class VideoChatScreenComponent: Component { guard let _ = self.inputPanel.view as? MessageInputPanelComponent.View else { return } + self.inputPanelIsActive = false self.currentInputMode = .text if hasFirstResponder(self) { if let view = self.inputPanel.view as? MessageInputPanelComponent.View { @@ -1842,7 +1845,7 @@ final class VideoChatScreenComponent: Component { } else { text = environment.strings.VoiceChat_DisplayAsSuccess(peer.displayTitle(strings: environment.strings, displayOrder: groupCall.accountContext.sharedContext.currentPresentationData.with({ $0 }).nameDisplayOrder)).string } - self.displayNotification(icon: .peer(peer), text: text, duration: 3) + self.displayToast(icon: .peer(peer), text: text, duration: 3) }) self.memberEventsDisposable?.dispose() @@ -1869,7 +1872,7 @@ final class VideoChatScreenComponent: Component { if displayEvent { let text = environment.strings.VoiceChat_PeerJoinedText("**\(event.peer.displayTitle(strings: environment.strings, displayOrder: groupCall.accountContext.sharedContext.currentPresentationData.with({ $0 }).nameDisplayOrder))**").string - self.displayNotification(icon: .peer(event.peer), text: text, duration: 3) + self.displayToast(icon: .peer(event.peer), text: text, duration: 3) } } } else { @@ -2196,6 +2199,8 @@ final class VideoChatScreenComponent: Component { self.containerView.layer.cornerRadius = containerOffset.isZero ? 0.0 : environment.deviceMetrics.screenCornerRadius } + transition.setFrame(view: self.inputDimView, frame: CGRect(origin: .zero, size: availableSize)) + transition.setFrame(view: self.containerView, frame: CGRect(origin: CGPoint(x: 0.0, y: containerOffset), size: availableSize), completion: { [weak self] completed in guard let self, completed else { return @@ -2253,7 +2258,7 @@ final class VideoChatScreenComponent: Component { let navigationButtonDiameter: CGFloat = 40.0 let navigationButtonInset: CGFloat = 4.0 - let panelColor = UIColor(rgb: 0x1f1f27) + let panelColor = UIColor(rgb: 0x161616, alpha: 0.6) let navigationLeftButtonSize = self.navigationLeftButton.update( transition: .immediate, @@ -2266,7 +2271,7 @@ final class VideoChatScreenComponent: Component { size: CGSize(width: 34.0, height: 34.0) )), background: AnyComponent( - GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), cornerRadius: navigationButtonDiameter * 0.5, isDark: true, tintColor: .init(kind: .panel, color: panelColor)) + GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), cornerRadius: navigationButtonDiameter * 0.5, isDark: true, tintColor: .init(kind: .custom, color: panelColor)) ), effectAlignment: .center, minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), @@ -2289,7 +2294,7 @@ final class VideoChatScreenComponent: Component { contentMode: .center )), background: AnyComponent( - GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), cornerRadius: navigationButtonDiameter * 0.5, isDark: true, tintColor: .init(kind: .panel, color: panelColor)) + GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), cornerRadius: navigationButtonDiameter * 0.5, isDark: true, tintColor: .init(kind: .custom, color: panelColor)) ), effectAlignment: .center, minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), @@ -2478,7 +2483,7 @@ final class VideoChatScreenComponent: Component { areButtonsCollapsed = true areButtonsActuallyCollapsed = false - mainColumnWidth = min(isLandscape ? 340.0 : 320.0, availableSize.width - leftInset - rightInset - 340.0) + mainColumnWidth = min(isLandscape ? 356.0 : 320.0, availableSize.width - leftInset - rightInset - 340.0) mainColumnSideInset = 0.0 } else { areButtonsCollapsed = true //self.expandedParticipantsVideoState != nil @@ -2520,6 +2525,7 @@ final class VideoChatScreenComponent: Component { theme: environment.theme, strings: environment.strings, emoji: self.encryptionKeyEmoji ?? [], + isShort: isTwoColumnLayout, isExpanded: self.isEncryptionKeyExpanded, tapAction: { [weak self] in guard let self else { @@ -2961,14 +2967,14 @@ final class VideoChatScreenComponent: Component { self.containerView.addSubview(encryptionKeyView) } - ComponentTransition.immediate.setScale(view: encryptionKeyView, scale: 0.001) - encryptionKeyView.alpha = 0.0 + //ComponentTransition.immediate.setScale(view: encryptionKeyView, scale: 0.001) + // encryptionKeyView.alpha = 0.0 } encryptionKeyTransition.setPosition(view: encryptionKeyView, position: encryptionKeyFrame.center) encryptionKeyTransition.setBounds(view: encryptionKeyView, bounds: CGRect(origin: CGPoint(), size: encryptionKeyFrame.size)) - transition.setScale(view: encryptionKeyView, scale: 1.0) - alphaTransition.setAlpha(view: encryptionKeyView, alpha: self.isAnimatedOutFromPrivateCall ? 0.0 : 1.0) + // transition.setScale(view: encryptionKeyView, scale: 1.0) +// alphaTransition.setAlpha(view: encryptionKeyView, alpha: self.isAnimatedOutFromPrivateCall ? 0.0 : 1.0) transition.setZPosition(layer: encryptionKeyView.layer, zPosition: self.isEncryptionKeyExpanded ? 1.0 : 0.0) @@ -3359,7 +3365,22 @@ final class VideoChatScreenComponent: Component { var inputPanelBottomInset: CGFloat = 0.0 var inputPanelSize: CGSize = .zero if self.inputPanelIsActive { - let inputPanelAvailableWidth = availableSize.width - environment.safeInsets.left - environment.safeInsets.right + if self.inputDimView.superview == nil { + self.inputDimView.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.4) + self.inputDimView.addTarget(self, action: #selector(self.deactivateInput), for: .touchUpInside) + self.inputDimView.alpha = 0.0 + + if let messageListView = self.messagesList.view, messageListView.superview != nil { + self.containerView.insertSubview(self.inputDimView, belowSubview: messageListView) + } else { + self.containerView.addSubview(self.inputDimView) + } + } + + ComponentTransition.easeInOut(duration: 0.25).setAlpha(view: self.inputDimView, alpha: 1.0) + + let inputPanelInnerInset: CGFloat = 8.0 + let inputPanelAvailableWidth = isTwoColumnLayout ? mainColumnWidth + inputPanelInnerInset * 2.0 : min(440.0 + inputPanelInnerInset * 2.0, availableSize.width - environment.safeInsets.left - environment.safeInsets.right) var inputPanelAvailableHeight = 103.0 let keyboardWasHidden = self.inputPanelExternalState.isKeyboardHidden @@ -3508,7 +3529,6 @@ final class VideoChatScreenComponent: Component { self.sendInput(randomId: transition?.randomId) } else { - self.inputPanelIsActive = false self.deactivateInput() } }, @@ -3588,7 +3608,17 @@ final class VideoChatScreenComponent: Component { inputPanelBottomInset = -inputPanelSize.height - environment.safeInsets.bottom } } - let inputPanelFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - inputPanelSize.width) / 2.0), y: availableSize.height - environment.safeInsets.bottom - inputPanelBottomInset - inputPanelSize.height - 3.0), size: inputPanelSize) + let inputPanelOriginX: CGFloat + if isTwoColumnLayout { + if buttonsOnTheSide { + inputPanelOriginX = availableSize.width - landscapeControlsWidth - mainColumnWidth - inputPanelInnerInset + } else { + inputPanelOriginX = availableSize.width - mainColumnWidth - inputPanelInnerInset - rightInset + } + } else { + inputPanelOriginX = floorToScreenPixels((availableSize.width - inputPanelSize.width) / 2.0) + } + let inputPanelFrame = CGRect(origin: CGPoint(x: inputPanelOriginX, y: availableSize.height - environment.safeInsets.bottom - inputPanelBottomInset - inputPanelSize.height - 3.0), size: inputPanelSize) if let inputPanelView = self.inputPanel.view { if inputPanelView.superview == nil { self.containerView.addSubview(inputPanelView) @@ -3598,6 +3628,8 @@ final class VideoChatScreenComponent: Component { } else { self.inputPanelExternalState.isEditing = false + transition.setAlpha(view: self.inputDimView, alpha: 0.0) + if let inputPanelView = self.inputPanel.view { var inputPanelFrame = inputPanelView.frame inputPanelFrame.origin.y = availableSize.height @@ -3645,6 +3677,16 @@ final class VideoChatScreenComponent: Component { effectiveDisplayReactions = true } + let reactionContextNodeOriginX: CGFloat + if isTwoColumnLayout { + if buttonsOnTheSide { + reactionContextNodeOriginX = availableSize.width - landscapeControlsWidth - mainColumnWidth * 0.5 - availableSize.width * 0.5 + } else { + reactionContextNodeOriginX = availableSize.width - mainColumnWidth * 0.5 - availableSize.width * 0.5 - rightInset + } + } else { + reactionContextNodeOriginX = 0.0 + } let reactionsAnchorRect: CGRect = CGRect(origin: CGPoint(x: availableSize.width - 44.0, y: availableSize.height - inputPanelBottomInset - inputPanelSize.height - 18.0), size: CGSize(width: 44.0, height: 44.0)) if let reactionItems = self.reactionItems, effectiveDisplayReactions { reactionsInset += 48.0 @@ -3724,7 +3766,17 @@ final class VideoChatScreenComponent: Component { } let targetSize = CGSize(width: 24.0, height: 24.0) - let targetView = UIView(frame: CGRect(origin: CGPoint(x: 230.0, y: self.bounds.height - targetSize.height - 133.0), size: targetSize)) + let targetViewOriginX: CGFloat + if isTwoColumnLayout { + if buttonsOnTheSide { + targetViewOriginX = availableSize.width - landscapeControlsWidth - mainColumnWidth * 0.5 + } else { + targetViewOriginX = availableSize.width - mainColumnWidth * 0.5 + } + } else { + targetViewOriginX = availableSize.width * 0.5 + } + let targetView = UIView(frame: CGRect(origin: CGPoint(x: targetViewOriginX + 20.0, y: self.bounds.height - targetSize.height - 133.0), size: targetSize)) targetView.isUserInteractionEnabled = false self.addSubview(targetView) @@ -3740,6 +3792,7 @@ final class VideoChatScreenComponent: Component { }) } + self.inputPanelIsActive = false if hasFirstResponder(self) { self.currentInputMode = .text self.endEditing(true) @@ -3825,8 +3878,7 @@ final class VideoChatScreenComponent: Component { animateReactionsIn = true self.containerView.addSubview(reactionContextNode.view) } - - reactionContextNodeTransition.setFrame(view: reactionContextNode.view, frame: CGRect(origin: CGPoint(), size: availableSize)) + reactionContextNodeTransition.setFrame(view: reactionContextNode.view, frame: CGRect(origin: CGPoint(x: reactionContextNodeOriginX, y: 0.0), size: availableSize)) reactionContextNode.updateLayout(size: availableSize, insets: UIEdgeInsets(), anchorRect: reactionsAnchorRect, centerAligned: true, isCoveredByInput: false, isAnimatingOut: false, transition: reactionContextNodeTransition.containedViewLayoutTransition) if animateReactionsIn { @@ -3848,7 +3900,7 @@ final class VideoChatScreenComponent: Component { } if let reactionContextNode = self.disappearingReactionContextNode { if !reactionContextNode.isAnimatingOutToReaction { - transition.setFrame(view: reactionContextNode.view, frame: CGRect(origin: CGPoint(), size: availableSize)) + transition.setFrame(view: reactionContextNode.view, frame: CGRect(origin: CGPoint(x: reactionContextNodeOriginX, y: 0.0), size: availableSize)) reactionContextNode.updateLayout(size: availableSize, insets: UIEdgeInsets(), anchorRect: reactionsAnchorRect, centerAligned: reactionContextNode.centerAligned, isCoveredByInput: false, isAnimatingOut: false, transition: transition.containedViewLayoutTransition) } } @@ -3883,7 +3935,7 @@ final class VideoChatScreenComponent: Component { } } - for notification in self.messageNotifications { + for notification in self.toastMessages { let icon: MessageItemComponent.Icon switch notification.icon { case let .peer(peer): @@ -3914,9 +3966,19 @@ final class VideoChatScreenComponent: Component { sendActionTransition: sendActionTransition )), environment: {}, - containerSize: CGSize(width: availableSize.width - environment.safeInsets.left - environment.safeInsets.right, height: availableSize.height - messagesBottomInset) + containerSize: CGSize(width: isTwoColumnLayout ? mainColumnWidth : min(440.0, availableSize.width - environment.safeInsets.left - environment.safeInsets.right), height: availableSize.height - messagesBottomInset) ) - let messagesListFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - messagesListSize.width) / 2.0), y: availableSize.height - messagesListSize.height - messagesBottomInset), size: messagesListSize) + let messageListOriginX: CGFloat + if isTwoColumnLayout { + if buttonsOnTheSide { + messageListOriginX = availableSize.width - landscapeControlsWidth - mainColumnWidth + } else { + messageListOriginX = availableSize.width - mainColumnWidth - rightInset + } + } else { + messageListOriginX = floorToScreenPixels((availableSize.width - messagesListSize.width) / 2.0) + } + let messagesListFrame = CGRect(origin: CGPoint(x: messageListOriginX, y: availableSize.height - messagesListSize.height - messagesBottomInset), size: messagesListSize) if let messagesListView = self.messagesList.view { if messagesListView.superview == nil { messagesListView.isUserInteractionEnabled = false diff --git a/submodules/TelegramCallsUI/Sources/VideoChatScreenMoreMenu.swift b/submodules/TelegramCallsUI/Sources/VideoChatScreenMoreMenu.swift index f1fd0514fa..e174f60440 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatScreenMoreMenu.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatScreenMoreMenu.swift @@ -249,7 +249,7 @@ extension VideoChatScreenComponent.View { iconName = "Call/ToastMessagesDisabled" text = environment.strings.VoiceChat_ToastMessagesDisabled } - self.displayNotification(icon: .icon(iconName), text: text, duration: 3) + self.displayToast(icon: .icon(iconName), text: text, duration: 3) }))) } diff --git a/submodules/TelegramCallsUI/Sources/VideoChatNotifications.swift b/submodules/TelegramCallsUI/Sources/VideoChatToasts.swift similarity index 66% rename from submodules/TelegramCallsUI/Sources/VideoChatNotifications.swift rename to submodules/TelegramCallsUI/Sources/VideoChatToasts.swift index 8fcf7a61de..86de23fcc3 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatNotifications.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatToasts.swift @@ -8,15 +8,15 @@ enum VideoChatNotificationIcon { } extension VideoChatScreenComponent.View { - func displayNotification(icon: VideoChatNotificationIcon, text: String, duration: Int32) { + func displayToast(icon: VideoChatNotificationIcon, text: String, duration: Int32) { let id = Int64.random(in: 0 ..< .max) let expiresOn = Int32(CFAbsoluteTimeGetCurrent()) + duration - self.messageNotifications.append((id: id, icon: icon, text: text, expiresOn: expiresOn)) + self.toastMessages.append((id: id, icon: icon, text: text, expiresOn: expiresOn)) self.state?.updated(transition: .spring(duration: 0.4)) Queue.mainQueue().after(Double(duration)) { - self.messageNotifications.removeAll(where: { $0.id == id }) + self.toastMessages.removeAll(where: { $0.id == id }) self.state?.updated(transition: .spring(duration: 0.4)) } } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 3364d2462d..e71ee5dd73 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -4905,6 +4905,7 @@ func replayFinalState( switch call { case let .groupCall(flags, _, _, participantsCount, title, _, recordStartDate, scheduleDate, _, _, _, _): + let isMin = (flags & (1 << 19)) != 0 let isMuted = (flags & (1 << 1)) != 0 let canChange = (flags & (1 << 2)) != 0 let isVideoEnabled = (flags & (1 << 9)) != 0 @@ -4914,7 +4915,7 @@ func replayFinalState( let messagesAreEnabled = GroupCallParticipantsContext.State.MessagesAreEnabled(isEnabled: messagesEnabled, canChange: canChangeMessagesEnabled) updatedGroupCallParticipants.append(( info.id, - .call(isTerminated: false, defaultParticipantsAreMuted: defaultParticipantsAreMuted, messagesAreEnabled: messagesAreEnabled, title: title, recordingStartTimestamp: recordStartDate, scheduleTimestamp: scheduleDate, isVideoEnabled: isVideoEnabled, participantCount: Int(participantsCount)) + .call(isTerminated: false, defaultParticipantsAreMuted: defaultParticipantsAreMuted, messagesAreEnabled: messagesAreEnabled, title: title, recordingStartTimestamp: recordStartDate, scheduleTimestamp: scheduleDate, isVideoEnabled: isVideoEnabled, participantCount: Int(participantsCount), isMin: isMin) )) default: break @@ -4923,7 +4924,7 @@ func replayFinalState( case let .groupCallDiscarded(callId, _, _): updatedGroupCallParticipants.append(( callId, - .call(isTerminated: true, defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: false, canChange: false), messagesAreEnabled: GroupCallParticipantsContext.State.MessagesAreEnabled(isEnabled: false, canChange: false), title: nil, recordingStartTimestamp: nil, scheduleTimestamp: nil, isVideoEnabled: false, participantCount: nil) + .call(isTerminated: true, defaultParticipantsAreMuted: GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: false, canChange: false), messagesAreEnabled: GroupCallParticipantsContext.State.MessagesAreEnabled(isEnabled: false, canChange: false), title: nil, recordingStartTimestamp: nil, scheduleTimestamp: nil, isVideoEnabled: false, participantCount: nil, isMin: false) )) if let peerId { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift b/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift index 560ca53c15..8b7aa9335f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift @@ -763,17 +763,18 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?, switch call { case let .groupCall(flags, _, _, _, title, _, recordStartDate, scheduleDate, _, unmutedVideoLimit, _, _): + let isMin = (flags & (1 << 19)) != 0 let isMuted = (flags & (1 << 1)) != 0 let canChange = (flags & (1 << 2)) != 0 let isVideoEnabled = (flags & (1 << 9)) != 0 let messagesEnabled = (flags & (1 << 17)) != 0 let canChangeMessagesEnabled = (flags & (1 << 18)) != 0 - state.defaultParticipantsAreMuted = GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: isMuted, canChange: canChange) - state.messagesAreEnabled = GroupCallParticipantsContext.State.MessagesAreEnabled(isEnabled: messagesEnabled, canChange: canChangeMessagesEnabled) + state.defaultParticipantsAreMuted = GroupCallParticipantsContext.State.DefaultParticipantsAreMuted(isMuted: isMuted, canChange: isMin ? state.defaultParticipantsAreMuted.canChange : canChange) + state.messagesAreEnabled = GroupCallParticipantsContext.State.MessagesAreEnabled(isEnabled: messagesEnabled, canChange: isMin ? state.messagesAreEnabled.canChange : canChangeMessagesEnabled) state.title = title state.recordingStartTimestamp = recordStartDate state.scheduleTimestamp = scheduleDate - state.isVideoEnabled = isVideoEnabled + state.isVideoEnabled = isMin ? state.isVideoEnabled : isVideoEnabled state.unmutedVideoLimit = Int(unmutedVideoLimit) default: break @@ -1586,7 +1587,7 @@ public final class GroupCallParticipantsContext { } case state(update: StateUpdate) - case call(isTerminated: Bool, defaultParticipantsAreMuted: State.DefaultParticipantsAreMuted, messagesAreEnabled: State.MessagesAreEnabled, title: String?, recordingStartTimestamp: Int32?, scheduleTimestamp: Int32?, isVideoEnabled: Bool, participantCount: Int?) + case call(isTerminated: Bool, defaultParticipantsAreMuted: State.DefaultParticipantsAreMuted, messagesAreEnabled: State.MessagesAreEnabled, title: String?, recordingStartTimestamp: Int32?, scheduleTimestamp: Int32?, isVideoEnabled: Bool, participantCount: Int?, isMin: Bool) case conferenceChainBlocks(subChainId: Int, blocks: [Data], nextOffset: Int) } @@ -1964,14 +1965,14 @@ public final class GroupCallParticipantsContext { for update in updates { if case let .state(update) = update { stateUpdates.append(update) - } else if case let .call(_, defaultParticipantsAreMuted, messagesAreEnabled, title, recordingStartTimestamp, scheduleTimestamp, isVideoEnabled, participantsCount) = update { + } else if case let .call(_, defaultParticipantsAreMuted, messagesAreEnabled, title, recordingStartTimestamp, scheduleTimestamp, isVideoEnabled, participantsCount, isMin) = update { var state = self.stateValue.state - state.defaultParticipantsAreMuted = defaultParticipantsAreMuted - state.messagesAreEnabled = messagesAreEnabled + state.defaultParticipantsAreMuted = isMin ? State.DefaultParticipantsAreMuted(isMuted: defaultParticipantsAreMuted.isMuted, canChange: state.defaultParticipantsAreMuted.canChange) : defaultParticipantsAreMuted + state.messagesAreEnabled = isMin ? State.MessagesAreEnabled(isEnabled: messagesAreEnabled.isEnabled, canChange: state.messagesAreEnabled.canChange) : messagesAreEnabled state.recordingStartTimestamp = recordingStartTimestamp state.title = title state.scheduleTimestamp = scheduleTimestamp - state.isVideoEnabled = isVideoEnabled + state.isVideoEnabled = isMin ? state.isVideoEnabled : isVideoEnabled if let participantsCount = participantsCount { state.totalCount = participantsCount } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift index 7d2cde5b0c..54b16a39bd 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift @@ -726,6 +726,9 @@ private extension StarsContext.State.Transaction { if (apiFlags & (1 << 25)) != 0 { flags.insert(.isStarGiftPrepaidUpgrade) } + if (apiFlags & (1 << 26)) != 0 { + flags.insert(.isStarGiftDropOriginalDetails) + } let media = extendedMedia.flatMap({ $0.compactMap { textMediaAndExpirationTimerFromApiMedia($0, PeerId(0)).media } }) ?? [] let _ = subscriptionPeriod @@ -782,6 +785,7 @@ public final class StarsContext { public static let isStarGiftResale = Flags(rawValue: 1 << 9) public static let isPostsSearch = Flags(rawValue: 1 << 10) public static let isStarGiftPrepaidUpgrade = Flags(rawValue: 1 << 11) + public static let isStarGiftDropOriginalDetails = Flags(rawValue: 1 << 12) } public enum Peer: Equatable { diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index 4bdc70a4fb..7d4fd7f666 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -4792,8 +4792,7 @@ private final class GiftViewSheetContent: CombinedComponent { if state.cachedSmallChevronImage == nil || state.cachedSmallChevronImage?.1 !== environment.theme { state.cachedSmallChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: theme.actionSheet.controlAccentColor)!, theme) } - //TODO:localize - let attributedString = NSMutableAttributedString(string: "See how price will decrease >", font: Font.regular(13.0), textColor: theme.actionSheet.controlAccentColor) + let attributedString = NSMutableAttributedString(string: strings.Gift_Upgrade_SeePriceDecrease, font: Font.regular(13.0), textColor: theme.actionSheet.controlAccentColor) if let range = attributedString.string.range(of: ">"), let chevronImage = state.cachedSmallChevronImage?.0 { attributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: attributedString.string)) } diff --git a/submodules/TelegramUI/Components/MessageInputPanelComponent/Sources/MessageInputPanelComponent.swift b/submodules/TelegramUI/Components/MessageInputPanelComponent/Sources/MessageInputPanelComponent.swift index 3476b86958..d5c6a34b7f 100644 --- a/submodules/TelegramUI/Components/MessageInputPanelComponent/Sources/MessageInputPanelComponent.swift +++ b/submodules/TelegramUI/Components/MessageInputPanelComponent/Sources/MessageInputPanelComponent.swift @@ -896,8 +896,9 @@ public final class MessageInputPanelComponent: Component { } }, isOneLineWhenUnfocused: component.style == .media, + emptyLineHandling: component.style == .glass ? .notAllowed : .allowed, formatMenuAvailability: component.isFormattingLocked ? .locked : .available(TextFieldComponent.FormatMenuAvailability.Action.all), - returnKeyType: component.style == .glass ? .done : .default, + returnKeyType: component.style == .glass ? .send : .default, lockedFormatAction: { component.presentTextFormattingTooltip?() }, diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 81025bf22e..0a9f7b7800 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -1503,17 +1503,10 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese if let note = cachedData.note, !note.text.isEmpty { var entities = note.entities - if !context.isPremium { - entities = entities.filter { entity in - switch entity.type { - case .Url, .TextUrl: - return false - default: - return true - } - } + if context.isPremium { + entities = generateTextEntities(note.text, enabledTypes: [.mention, .hashtag, .allUrl], currentEntities: entities) } - items[currentPeerInfoSection]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.PeerInfo_Notes, rightLabel: presentationData.strings.PeerInfo_NotesInfo, text: note.text, entities: entities, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: []), action: nil, linkItemAction: bioLinkAction, button: nil, contextAction: noteContextAction, requestLayout: { animated in + items[currentPeerInfoSection]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.PeerInfo_Notes, rightLabel: presentationData.strings.PeerInfo_NotesInfo, text: note.text, entities: entities, handleSpoilers: true, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: []), action: nil, linkItemAction: bioLinkAction, button: nil, contextAction: noteContextAction, requestLayout: { animated in interaction.requestLayout(animated) })) } @@ -4589,7 +4582,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro let noteUpdateSignal: Signal if noteUpdated, let note { - let entities = generateTextEntities(note.string, enabledTypes: [.mention, .hashtag, .allUrl], currentEntities: generateChatInputTextEntities(note)) + let entities = generateChatInputTextEntities(note) noteUpdateSignal = context.engine.contacts.updateContactNote(peerId: peer.id, text: note.string, entities: entities) |> mapError { _ -> ContactUpdateError in return .generic @@ -6680,7 +6673,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } } if !headerButtons.contains(.discussion) && hasDiscussion { - //TODO:localize items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_ViewDiscussion, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MessageBubble"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/GiftListItemComponent.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/GiftListItemComponent.swift index 87f23eca4a..3544197c64 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/GiftListItemComponent.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/GiftListItemComponent.swift @@ -16,8 +16,14 @@ import BalancedTextComponent import GiftLoadingShimmerView final class GiftListItemComponent: Component { + enum Subject { + case profile + case name + } + let context: AccountContext let theme: PresentationTheme + let subject: Subject let gifts: [StarGift.UniqueGift] let starGifts: [StarGift] let selectedId: Int64? @@ -28,6 +34,7 @@ final class GiftListItemComponent: Component { init( context: AccountContext, theme: PresentationTheme, + subject: Subject, gifts: [StarGift.UniqueGift], starGifts: [StarGift], selectedId: Int64?, @@ -37,6 +44,7 @@ final class GiftListItemComponent: Component { ) { self.context = context self.theme = theme + self.subject = subject self.gifts = gifts self.starGifts = starGifts self.selectedId = selectedId @@ -49,6 +57,9 @@ final class GiftListItemComponent: Component { if lhs.theme !== rhs.theme { return false } + if lhs.subject != rhs.subject { + return false + } if lhs.gifts != rhs.gifts { return false } @@ -156,6 +167,7 @@ final class GiftListItemComponent: Component { self.resaleGiftsState = state if !self.isUpdating { let transition: ComponentTransition = isFirstTime ? .easeInOut(duration: 0.25) : .immediate + self.state?.updated(transition: transition) component.updated(transition) } isFirstTime = false @@ -164,6 +176,7 @@ final class GiftListItemComponent: Component { if !self.isUpdating { let transition: ComponentTransition = .easeInOut(duration: 0.25) + self.state?.updated(transition: transition) component.updated(transition) } } @@ -186,11 +199,10 @@ final class GiftListItemComponent: Component { let rowSpacing: CGFloat = 10.0 let itemsInRow = 3 - //TODO:localize var tabSelectorItems: [TabSelectorComponent.Item] = [] tabSelectorItems.append(TabSelectorComponent.Item( id: AnyHashable(Int64(0)), - title: "My Gifts" + title: component.strings.ProfileColorSetup_MyGifts )) for gift in component.starGifts { @@ -257,6 +269,9 @@ final class GiftListItemComponent: Component { var uniqueGifts: [StarGift.UniqueGift] = [] for gift in resaleGiftsState.gifts { if case let .unique(uniqueGift) = gift { + if case let .peerId(peerId) = uniqueGift.owner, component.context.account.peerId == peerId { + continue + } uniqueGifts.append(uniqueGift) } } @@ -288,12 +303,21 @@ final class GiftListItemComponent: Component { environment: {}, containerSize: CGSize(width: emptyAnimationHeight, height: emptyAnimationHeight) ) - //TODO:localize + + + let emptyText: String + switch component.subject { + case .profile: + emptyText = component.strings.ProfileColorSetup_NoProfileGiftsPlaceholder + case .name: + emptyText = component.strings.ProfileColorSetup_NoNameGiftsPlaceholder + } + let emptyResultsTextSize = self.emptyResultsText.update( transition: .immediate, component: AnyComponent( BalancedTextComponent( - text: .plain(NSAttributedString(string: "You don't have any gifts you can use as styles for your profile.", font: Font.regular(13.0), textColor: component.theme.list.itemSecondaryTextColor)), + text: .plain(NSAttributedString(string: emptyText, font: Font.regular(13.0), textColor: component.theme.list.itemSecondaryTextColor)), horizontalAlignment: .center, maximumNumberOfLines: 0 ) @@ -306,7 +330,7 @@ final class GiftListItemComponent: Component { self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: component.theme.list.itemAccentColor)!, component.theme) } - let buttonAttributedString = NSMutableAttributedString(string: "Browse gifts available for purchase >", font: Font.regular(15.0), textColor: component.theme.list.itemAccentColor, paragraphAlignment: .center) + let buttonAttributedString = NSMutableAttributedString(string: component.strings.ProfileColorSetup_BrowseGiftsForPurchase, font: Font.regular(15.0), textColor: component.theme.list.itemAccentColor, paragraphAlignment: .center) if let range = buttonAttributedString.string.range(of: ">"), let chevronImage = self.cachedChevronImage?.0 { buttonAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: buttonAttributedString.string)) } diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/UserApperanceScreen.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/UserApperanceScreen.swift index a29ec3d6c6..22b366fab0 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/UserApperanceScreen.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/UserApperanceScreen.swift @@ -1221,7 +1221,6 @@ final class UserAppearanceScreenComponent: Component { maximumNumberOfLines: 0 )))) - //TODO:localize let footerAttributes = MarkdownAttributes( body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.freeTextColor), bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: environment.theme.list.freeTextColor), @@ -1230,7 +1229,7 @@ final class UserAppearanceScreenComponent: Component { return (TelegramTextAttributes.URL, contents) } ) - let previewFooterText = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString("You can also change color of your name and customize replies to you. [Change >]()", attributes: footerAttributes)) + let previewFooterText = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.ProfileColorSetup_ProfileColorPreviewInfo, attributes: footerAttributes)) if let range = previewFooterText.string.range(of: ">"), let chevronImage = self.cachedChevronImage?.0 { previewFooterText.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: previewFooterText.string)) } @@ -1392,7 +1391,6 @@ final class UserAppearanceScreenComponent: Component { if let status = resolvedState.emojiStatus, case let .starGift(id, _, _, _, _, _, _, _, _) = status.content { selectedGiftId = id } - //TODO:localize let giftsSectionSize = self.profileGiftsSection.update( transition: transition, component: AnyComponent(ListSectionComponent( @@ -1400,7 +1398,7 @@ final class UserAppearanceScreenComponent: Component { style: .glass, header: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( - string: "Your Gifts".uppercased(), + string: environment.strings.NameColor_GiftTitle.uppercased(), font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), textColor: environment.theme.list.freeTextColor )), @@ -1647,7 +1645,6 @@ final class UserAppearanceScreenComponent: Component { if case let .collectible(collectibleColor) = resolvedState.nameColor { selectedGiftId = collectibleColor.collectibleId } - //TODO:localize var peerColorStarGifts: [StarGift] = [] for gift in contentsData.starGifts { @@ -1663,7 +1660,7 @@ final class UserAppearanceScreenComponent: Component { style: .glass, header: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( - string: "Your Gifts".uppercased(), + string: environment.strings.NameColor_GiftTitle.uppercased(), font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), textColor: environment.theme.list.freeTextColor )), @@ -1721,9 +1718,8 @@ final class UserAppearanceScreenComponent: Component { contentHeight += bottomContentInset - //TODO:localize let buttonSideInset: CGFloat = environment.safeInsets.left + 36.0 - var buttonTitle = "Apply Style" // environment.strings.Channel_Appearance_ApplyButton + var buttonTitle = environment.strings.ProfileColorSetup_ApplyStyle var buttonAttributedSubtitleString: NSMutableAttributedString? if let gift = self.selectedProfileGift, let resellAmounts = gift.resellAmounts, let starsAmount = resellAmounts.first(where: { $0.currency == .stars }) { diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsListPanelComponent.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsListPanelComponent.swift index 319a099884..ee625122fd 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsListPanelComponent.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsListPanelComponent.swift @@ -315,7 +315,14 @@ final class StarsTransactionsListPanelComponent: Component { itemTitle = peer.displayTitle(strings: environment.strings, displayOrder: .firstLast) itemSubtitle = environment.strings.Stars_Intro_Transaction_PaidMessage(item.paidMessageCount ?? 1) } else if let starGift = item.starGift { - if item.flags.contains(.isStarGiftUpgrade), case let .unique(gift) = starGift { + if item.flags.contains(.isStarGiftPrepaidUpgrade) { + itemTitle = peer.displayTitle(strings: environment.strings, displayOrder: .firstLast) + itemSubtitle = environment.strings.Stars_Intro_Transaction_PrepaidGiftUpgrade + } else if item.flags.contains(.isStarGiftDropOriginalDetails), case let .unique(gift) = starGift { + itemTitle = "\(gift.title) #\(presentationStringsFormattedNumber(gift.number, environment.dateTimeFormat.groupingSeparator))" + itemSubtitle = environment.strings.Stars_Intro_Transaction_GiftDropOriginalDetails + uniqueGift = gift + } else if item.flags.contains(.isStarGiftUpgrade), case let .unique(gift) = starGift { itemTitle = "\(gift.title) #\(presentationStringsFormattedNumber(gift.number, environment.dateTimeFormat.groupingSeparator))" itemSubtitle = environment.strings.Stars_Intro_Transaction_GiftUpgrade uniqueGift = gift diff --git a/submodules/TelegramUI/Sources/ChatAdPanelNode.swift b/submodules/TelegramUI/Sources/ChatAdPanelNode.swift index 592b670e7c..718ae72368 100644 --- a/submodules/TelegramUI/Sources/ChatAdPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatAdPanelNode.swift @@ -375,15 +375,16 @@ final class ChatAdPanelNode: ASDisplayNode { } } + let (adLayout, adApply) = makeAdLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: strings.Chat_BotAd_Title, font: Font.semibold(14.0), textColor: theme.chat.inputPanel.panelControlAccentColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: width, height: .greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: .zero)) + + let titleConstrainedSize = CGSize(width: width - contentLeftInset - contentRightInset - textRightInset - adLayout.size.width - 90.0, height: CGFloat.greatestFiniteMagnitude) let textConstrainedSize = CGSize(width: width - contentLeftInset - contentRightInset - textRightInset, height: CGFloat.greatestFiniteMagnitude) - let (adLayout, adApply) = makeAdLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: strings.Chat_BotAd_Title, font: Font.semibold(14.0), textColor: theme.chat.inputPanel.panelControlAccentColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: .zero)) - var titleText: String = "" if let author = message.author { titleText = EnginePeer(author).compactDisplayTitle } - let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: titleText, font: Font.semibold(14.0), textColor: theme.chat.inputPanel.primaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: .zero)) + let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: titleText, font: Font.semibold(14.0), textColor: theme.chat.inputPanel.primaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: titleConstrainedSize, alignment: .natural, cutout: nil, insets: .zero)) let (textString, _, isText) = descriptionStringForMessage(contentSettings: context.currentContentSettings.with { $0 }, message: EngineMessage(message), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, accountPeerId: accountPeerId)