mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge commit 'c39b34d430'
This commit is contained in:
commit
3fe6791076
19 changed files with 199 additions and 103 deletions
|
|
@ -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 >";
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1105,7 +1105,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||
}
|
||||
}
|
||||
}
|
||||
case let .call(isTerminated, _, _, _, _, _, _, _):
|
||||
case let .call(isTerminated, _, _, _, _, _, _, _, _):
|
||||
if isTerminated {
|
||||
self.markAsCanBeRemoved()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Empty>] = []
|
||||
private let background = ComponentView<Empty>()
|
||||
private let backgroundShadowLayer = SimpleLayer()
|
||||
private let backgroundView = GlassBackgroundView()
|
||||
private let collapsedText = ComponentView<Empty>()
|
||||
private let expandedText = ComponentView<Empty>()
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<Empty>()
|
||||
var scheduleInfo: ComponentView<Empty>?
|
||||
|
||||
var inputDimView = UIButton()
|
||||
var inputPanelIsActive = false
|
||||
let inputPanel = ComponentView<Empty>()
|
||||
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<Empty>()
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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?()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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<Never, ContactUpdateError>
|
||||
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
|
||||
|
|
|
|||
|
|
@ -16,8 +16,15 @@ import BalancedTextComponent
|
|||
import GiftLoadingShimmerView
|
||||
|
||||
final class GiftListItemComponent: Component {
|
||||
enum Subject {
|
||||
case profile
|
||||
case name
|
||||
}
|
||||
|
||||
let context: AccountContext
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let subject: Subject
|
||||
let gifts: [StarGift.UniqueGift]
|
||||
let starGifts: [StarGift]
|
||||
let selectedId: Int64?
|
||||
|
|
@ -28,6 +35,8 @@ final class GiftListItemComponent: Component {
|
|||
init(
|
||||
context: AccountContext,
|
||||
theme: PresentationTheme,
|
||||
strings: PresentationStrings,
|
||||
subject: Subject,
|
||||
gifts: [StarGift.UniqueGift],
|
||||
starGifts: [StarGift],
|
||||
selectedId: Int64?,
|
||||
|
|
@ -37,6 +46,8 @@ final class GiftListItemComponent: Component {
|
|||
) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.subject = subject
|
||||
self.gifts = gifts
|
||||
self.starGifts = starGifts
|
||||
self.selectedId = selectedId
|
||||
|
|
@ -49,6 +60,12 @@ final class GiftListItemComponent: Component {
|
|||
if lhs.theme !== rhs.theme {
|
||||
return false
|
||||
}
|
||||
if lhs.strings !== rhs.strings {
|
||||
return false
|
||||
}
|
||||
if lhs.subject != rhs.subject {
|
||||
return false
|
||||
}
|
||||
if lhs.gifts != rhs.gifts {
|
||||
return false
|
||||
}
|
||||
|
|
@ -156,6 +173,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 +182,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 +205,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 +275,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 +309,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 +336,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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)),
|
||||
|
|
@ -1412,6 +1410,8 @@ final class UserAppearanceScreenComponent: Component {
|
|||
GiftListItemComponent(
|
||||
context: component.context,
|
||||
theme: environment.theme,
|
||||
strings: environment.strings,
|
||||
subject: .profile,
|
||||
gifts: contentsData.gifts,
|
||||
starGifts: contentsData.starGifts,
|
||||
selectedId: selectedGiftId,
|
||||
|
|
@ -1647,7 +1647,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 +1662,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
|
||||
)),
|
||||
|
|
@ -1675,6 +1674,8 @@ final class UserAppearanceScreenComponent: Component {
|
|||
GiftListItemComponent(
|
||||
context: component.context,
|
||||
theme: environment.theme,
|
||||
strings: environment.strings,
|
||||
subject: .name,
|
||||
gifts: self.starGifts,
|
||||
starGifts: peerColorStarGifts,
|
||||
selectedId: selectedGiftId,
|
||||
|
|
@ -1721,9 +1722,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 }) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue