diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index cebd229c5b..93cd1bad2e 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -15697,8 +15697,8 @@ Error: %8$@"; "Gift.Craft.Info.Paragraph3.Title" = "Affect the Result"; "Gift.Craft.Info.Paragraph3.Text" = "Use gifts with the same attribute to boost it's chance."; "Gift.Craft.Info.Understood" = "Understood"; -"Gift.Craft.Unavailable.Title" = "Try Later"; -"Gift.Craft.Unavailable.Text" = "You will be able to craft this gift on %@."; +"Gift.Craft.Unavailable.Title" = "Crafting Unavailable"; +"Gift.Craft.Unavailable.Text" = "This gift will become available for crafting on **%@**."; "Gift.Craft.Error.NotAvailable" = "One of the gifts is not available for crafting."; "Gift.Craft.Select.Title" = "Select Gifts"; diff --git a/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift b/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift index 20dbcfde9e..1e6f247d47 100644 --- a/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift +++ b/submodules/Components/ResizableSheetComponent/Sources/ResizableSheetComponent.swift @@ -623,7 +623,7 @@ public final class ResizableSheetComponent() - private let cancelButton = ComponentView() + private let buttons = ComponentView() + private let actionButton = ComponentView() private let title = ComponentView() private let mainText = ComponentView() @@ -110,6 +111,43 @@ private final class ScheduleVideoChatSheetContentComponent: Component { var contentHeight: CGFloat = 0.0 contentHeight += 16.0 + let buttonsSize = self.buttons.update( + transition: transition, + component: AnyComponent( + GlassControlPanelComponent( + theme: environment.theme, + leftItem: GlassControlPanelComponent.Item( + items: [ + GlassControlGroupComponent.Item( + id: AnyHashable("close"), + content: .icon("Navigation/Close"), + action: { [weak self] in + guard let component = self?.component else { + return + } + component.dismiss() + } + ) + ], + background: .panel + ), + centralItem: nil, + rightItem: nil, + centerAlignmentIfPossible: true, + isDark: true + ) + ), + environment: {}, + containerSize: CGSize(width: availableSize.width - 16.0 * 2.0, height: 44.0) + ) + if let buttonsView = self.buttons.view { + if buttonsView.superview == nil { + self.addSubview(buttonsView) + } + transition.setFrame(view: buttonsView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - buttonsSize.width) * 0.5), y: contentHeight), size: buttonsSize)) + } + contentHeight += buttonsSize.height + let titleString = NSMutableAttributedString() titleString.append(NSAttributedString(string: environment.strings.VideoChat_ScheduleButtonTitle, font: Font.semibold(17.0), textColor: environment.theme.list.itemPrimaryTextColor)) @@ -126,9 +164,8 @@ private final class ScheduleVideoChatSheetContentComponent: Component { if titleView.superview == nil { self.addSubview(titleView) } - transition.setFrame(view: titleView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5), y: contentHeight), size: titleSize)) + transition.setFrame(view: titleView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5), y: contentHeight - buttonsSize.height * 0.5 - titleSize.height * 0.5), size: titleSize)) } - contentHeight += titleSize.height contentHeight += 16.0 let pickerView: UIDatePicker @@ -221,17 +258,20 @@ private final class ScheduleVideoChatSheetContentComponent: Component { transition.setFrame(view: mainTextView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - mainTextSize.width) * 0.5), y: contentHeight), size: mainTextSize)) } contentHeight += mainTextSize.height - contentHeight += 10.0 + contentHeight += 32.0 var buttonContents: [AnyComponentWithIdentity] = [] buttonContents.append(AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent( Text(text: buttonTitle, font: Font.semibold(17.0), color: environment.theme.list.itemCheckColors.foregroundColor) ))) let buttonTransition = transition - let buttonSize = self.button.update( + + let buttonInsets = ContainerViewLayout.concentricInsets(bottomInset: environment.safeInsets.bottom, innerDiameter: 52.0, sideInset: 30.0) + let buttonSize = self.actionButton.update( transition: buttonTransition, component: AnyComponent(ButtonComponent( background: ButtonComponent.Background( + style: .glass, color: UIColor(rgb: 0x3252EF), foreground: .white, pressedColor: UIColor(rgb: 0x3252EF).withMultipliedAlpha(0.8) @@ -250,56 +290,17 @@ private final class ScheduleVideoChatSheetContentComponent: Component { } )), environment: {}, - containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 50.0) + containerSize: CGSize(width: availableSize.width - buttonInsets.left - buttonInsets.right, height: 52.0) ) - let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: buttonSize) - if let buttonView = self.button.view { + let buttonFrame = CGRect(origin: CGPoint(x: buttonInsets.left, y: contentHeight), size: buttonSize) + if let buttonView = self.actionButton.view { if buttonView.superview == nil { self.addSubview(buttonView) } transition.setFrame(view: buttonView, frame: buttonFrame) } contentHeight += buttonSize.height - contentHeight += 10.0 - - let cancelButtonSize = self.cancelButton.update( - transition: buttonTransition, - component: AnyComponent(ButtonComponent( - background: ButtonComponent.Background( - color: UIColor(rgb: 0x2B2B2F), - foreground: .white, - pressedColor: UIColor(rgb: 0x2B2B2F).withMultipliedAlpha(0.8) - ), - content: AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent( - Text(text: environment.strings.Common_Cancel, font: Font.semibold(17.0), color: environment.theme.list.itemPrimaryTextColor) - )), - isEnabled: true, - tintWhenDisabled: false, - displaysProgress: false, - action: { [weak self] in - guard let self, let component = self.component else { - return - } - component.dismiss() - } - )), - environment: {}, - containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 50.0) - ) - let cancelButtonFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: cancelButtonSize) - if let cancelButtonView = self.cancelButton.view { - if cancelButtonView.superview == nil { - self.addSubview(cancelButtonView) - } - transition.setFrame(view: cancelButtonView, frame: cancelButtonFrame) - } - contentHeight += cancelButtonSize.height - - if environment.safeInsets.bottom.isZero { - contentHeight += 16.0 - } else { - contentHeight += environment.safeInsets.bottom + 14.0 - } + contentHeight += buttonInsets.bottom return CGSize(width: availableSize.width, height: contentHeight) } @@ -407,7 +408,8 @@ private final class ScheduleVideoChatSheetScreenComponent: Component { }) } )), - backgroundColor: .color(UIColor(rgb: 0x1C1C1E)), + style: .glass, + backgroundColor: .color(UIColor(rgb: 0x1c1c1e)), animateOut: self.sheetAnimateOut )), environment: { diff --git a/submodules/TelegramUI/Components/Gifts/GiftCraftScreen/Sources/GiftCraftScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftCraftScreen/Sources/GiftCraftScreen.swift index 2e4247c661..a4609566ee 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftCraftScreen/Sources/GiftCraftScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftCraftScreen/Sources/GiftCraftScreen.swift @@ -1517,6 +1517,7 @@ private final class SheetContainerComponent: CombinedComponent { let state = context.state let strings = environment.strings + let dateTimeFormat = environment.dateTimeFormat if externalState.displayFailure { state.displayFailure = true @@ -1846,6 +1847,9 @@ private final class SheetContainerComponent: CombinedComponent { if let navigationController = controller()?.navigationController { var text: String = strings.Login_UnknownError switch error { + case let .tooEarly(canCraftDate): + let dateString = stringForFullDate(timestamp: canCraftDate, strings: strings, dateTimeFormat: dateTimeFormat) + text = strings.Gift_Craft_Unavailable_Text(dateString).string case .unavailable: text = strings.Gift_Craft_Error_NotAvailable default: diff --git a/submodules/TelegramUI/Components/Gifts/GiftCraftScreen/Sources/SelectCraftGiftScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftCraftScreen/Sources/SelectCraftGiftScreen.swift index 93ec2b2d5d..c15653176b 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftCraftScreen/Sources/SelectCraftGiftScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftCraftScreen/Sources/SelectCraftGiftScreen.swift @@ -87,7 +87,7 @@ final class SelectGiftPageContent: Component { private var craftStateDisposable: Disposable? private var availableGifts: [GiftItem] = [] - private var giftMap: [Int64: GiftItem] = [:] + private var giftMap: [Int64: ProfileGiftsContext.State.StarGift] = [:] private var availableSize: CGSize? private var currentBounds: CGRect? @@ -203,11 +203,27 @@ final class SelectGiftPageContent: Component { isEditing: false, mode: .grid, action: { [weak self] in - guard let self, let component = self.component else { + guard let self, let component = self.component, let environment = self.environment else { return } HapticFeedback().impact(.light) + let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) + if let profileGift = self.giftMap[gift.gift.id], let canCraftDate = profileGift.canCraftAt, currentTime < canCraftDate { + let dateString = stringForFullDate(timestamp: canCraftDate, strings: environment.strings, dateTimeFormat: environment.dateTimeFormat) + let alertController = textAlertController( + context: component.context, + title: environment.strings.Gift_Craft_Unavailable_Title, + text: environment.strings.Gift_Craft_Unavailable_Text(dateString).string, + actions: [ + TextAlertAction(type: .defaultAction, title: environment.strings.Common_OK, action: {}) + ], + parseMarkdown: true + ) + environment.controller()?.present(alertController, in: .window(.root)) + return + } + component.selectGift(gift) component.dismiss() }, @@ -322,7 +338,6 @@ final class SelectGiftPageContent: Component { self.availableGifts = [ initialGiftItem ] - self.giftMap = [initialGiftItem.gift.id: initialGiftItem] self.craftStateDisposable = (component.craftContext.state |> deliverOnMainQueue).start(next: { [weak self] state in @@ -332,32 +347,28 @@ final class SelectGiftPageContent: Component { self.craftState = state var items: [GiftItem] = [] - var map: [Int64: GiftItem] = [:] - var foundInitial = false + var giftMap: [Int64: ProfileGiftsContext.State.StarGift] = [:] + var existingIds = Set() for gift in state.gifts { - guard let reference = gift.reference, case let .unique(uniqueGift) = gift.gift else { + guard let reference = gift.reference, case let .unique(uniqueGift) = gift.gift, !existingIds.contains(uniqueGift.id) else { continue } + existingIds.insert(uniqueGift.id) + let giftItem = GiftItem( gift: uniqueGift, reference: reference ) - map[uniqueGift.id] = giftItem - if uniqueGift.id == component.gift.id { - foundInitial = true - } else { - if component.selectedGiftIds.contains(uniqueGift.id) { - continue - } - items.append(giftItem) + giftMap[uniqueGift.id] = gift + + if component.selectedGiftIds.contains(uniqueGift.id) { + continue } + items.append(giftItem) } - if !foundInitial { - map[initialGiftItem.gift.id] = initialGiftItem - } self.availableGifts = items - self.giftMap = map + self.giftMap = giftMap self.state?.updated(transition: .spring(duration: 0.4)) }) diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index ba562296a8..cad07f1e0a 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -1536,9 +1536,18 @@ private final class GiftViewSheetContent: CombinedComponent { controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current) }))) - if let _ = arguments.canCraftDate { + var canCraft = false + if let data = self.context.currentAppConfiguration.with({ $0 }).data { + if let _ = data["ios_enable_crafting"] { + canCraft = true + } else if let isDev = data["dev"] as? Double, isDev == 1.0 { + canCraft = true + } + } + + if let _ = arguments.canCraftDate, canCraft { items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_Craft, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor) + return generateTintedImage(image: UIImage(bundleImageName: "Premium/Craft/Craft"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in c?.dismiss(completion: nil) diff --git a/submodules/TelegramUI/Images.xcassets/Premium/Craft/Craft.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Premium/Craft/Craft.imageset/Contents.json new file mode 100644 index 0000000000..223348a3b8 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Premium/Craft/Craft.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "craft.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Premium/Craft/Craft.imageset/craft.pdf b/submodules/TelegramUI/Images.xcassets/Premium/Craft/Craft.imageset/craft.pdf new file mode 100644 index 0000000000..03edcb130e Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Premium/Craft/Craft.imageset/craft.pdf differ diff --git a/submodules/TranslateUI/Sources/TranslateScreen.swift b/submodules/TranslateUI/Sources/TranslateScreen.swift index acd4163bfc..e68e5df3ef 100644 --- a/submodules/TranslateUI/Sources/TranslateScreen.swift +++ b/submodules/TranslateUI/Sources/TranslateScreen.swift @@ -251,7 +251,7 @@ private final class SheetContent: CombinedComponent { return { context in let environment = context.environment[ViewControllerComponentContainer.Environment.self].value let state = context.state - let theme = environment.theme + let theme = environment.theme.withModalBlocksBackground() let strings = environment.strings let topInset: CGFloat = environment.navigationHeight - 35.0