diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index b9ac440c7f..89f15877f4 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -15367,3 +15367,8 @@ Error: %8$@"; "Stars.Transaction.LiveStreamPaidMessage_1" = "Fee for %@ Live Stream Message"; "Stars.Transaction.LiveStreamPaidMessage_any" = "Fee for %@ Live Stream Messages"; "Stars.Transaction.LiveStreamPaidMessage.Text" = "You receive **%@%** of the price that you charge for each incoming message."; + +"Notification.StarGift.Subtitle.NoConvert" = "We'll notify you once it becomes eligible for unique upgrades."; +"Notification.StarGift.Subtitle.OtherNoConvert" = "We'll notify %1$@ once it becomes eligible for unique upgrades."; +"Gift.View.NoConvertDescription" = "We'll notify you once it becomes eligible for unique upgrades."; +"Gift.View.OtherNoConvertDescription" = "We'll notify %1$@ once it becomes eligible for unique upgrades."; diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index b59c8fe046..d6b75900dc 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -205,6 +205,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att private let titleView: MediaPickerTitleView private let cancelButtonNode: WebAppCancelButtonNode + private var glassContainerView = GlassBackgroundContainerView() private var cancelButton: ComponentView? private var rightButton: ComponentView? private let moreButtonPlayOnce = ActionSlot() @@ -2572,6 +2573,14 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att transition.updateAlpha(layer: self.controllerNode.topEdgeEffectView.layer, alpha: self.controllerNode.scrolledExactlyToTop && self.controllerNode.currentDisplayMode == .all ? 0.0 : 1.0) self.controllerNode.topEdgeEffectView.update(content: topEdgeColor, blur: true, alpha: 0.8, rect: topEdgeEffectFrame, edge: .top, edgeSize: topEdgeEffectFrame.height, transition: ComponentTransition(transition)) + if self.cancelButton != nil { + if self.glassContainerView.superview == nil { + self.view.addSubview(self.glassContainerView) + } + self.glassContainerView.frame = CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: 72.0)) + self.glassContainerView.update(size: self.glassContainerView.frame.size, isDark: self.presentationData.theme.overallDarkAppearance, transition: .immediate) + } + if let cancelButton = self.cancelButton { if cancelButton.view == nil { buttonTransition = .immediate @@ -2599,7 +2608,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att let cancelButtonFrame = CGRect(origin: CGPoint(x: barButtonSideInset + layout.safeInsets.left, y: barButtonSideInset), size: cancelButtonSize) if let view = cancelButton.view { if view.superview == nil { - self.view.addSubview(view) + self.glassContainerView.contentView.addSubview(view) } view.bounds = CGRect(origin: .zero, size: cancelButtonFrame.size) view.center = cancelButtonFrame.center @@ -2634,7 +2643,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att let moreButtonFrame = CGRect(origin: CGPoint(x: layout.size.width - moreButtonSize.width - barButtonSideInset - layout.safeInsets.right, y: barButtonSideInset), size: moreButtonSize) if let view = moreButton.view { if view.superview == nil { - self.view.addSubview(view) + self.glassContainerView.contentView.addSubview(view) } view.bounds = CGRect(origin: .zero, size: moreButtonFrame.size) view.center = moreButtonFrame.center diff --git a/submodules/PremiumUI/Sources/PremiumGiftCodeScreen.swift b/submodules/PremiumUI/Sources/PremiumGiftCodeScreen.swift index 0e42910ba3..be0595440a 100644 --- a/submodules/PremiumUI/Sources/PremiumGiftCodeScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumGiftCodeScreen.swift @@ -12,7 +12,6 @@ import ViewControllerComponent import SheetComponent import MultilineTextComponent import BundleIconComponent -import SolidRoundedButtonComponent import Markdown import BalancedTextComponent import ConfettiEffect @@ -22,6 +21,8 @@ import TelegramStringFormatting import UndoUI import InvisibleInkDustNode import PremiumStarComponent +import GlassBarButtonComponent +import ButtonComponent private final class PremiumGiftCodeSheetContent: CombinedComponent { typealias EnvironmentType = ViewControllerComponentContainer.Environment @@ -74,9 +75,7 @@ private final class PremiumGiftCodeSheetContent: CombinedComponent { var initialized = false var peerMap: [EnginePeer.Id: EnginePeer] = [:] - - var cachedCloseImage: (UIImage, PresentationTheme)? - + var inProgress = false init(context: AccountContext, subject: PremiumGiftCodeScreen.Subject) { @@ -132,14 +131,14 @@ private final class PremiumGiftCodeSheetContent: CombinedComponent { } static var body: Body { - let closeButton = Child(Button.self) + let closeButton = Child(GlassBarButtonComponent.self) let title = Child(MultilineTextComponent.self) let star = Child(PremiumStarComponent.self) let description = Child(BalancedTextComponent.self) let linkButton = Child(Button.self) let table = Child(TableComponent.self) let additional = Child(BalancedTextComponent.self) - let button = Child(SolidRoundedButtonComponent.self) + let button = Child(ButtonComponent.self) return { context in let environment = context.environment[ViewControllerComponentContainer.Environment.self].value @@ -155,22 +154,23 @@ private final class PremiumGiftCodeSheetContent: CombinedComponent { let sideInset: CGFloat = 16.0 + environment.safeInsets.left let textSideInset: CGFloat = 32.0 + environment.safeInsets.left - let closeImage: UIImage - if let (image, theme) = state.cachedCloseImage, theme === environment.theme { - closeImage = image - } else { - closeImage = generateCloseButtonImage(backgroundColor: UIColor(rgb: 0x808084, alpha: 0.1), foregroundColor: theme.actionSheet.inputClearButtonColor)! - state.cachedCloseImage = (closeImage, theme) - } - let closeButton = closeButton.update( - component: Button( - content: AnyComponent(Image(image: closeImage)), - action: { [weak component] in - component?.cancel(true) + component: GlassBarButtonComponent( + size: CGSize(width: 40.0, height: 40.0), + backgroundColor: theme.rootController.navigationBar.glassBarButtonBackgroundColor, + isDark: theme.overallDarkAppearance, + state: .generic, + component: AnyComponentWithIdentity(id: "close", component: AnyComponent( + BundleIconComponent( + name: "Navigation/Close", + tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor + ) + )), + action: { _ in + component.cancel(true) } ), - availableSize: CGSize(width: 30.0, height: 30.0), + availableSize: CGSize(width: 40.0, height: 40.0), transition: .immediate ) @@ -312,7 +312,7 @@ private final class PremiumGiftCodeSheetContent: CombinedComponent { } } ), - availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0), + availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 52.0), transition: .immediate ) @@ -462,20 +462,21 @@ private final class PremiumGiftCodeSheetContent: CombinedComponent { availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height), transition: .immediate ) - + + let buttonInsets = ContainerViewLayout.concentricInsets(bottomInset: environment.safeInsets.bottom, innerDiameter: 52.0, sideInset: 30.0) let button = button.update( - component: SolidRoundedButtonComponent( - title: buttonText, - theme: SolidRoundedButtonComponent.Theme(theme: theme), - font: .bold, - fontSize: 17.0, - height: 50.0, - cornerRadius: 10.0, - gloss: gloss, - iconName: nil, - animationName: nil, - iconPosition: .left, - isLoading: state.inProgress, + component: ButtonComponent( + background: ButtonComponent.Background( + style: .glass, + color: theme.list.itemCheckColors.fillColor, + foreground: theme.list.itemCheckColors.foregroundColor, + pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9), + cornerRadius: 10.0, + ), + content: AnyComponentWithIdentity( + id: AnyHashable(0), + component: AnyComponent(MultilineTextComponent(text: .plain(NSMutableAttributedString(string: buttonText, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)))) + ), action: { [weak state] in if gloss { component.action() @@ -488,12 +489,12 @@ private final class PremiumGiftCodeSheetContent: CombinedComponent { } } ), - availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0), - transition: context.transition + availableSize: CGSize(width: context.availableSize.width - buttonInsets.left - buttonInsets.right, height: 52.0), + transition: .immediate ) context.add(title - .position(CGPoint(x: context.availableSize.width / 2.0, y: 28.0)) + .position(CGPoint(x: context.availableSize.width / 2.0, y: 36.0)) ) context.add(star @@ -501,7 +502,7 @@ private final class PremiumGiftCodeSheetContent: CombinedComponent { ) var originY: CGFloat = 0.0 - originY += star.size.height - 32.0 + originY += star.size.height - 24.0 context.add(description .position(CGPoint(x: context.availableSize.width / 2.0, y: originY + description.size.height / 2.0)) @@ -523,16 +524,17 @@ private final class PremiumGiftCodeSheetContent: CombinedComponent { ) originY += additional.size.height + 23.0 - let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: originY), size: button.size) context.add(button - .position(CGPoint(x: buttonFrame.midX, y: buttonFrame.midY)) + .position(CGPoint(x: context.availableSize.width / 2.0, y: originY + button.size.height / 2.0)) ) + originY += button.size.height + originY += buttonInsets.bottom context.add(closeButton - .position(CGPoint(x: context.availableSize.width - environment.safeInsets.left - closeButton.size.width, y: 28.0)) + .position(CGPoint(x: 16.0 + closeButton.size.width / 2.0, y: 16.0 + closeButton.size.height / 2.0)) ) - let contentSize = CGSize(width: context.availableSize.width, height: buttonFrame.maxY + 5.0 + environment.safeInsets.bottom) + let contentSize = CGSize(width: context.availableSize.width, height: originY) return contentSize } @@ -612,6 +614,7 @@ private final class PremiumGiftCodeSheetComponent: CombinedComponent { shareLink: context.component.shareLink, displayHiddenTooltip: context.component.displayHiddenTooltip )), + style: .glass, backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor), followContentSizeChanges: true, clipsContent: true, @@ -799,10 +802,10 @@ final class GiftLinkButtonContentComponent: CombinedComponent { return { context in let component = context.component - let sideInset: CGFloat = 38.0 + let sideInset: CGFloat = 42.0 let background = background.update( - component: RoundedRectangle(color: component.isSeparateSection ? component.theme.list.itemBlocksBackgroundColor : component.theme.list.itemInputField.backgroundColor, cornerRadius: 10.0), + component: RoundedRectangle(color: component.isSeparateSection ? component.theme.list.itemBlocksBackgroundColor : component.theme.list.itemInputField.backgroundColor, cornerRadius: 26.0), availableSize: context.availableSize, transition: context.transition ) @@ -989,8 +992,8 @@ private final class TableComponent: CombinedComponent { if let (currentImage, theme) = context.state.cachedBorderImage, theme === context.component.theme { borderImage = currentImage } else { - let borderRadius: CGFloat = 5.0 - borderImage = generateImage(CGSize(width: 16.0, height: 16.0), rotatedContext: { size, context in + let borderRadius: CGFloat = 14.0 + borderImage = generateImage(CGSize(width: borderRadius * 2.0 + 6.0, height: borderRadius * 2.0 + 6.0), rotatedContext: { size, context in let bounds = CGRect(origin: .zero, size: size) context.setFillColor(backgroundColor.cgColor) context.fill(bounds) @@ -1005,7 +1008,7 @@ private final class TableComponent: CombinedComponent { context.setLineWidth(borderWidth) context.addPath(path) context.strokePath() - })!.stretchableImage(withLeftCapWidth: 5, topCapHeight: 5) + })!.stretchableImage(withLeftCapWidth: Int(borderRadius), topCapHeight: Int(borderRadius)) context.state.cachedBorderImage = (borderImage, context.component.theme) } diff --git a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift index 496644cd0f..c383986b0e 100644 --- a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift +++ b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift @@ -368,8 +368,13 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { guard let self else { return } - self.giftAuctionStates = states - + self.giftAuctionStates = states.filter { state in + if case .ongoing = state.auctionState { + return true + } else { + return false + } + } }) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGiftsAuctions.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGiftsAuctions.swift index c4bf54f9a3..a83ed04ca1 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGiftsAuctions.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGiftsAuctions.swift @@ -432,18 +432,20 @@ public class GiftAuctionsManager { } private func updateState() { - var signals: [Signal] = [] + var signals: [Signal] = [] for auction in self.auctionContexts.values.sorted(by: { $0.gift.giftId < $1.gift.giftId }) { - signals.append(auction.state - |> mapToSignal { state in - if let state, state.myState.bidAmount != nil, case .ongoing = state.auctionState { - return .single(state) - } else { - return .complete() - } - }) + signals.append(auction.state) } - self.statePromise.set(combineLatest(signals)) + self.statePromise.set(combineLatest(signals) + |> map { states -> [GiftAuctionContext.State] in + var filteredStates: [GiftAuctionContext.State] = [] + for state in states { + if let state, case .ongoing = state.auctionState, state.myState.bidAmount != nil { + filteredStates.append(state) + } + } + return filteredStates + }) } } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift index 52ae49c1dc..44db6e68a2 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift @@ -554,16 +554,23 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { buttonTitle = item.presentationData.strings.Notification_PremiumPrize_View hasServiceMessage = false } - case let .starGift(gift, convertStars, giftText, giftEntities, _, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, isRefunded, isPrepaidUpgrade, _, channelPeerId, senderPeerId, _, _, _, _, _, _): + case let .starGift(gift, convertStars, giftText, giftEntities, _, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, isRefunded, isPrepaidUpgrade, _, channelPeerId, senderPeerId, _, _, _, _, _, toPeerId): + var incoming = incoming if case let .generic(gift) = gift { if let releasedBy = gift.releasedBy, let peer = item.message.peers[releasedBy], let addressName = peer.addressName { creatorButtonTitle = item.presentationData.strings.Notification_StarGift_ReleasedBy("**@\(addressName)**").string } - isStarGift = true - var authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? "" - - let isSelfGift = item.message.id.peerId == item.context.account.peerId + + var isSelfGift = item.message.id.peerId == item.context.account.peerId + if item.message.id.peerId.isTelegramNotifications, let toPeerId { + if toPeerId == item.context.account.peerId { + isSelfGift = true + } else { + incoming = false + } + } + let isChannelGift = item.message.id.peerId.namespace == Namespaces.Peer.CloudChannel || channelPeerId != nil if isSelfGift { title = item.presentationData.strings.Notification_StarGift_Self_Title @@ -572,10 +579,17 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { title = item.presentationData.strings.Gift_View_Unknown_Title } else { if let senderPeerId, let name = item.message.peers[senderPeerId].flatMap(EnginePeer.init)?.compactDisplayTitle { - authorName = name - title = item.presentationData.strings.Notification_StarGift_Title(authorName).string - } else if !incoming, let name = item.message.peers[item.message.id.peerId].flatMap(EnginePeer.init)?.compactDisplayTitle { - title = item.presentationData.strings.Notification_StarGift_TitleTo(name).string + title = item.presentationData.strings.Notification_StarGift_Title(name).string + } else if !incoming { + var recipientPeerId = item.message.id.peerId + if let toPeerId { + recipientPeerId = toPeerId + } + if let name = item.message.peers[recipientPeerId].flatMap(EnginePeer.init)?.compactDisplayTitle { + title = item.presentationData.strings.Notification_StarGift_TitleTo(name).string + } else { + title = item.presentationData.strings.Gift_View_Unknown_Title + } } else { title = item.presentationData.strings.Gift_View_Unknown_Title } @@ -614,8 +628,12 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { } } } else { + var recipientPeerId = item.message.id.peerId + if let toPeerId { + recipientPeerId = toPeerId + } var peerName = "" - if let peer = item.message.peers[item.message.id.peerId] { + if let peer = item.message.peers[recipientPeerId] { peerName = EnginePeer(peer).compactDisplayTitle } if peerName.isEmpty { @@ -637,6 +655,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { if let starsRange = formattedString.ranges.last { entities.append(MessageTextEntity(range: starsRange.range.lowerBound ..< starsRange.range.upperBound, type: .Bold)) } + } else { + text = item.presentationData.strings.Notification_StarGift_Subtitle_OtherNoConvert(peerName).string } } } diff --git a/submodules/TelegramUI/Components/FaceScanScreen/Sources/AgeVerificationScreen.swift b/submodules/TelegramUI/Components/FaceScanScreen/Sources/AgeVerificationScreen.swift index bb51ff3f62..761c842b09 100644 --- a/submodules/TelegramUI/Components/FaceScanScreen/Sources/AgeVerificationScreen.swift +++ b/submodules/TelegramUI/Components/FaceScanScreen/Sources/AgeVerificationScreen.swift @@ -182,6 +182,7 @@ private final class SheetContent: CombinedComponent { let controller = environment.controller() as? AgeVerificationScreen + let buttonInsets = ContainerViewLayout.concentricInsets(bottomInset: environment.safeInsets.bottom, innerDiameter: 52.0, sideInset: 30.0) let button = button.update( component: ButtonComponent( background: ButtonComponent.Background( @@ -201,15 +202,14 @@ private final class SheetContent: CombinedComponent { controller?.complete(result: true) } ), - availableSize: CGSize(width: context.availableSize.width - 30.0 * 2.0, height: 52.0), + availableSize: CGSize(width: context.availableSize.width - buttonInsets.left - buttonInsets.right, height: 52.0), transition: .immediate ) context.add(button .position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + button.size.height / 2.0)) ) contentSize.height += button.size.height - - contentSize.height += 30.0 + contentSize.height += buttonInsets.bottom return contentSize } @@ -366,27 +366,6 @@ public final class AgeVerificationScreen: ViewControllerComponentContainer { } } -func generateCloseButtonImage(backgroundColor: UIColor, foregroundColor: UIColor) -> UIImage? { - return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - - context.setFillColor(backgroundColor.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) - - context.setLineWidth(2.0) - context.setLineCap(.round) - context.setStrokeColor(foregroundColor.cgColor) - - context.move(to: CGPoint(x: 10.0, y: 10.0)) - context.addLine(to: CGPoint(x: 20.0, y: 20.0)) - context.strokePath() - - context.move(to: CGPoint(x: 20.0, y: 10.0)) - context.addLine(to: CGPoint(x: 10.0, y: 20.0)) - context.strokePath() - }) -} - public func presentAgeVerification(context: AccountContext, parentController: ViewController, completion: @escaping () -> Void) { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let _ = (contentSettingsConfiguration(network: context.account.network) diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionActiveBidsScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionActiveBidsScreen.swift index de8a302145..c9b99b3350 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionActiveBidsScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionActiveBidsScreen.swift @@ -260,8 +260,18 @@ private final class GiftAuctionActiveBidsScreenComponent: Component { guard let self else { return } - self.auctionStates = auctionStates + self.auctionStates = auctionStates.filter { state in + if case .ongoing = state.auctionState { + return true + } else { + return false + } + } self.state?.updated(transition: .immediate) + + if self.auctionStates.isEmpty { + self.environment?.controller()?.dismiss() + } }) self.giftAuctionTimer = SwiftSignalKit.Timer(timeout: 0.5, repeat: true, completion: { [weak self] in @@ -286,8 +296,12 @@ private final class GiftAuctionActiveBidsScreenComponent: Component { let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) var contentHeight: CGFloat = 75.0 + + var validKeys: Set = Set() for auctionState in self.auctionStates { let id = auctionState.gift.giftId + validKeys.insert(id) + let itemView: ComponentView if let current = self.itemsViews[id] { itemView = current @@ -340,6 +354,22 @@ private final class GiftAuctionActiveBidsScreenComponent: Component { } contentHeight -= 10.0 + var removeKeys: [Int64] = [] + for (id, item) in self.itemsViews { + if !validKeys.contains(id) { + removeKeys.append(id) + + if let itemView = item.view { + transition.setAlpha(view: itemView, alpha: 0.0, completion: { _ in + itemView.removeFromSuperview() + }) + } + } + } + for id in removeKeys { + self.itemsViews.removeValue(forKey: id) + } + if self.backgroundHandleView.image == nil { self.backgroundHandleView.image = generateStretchableFilledCircleImage(diameter: 5.0, color: .white)?.withRenderingMode(.alwaysTemplate) } diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift index ca6866402b..b92dc37999 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift @@ -1318,6 +1318,7 @@ private final class GiftAuctionBidScreenComponent: Component { if let actionButtonView = self.actionButton.view { actionButtonView.layer.animatePosition(from: CGPoint(x: 0.0, y: animateOffset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true) } + self.bottomEdgeEffectView.layer.animatePosition(from: CGPoint(x: 0.0, y: animateOffset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true) } func animateOut(completion: @escaping () -> Void) { @@ -1332,7 +1333,8 @@ private final class GiftAuctionBidScreenComponent: Component { if let actionButtonView = self.actionButton.view { actionButtonView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: animateOffset), duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true) } - + self.bottomEdgeEffectView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: animateOffset), duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true) + if let view = self.balanceOverlay.view { view.layer.animateScale(from: 1.0, to: 0.8, duration: 0.4, removeOnCompletion: false) view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) @@ -1683,9 +1685,6 @@ private final class GiftAuctionBidScreenComponent: Component { guard let component = self.component else { return } - if "".isEmpty { - return - } let controller = giftAuctionCustomBidController( context: component.context, title: "Place a Custom Bid", diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index 2a2e879880..296b4545bc 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -2410,6 +2410,11 @@ private final class GiftViewSheetContent: CombinedComponent { soldOut = true titleString = strings.Gift_View_UnavailableTitle } else if let arguments = subject.arguments { + if let toPeerId = arguments.auctionToPeerId { + isSelfGift = arguments.messageId?.peerId.isTelegramNotifications == true && toPeerId == component.context.account.peerId + } else { + isSelfGift = arguments.messageId?.peerId == component.context.account.peerId + } switch arguments.gift { case let .generic(gift): if let releasedBy = gift.releasedBy, let peer = state.peerMap[releasedBy], let addressName = peer.addressName { @@ -2451,13 +2456,15 @@ private final class GiftViewSheetContent: CombinedComponent { isChannelGift = true incoming = true } else { - incoming = arguments.incoming || arguments.peerId == component.context.account.peerId + if let toPeerId = arguments.auctionToPeerId, toPeerId != component.context.account.peerId { + incoming = false + } else { + incoming = arguments.incoming || arguments.peerId == component.context.account.peerId + } } nameHidden = arguments.nameHidden canGiftUpgrade = arguments.prepaidUpgradeHash != nil - isSelfGift = arguments.messageId?.peerId == component.context.account.peerId - if case let .peerId(peerId) = uniqueGift?.owner, peerId == component.context.account.peerId { isMyOwnedUniqueGift = true } @@ -3025,33 +3032,52 @@ private final class GiftViewSheetContent: CombinedComponent { } else if incoming { if let _ = upgradeStars { descriptionText = strings.Gift_View_FreeUpgradeDescription + } else if let gift = subject.arguments?.gift, case let .generic(gift) = gift, gift.availability != nil, !upgraded { + if canUpgrade || upgradeStars != nil { + if let upgradeStars, upgradeStars > 0 { + descriptionText = strings.Gift_View_UpgradeFreeDescription + } else { + descriptionText = strings.Gift_View_UpgradeDescription + } + } else { + descriptionText = strings.Gift_View_NoConvertDescription + } } else if let convertStars, !upgraded { if !converted { - if canUpgrade || upgradeStars != nil { - if let upgradeStars, upgradeStars > 0 { - descriptionText = strings.Gift_View_UpgradeFreeDescription - } else { - descriptionText = strings.Gift_View_UpgradeDescription - } - } else { - descriptionText = isChannelGift ? strings.Gift_View_KeepOrConvertDescription_Channel(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(clamping: convertStars))).string : strings.Gift_View_KeepOrConvertDescription(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(clamping: convertStars))).string - } + descriptionText = isChannelGift ? strings.Gift_View_KeepOrConvertDescription_Channel(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(clamping: convertStars))).string : strings.Gift_View_KeepOrConvertDescription(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(clamping: convertStars))).string } else { descriptionText = strings.Gift_View_ConvertedDescription(strings.Gift_View_ConvertedDescription_Stars(Int32(clamping: convertStars))).string } } else { - descriptionText = strings.Gift_View_BotDescription + descriptionText = strings.Gift_View_NoConvertDescription } - } else if let peerId = subject.arguments?.peerId, let peer = state.peerMap[peerId] { - if let _ = upgradeStars { - descriptionText = strings.Gift_View_FreeUpgradeOtherDescription(peer.compactDisplayTitle).string - } else if case .message = subject, let convertStars { - descriptionText = strings.Gift_View_OtherDescription(peer.compactDisplayTitle, strings.Gift_View_OtherDescription_Stars(Int32(clamping: convertStars))).string + } else { + let recipientPeerId: EnginePeer.Id? + if let toPeerId = subject.arguments?.auctionToPeerId { + recipientPeerId = toPeerId + } else if let peerId = subject.arguments?.peerId { + recipientPeerId = peerId + } else { + recipientPeerId = nil + } + + if let recipientPeerId, let peer = state.peerMap[recipientPeerId] { + if let _ = upgradeStars { + descriptionText = strings.Gift_View_FreeUpgradeOtherDescription(peer.compactDisplayTitle).string + } else if case .message = subject { + if let gift = subject.arguments?.gift, case let .generic(gift) = gift, gift.availability != nil { + descriptionText = strings.Gift_View_OtherNoConvertDescription(peer.compactDisplayTitle).string + } else if let convertStars { + descriptionText = strings.Gift_View_OtherDescription(peer.compactDisplayTitle, strings.Gift_View_OtherDescription_Stars(Int32(clamping: convertStars))).string + } else { + descriptionText = "" + } + } else { + descriptionText = "" + } } else { descriptionText = "" } - } else { - descriptionText = "" } if let spaceRegex { let nsRange = NSRange(descriptionText.startIndex..., in: descriptionText) @@ -3497,7 +3523,10 @@ private final class GiftViewSheetContent: CombinedComponent { )) } - } else if let peerId = subject.arguments?.fromPeerId, let peer = state.peerMap[peerId] { + } else if let peerId = subject.arguments?.fromPeerId, var peer = state.peerMap[peerId] { + if let toPeerId = subject.arguments?.auctionToPeerId, toPeerId != component.context.account.peerId, let selfPeer = state.peerMap[component.context.account.peerId] { + peer = selfPeer + } var isBot = false if case let .user(user) = peer, user.botInfo != nil { isBot = true @@ -5128,12 +5157,43 @@ public class GiftViewScreen: ViewControllerComponentContainer { case upgradePreview([StarGift.UniqueGift.Attribute], String) case wearPreview(StarGift.UniqueGift) - var arguments: (peerId: EnginePeer.Id?, fromPeerId: EnginePeer.Id?, fromPeerName: String?, fromPeerCompactName: String?, messageId: EngineMessage.Id?, reference: StarGiftReference?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, pinnedToTop: Bool?, converted: Bool, upgraded: Bool, refunded: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, resellAmounts: [CurrencyAmount]?, canExportDate: Int32?, upgradeMessageId: Int32?, canTransferDate: Int32?, canResaleDate: Int32?, prepaidUpgradeHash: String?, upgradeSeparate: Bool, dropOriginalDetailsStars: Int64?)? { + var arguments: ( + peerId: EnginePeer.Id?, + fromPeerId: EnginePeer.Id?, + fromPeerName: String?, + fromPeerCompactName: String?, + messageId: EngineMessage.Id?, + reference: StarGiftReference?, + incoming: Bool, + gift: StarGift, + date: Int32, + convertStars: Int64?, + text: String?, + entities: [MessageTextEntity]?, + nameHidden: Bool, + savedToProfile: Bool, + pinnedToTop: Bool?, + converted: Bool, + upgraded: Bool, + refunded: Bool, + canUpgrade: Bool, + upgradeStars: Int64?, + transferStars: Int64?, + resellAmounts: [CurrencyAmount]?, + canExportDate: Int32?, + upgradeMessageId: Int32?, + canTransferDate: Int32?, + canResaleDate: Int32?, + prepaidUpgradeHash: String?, + upgradeSeparate: Bool, + dropOriginalDetailsStars: Int64?, + auctionToPeerId: EnginePeer.Id? + )? { switch self { case let .message(message): if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction { switch action.action { - case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, isRefunded, _, upgradeMessageId, peerId, senderId, savedId, prepaidUpgradeHash, giftMessageId, upgradeSeparate, _, _): + case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, isRefunded, _, upgradeMessageId, peerId, senderId, savedId, prepaidUpgradeHash, giftMessageId, upgradeSeparate, _, toPeerId): var reference: StarGiftReference if let peerId, let giftMessageId { reference = .message(messageId: EngineMessage.Id(peerId: peerId, namespace: Namespaces.Message.Cloud, id: giftMessageId)) @@ -5142,7 +5202,9 @@ public class GiftViewScreen: ViewControllerComponentContainer { } else { reference = .message(messageId: message.id) } - return (message.id.peerId, senderId ?? message.author?.id, message.author?.debugDisplayTitle, message.author?.compactDisplayTitle, message.id, reference, message.flags.contains(.Incoming), gift, message.timestamp, convertStars, text, entities, nameHidden, savedToProfile, nil, converted, upgraded, isRefunded, canUpgrade, upgradeStars, nil, nil, nil, upgradeMessageId, nil, nil, prepaidUpgradeHash, upgradeSeparate, nil) + + let fromPeerId = senderId ?? message.author?.id + return (message.id.peerId, fromPeerId, message.author?.debugDisplayTitle, message.author?.compactDisplayTitle, message.id, reference, message.flags.contains(.Incoming), gift, message.timestamp, convertStars, text, entities, nameHidden, savedToProfile, nil, converted, upgraded, isRefunded, canUpgrade, upgradeStars, nil, nil, nil, upgradeMessageId, nil, nil, prepaidUpgradeHash, upgradeSeparate, nil, toPeerId) case let .starGiftUnique(gift, isUpgrade, isTransferred, savedToProfile, canExportDate, transferStars, _, _, peerId, senderId, savedId, _, canTransferDate, canResaleDate, dropOriginalDetailsStars, _): var reference: StarGiftReference if let peerId, let savedId { @@ -5167,13 +5229,13 @@ public class GiftViewScreen: ViewControllerComponentContainer { if case let .unique(uniqueGift) = gift { resellAmounts = uniqueGift.resellAmounts } - return (message.id.peerId, senderId ?? message.author?.id, message.author?.debugDisplayTitle, message.author?.compactDisplayTitle, message.id, reference, incoming, gift, message.timestamp, nil, nil, nil, false, savedToProfile, nil, false, false, false, false, nil, transferStars, resellAmounts, canExportDate, nil, canTransferDate, canResaleDate, nil, false, dropOriginalDetailsStars) + return (message.id.peerId, senderId ?? message.author?.id, message.author?.debugDisplayTitle, message.author?.compactDisplayTitle, message.id, reference, incoming, gift, message.timestamp, nil, nil, nil, false, savedToProfile, nil, false, false, false, false, nil, transferStars, resellAmounts, canExportDate, nil, canTransferDate, canResaleDate, nil, false, dropOriginalDetailsStars, nil) default: return nil } } case let .uniqueGift(gift, _), let .wearPreview(gift): - return (nil, nil, nil, nil, nil, nil, false, .unique(gift), 0, nil, nil, nil, false, false, nil, false, false, false, false, nil, nil, gift.resellAmounts, nil, nil, nil, nil, nil, false, nil) + return (nil, nil, nil, nil, nil, nil, false, .unique(gift), 0, nil, nil, nil, false, false, nil, false, false, false, false, nil, nil, gift.resellAmounts, nil, nil, nil, nil, nil, false, nil, nil) case let .profileGift(peerId, gift): var messageId: EngineMessage.Id? if case let .message(messageIdValue) = gift.reference { @@ -5183,7 +5245,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { if case let .unique(uniqueGift) = gift.gift { resellAmounts = uniqueGift.resellAmounts } - return (peerId, gift.fromPeer?.id, gift.fromPeer?.debugDisplayTitle, gift.fromPeer?.compactDisplayTitle, messageId, gift.reference, false, gift.gift, gift.date, gift.convertStars, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, gift.pinnedToTop, false, false, false, gift.canUpgrade, gift.upgradeStars, gift.transferStars, resellAmounts, gift.canExportDate, nil, gift.canTransferDate, gift.canResaleDate, gift.prepaidUpgradeHash, gift.upgradeSeparate, gift.dropOriginalDetailsStars) + return (peerId, gift.fromPeer?.id, gift.fromPeer?.debugDisplayTitle, gift.fromPeer?.compactDisplayTitle, messageId, gift.reference, false, gift.gift, gift.date, gift.convertStars, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, gift.pinnedToTop, false, false, false, gift.canUpgrade, gift.upgradeStars, gift.transferStars, resellAmounts, gift.canExportDate, nil, gift.canTransferDate, gift.canResaleDate, gift.prepaidUpgradeHash, gift.upgradeSeparate, gift.dropOriginalDetailsStars, nil) case .soldOutGift: return nil case .upgradePreview: diff --git a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/BUILD b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/BUILD index c55b3c36f6..573462e416 100644 --- a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/BUILD +++ b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/BUILD @@ -40,6 +40,7 @@ swift_library( "//submodules/TelegramUI/Components/ChatScheduleTimeController", "//submodules/TelegramUI/Components/TabSelectorComponent", "//submodules/TelegramUI/Components/Stars/BalanceNeededScreen", + "//submodules/TelegramUI/Components/GlassBarButtonComponent", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift index df8957dc2b..42dad06ae6 100644 --- a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift @@ -26,6 +26,7 @@ import ChatScheduleTimeController import TabSelectorComponent import PresentationDataUtils import BalanceNeededScreen +import GlassBarButtonComponent private let amountTag = GenericComponentViewTag() @@ -54,7 +55,8 @@ private final class SheetContent: CombinedComponent { } static var body: (CombinedComponentContext) -> CGSize { - let closeButton = Child(Button.self) + let closeButton = Child(GlassBarButtonComponent.self) + let cancelButton = Child(Button.self) let balance = Child(BalanceComponent.self) let title = Child(Text.self) let currencyToggle = Child(TabSelectorComponent.self) @@ -114,7 +116,7 @@ private final class SheetContent: CombinedComponent { ) } - let closeButton = closeButton.update( + let cancelButton = cancelButton.update( component: Button( content: AnyComponent(Text(text: environment.strings.Common_Cancel, font: Font.regular(17.0), color: environment.theme.list.itemAccentColor)), action: { @@ -124,30 +126,32 @@ private final class SheetContent: CombinedComponent { availableSize: CGSize(width: 200.0, height: 100.0), transition: .immediate ) - let closeFrame = CGRect(origin: CGPoint(x: 16.0, y: floor((56.0 - closeButton.size.height) * 0.5)), size: closeButton.size) - context.add(closeButton + let closeFrame = CGRect(origin: CGPoint(x: 16.0, y: floor((56.0 - cancelButton.size.height) * 0.5)), size: cancelButton.size) + context.add(cancelButton .position(closeFrame.center) ) } else { - let closeImage: UIImage - if let (image, theme) = state.cachedCloseImage, theme === environment.theme { - closeImage = image - } else { - closeImage = generateCloseButtonImage(backgroundColor: UIColor(rgb: 0x808084, alpha: 0.1), foregroundColor: theme.actionSheet.inputClearButtonColor)! - state.cachedCloseImage = (closeImage, theme) - } let closeButton = closeButton.update( - component: Button( - content: AnyComponent(Image(image: closeImage)), - action: { + component: GlassBarButtonComponent( + size: CGSize(width: 40.0, height: 40.0), + backgroundColor: theme.rootController.navigationBar.glassBarButtonBackgroundColor, + isDark: theme.overallDarkAppearance, + state: .generic, + component: AnyComponentWithIdentity(id: "close", component: AnyComponent( + BundleIconComponent( + name: "Navigation/Close", + tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor + ) + )), + action: { _ in component.dismiss() } ), - availableSize: CGSize(width: 30.0, height: 30.0), + availableSize: CGSize(width: 40.0, height: 40.0), transition: .immediate ) context.add(closeButton - .position(CGPoint(x: context.availableSize.width - closeButton.size.width, y: 28.0)) + .position(CGPoint(x: 16.0 + closeButton.size.width / 2.0, y: 16.0 + closeButton.size.height / 2.0)) ) } @@ -257,7 +261,7 @@ private final class SheetContent: CombinedComponent { transition: .immediate ) context.add(title - .position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + title.size.height / 2.0)) + .position(CGPoint(x: context.availableSize.width / 2.0, y: 36.0)) ) contentSize.height += title.size.height contentSize.height += 40.0 @@ -537,6 +541,7 @@ private final class SheetContent: CombinedComponent { let amountSection = amountSection.update( component: ListSectionComponent( theme: theme, + style: .glass, header: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( string: amountTitle.uppercased(), @@ -838,13 +843,14 @@ private final class SheetContent: CombinedComponent { isButtonEnabled = true } + let buttonInsets = ContainerViewLayout.concentricInsets(bottomInset: environment.safeInsets.bottom, innerDiameter: 52.0, sideInset: 30.0) let button = button.update( component: ButtonComponent( background: ButtonComponent.Background( + style: .glass, color: theme.list.itemCheckColors.fillColor, foreground: theme.list.itemCheckColors.foregroundColor, - pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9), - cornerRadius: 10.0 + pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9) ), content: AnyComponentWithIdentity( id: AnyHashable(0), @@ -931,19 +937,21 @@ private final class SheetContent: CombinedComponent { } } ), - availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50), + availableSize: CGSize(width: context.availableSize.width - buttonInsets.left - buttonInsets.right, height: 52.0), transition: .immediate ) context.add(button - .clipsToBounds(true) - .cornerRadius(10.0) .position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + button.size.height / 2.0)) ) contentSize.height += button.size.height - contentSize.height += 15.0 - contentSize.height += max(environment.inputHeight, environment.safeInsets.bottom) - + if environment.inputHeight > 0.0 { + contentSize.height += 15.0 + contentSize.height += max(environment.inputHeight, environment.safeInsets.bottom) + } else { + contentSize.height += buttonInsets.bottom + } + return contentSize } @@ -965,7 +973,6 @@ private final class SheetContent: CombinedComponent { fileprivate var tonBalance: StarsAmount? private var tonStateDisposable: Disposable? - var cachedCloseImage: (UIImage, PresentationTheme)? var cachedStarImage: (UIImage, PresentationTheme)? var cachedTonImage: (UIImage, PresentationTheme)? var cachedChevronImage: (UIImage, PresentationTheme)? @@ -1130,6 +1137,7 @@ private final class StarsWithdrawSheetComponent: CombinedComponent { }) } )), + style: .glass, backgroundColor: .color(environment.theme.list.blocksBackgroundColor), followContentSizeChanges: false, clipsContent: true, @@ -1696,7 +1704,7 @@ private final class AmountFieldComponent: Component { self.component = component self.state = state - let size = CGSize(width: availableSize.width, height: 44.0) + let size = CGSize(width: availableSize.width, height: 52.0) let sideInset: CGFloat = 16.0 var leftInset: CGFloat = 16.0 @@ -1782,7 +1790,7 @@ private final class AmountFieldComponent: Component { labelView.removeFromSuperview() } - self.textField.frame = CGRect(x: leftInset, y: 0.0, width: size.width - 30.0, height: 44.0) + self.textField.frame = CGRect(x: leftInset, y: 4.0, width: size.width - 30.0, height: 44.0) return size }