Various improvements

This commit is contained in:
Ilya Laktyushin 2025-04-24 21:12:40 +04:00
parent 9483448aa3
commit c4731d8b8d
13 changed files with 164 additions and 124 deletions

View File

@ -14225,3 +14225,68 @@ Sorry for the inconvenience.";
"Notification.StarsGift.Bought.Stars_1" = "%@ Star";
"Notification.StarsGift.Bought.Stars_any" = "%@ Stars";
"Notification.StarsGift.BoughtYou" = "You gifted %1$@ for %2$@";
"Notification.StarsGift.BoughtForYouself" = "You bought this gift for %1$@";
"Gift.View.Context.ChangePrice" = "Change Price";
"Gift.View.Context.ViewInProfile" = "View in Profile";
"Gift.View.Sell" = "sell";
"Gift.View.Unlist" = "unlist";
"Gift.View.BuyFor" = "Buy for";
"Gift.View.SellingGiftInfo" = "%@ is selling this gift and you can buy it.";
"Gift.View.Resale.Success.Title" = "Gift Sent";
"Gift.View.Resale.Success.Text" = "%@ has been notified about your gift.";
"Gift.View.Resale.SuccessYou.Title" = "Gift Acquired";
"Gift.View.Resale.SuccessYou.Text" = "%@ is now yours.";
"Gift.View.Resale.Unlist.Title" = "Unlist This Item?";
"Gift.View.Resale.Unlist.Text" = "It will no longer be for sale.";
"Gift.View.Resale.Unlist.Unlist" = "Unlist";
"Gift.View.Resale.Unlist.Success" = "%@ is removed from sale.";
"Gift.View.Resale.List.Success" = "%@ is now for sale!";
"Gift.View.Resale.Relist.Success" = "%1$@ is relisted for %2$@.";
"Gift.View.Resale.Relist.Success.Stars_1" = "%@ Star";
"Gift.View.Resale.Relist.Success.Stars_any" = "%@ Stars";
"Stars.SellGift.Title" = "Sell Gift";
"Stars.SellGift.EditTitle" = "Edit Price";
"Stars.SellGift.AmountTitle" = "PRICE IN STARS";
"Stars.SellGift.AmountPlaceholder" = "Enter Price";
"Stars.SellGift.AmountInfo" = "You will receive **%@**.";
"Stars.SellGift.AmountInfo.Stars_1" = "%@ Star";
"Stars.SellGift.AmountInfo.Stars_any" = "%@ Stars";
"Stars.SellGift.Sell" = "Sell";
"Stars.SellGift.SellFor" = "Sell for";
"PeerInfo.Gifts.Sale" = "sale";
"Gift.Store.ForResale_1" = "%@ for resale";
"Gift.Store.ForResale_any" = "%@ for resale";
"Gift.Store.Sort.Price" = "Price";
"Gift.Store.Sort.Date" = "Date";
"Gift.Store.Sort.Number" = "Number";
"Gift.Store.SortByPrice" = "Sort By Price";
"Gift.Store.SortByDate" = "Sort By Date";
"Gift.Store.SortByNumber" = "Sort By Number";
"Gift.Store.Filter.Model" = "Model";
"Gift.Store.Filter.Backdrop" = "Backdrop";
"Gift.Store.Filter.Symbol" = "Symbol";
"Gift.Store.Filter.Selected.Model_1" = "%@ Model";
"Gift.Store.Filter.Selected.Model_any" = "%@ Models";
"Gift.Store.Filter.Selected.Backdrop_1" = "%@ Backdrop";
"Gift.Store.Filter.Selected.Backdrop_any" = "%@ Backdrops";
"Gift.Store.Filter.Selected.Symbol_1" = "%@ Symbol";
"Gift.Store.Filter.Selected.Symbol_any" = "%@ Symbols";
"Gift.Store.Search" = "Search";
"Gift.Store.SelectAll" = "Select All";
"Gift.Store.NoResults" = "No Results";
"Gift.Store.EmptyResults" = "No Matching Gifts";
"Gift.Store.ClearFilters" = "Clear Filters";
"Gift.Send.AvailableForResale" = "Available for Resale";
"MediaPicker.CreateStory_1" = "Create %@ Story";
"MediaPicker.CreateStory_any" = "Create %@ Stories";
"MediaPicker.CombineIntoCollage" = "Combine into Collage";

View File

@ -2395,15 +2395,11 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
transition.updateTransformScale(node: self.moreButtonNode.iconNode, scale: moreIsVisible ? 1.0 : 0.1)
if case .assets(_, .story) = self.subject, self.selectionCount > 0 {
//TODO:localize
var text = "Create 1 Story"
if self.selectionCount > 1 {
text = "Create \(self.selectionCount) Stories"
}
let text = self.presentationData.strings.MediaPicker_CreateStory(self.selectionCount)
self.mainButtonStatePromise.set(.single(AttachmentMainButtonState(text: text, badge: nil, font: .bold, background: .color(self.presentationData.theme.actionSheet.controlAccentColor), textColor: self.presentationData.theme.list.itemCheckColors.foregroundColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false, position: .top)))
if self.selectionCount > 1 && self.selectionCount <= 6 {
self.secondaryButtonStatePromise.set(.single(AttachmentMainButtonState(text: "Combine into Collage", badge: nil, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false, iconName: "Media Editor/Collage", smallSpacing: true, position: .bottom)))
self.secondaryButtonStatePromise.set(.single(AttachmentMainButtonState(text: self.presentationData.strings.MediaPicker_CombineIntoCollage, badge: nil, font: .regular, background: .color(.clear), textColor: self.presentationData.theme.actionSheet.controlAccentColor, isVisible: true, progress: .none, isEnabled: true, hasShimmer: false, iconName: "Media Editor/Collage", smallSpacing: true, position: .bottom)))
} else {
self.secondaryButtonStatePromise.set(.single(nil))
}

View File

@ -542,6 +542,8 @@ NSString *suffix = @"";
return @"iPhone 16 Pro";
if ([platform isEqualToString:@"iPhone17,2"])
return @"iPhone 16 Pro Max";
if ([platform isEqualToString:@"iPhone17,5"])
return @"iPhone 16e";
if ([platform hasPrefix:@"iPod1"])
return @"iPod touch 1G";

View File

@ -1534,13 +1534,28 @@ private final class ProfileGiftsContextImpl {
guard let self else {
return EmptyDisposable
}
var saveToProfile = false
if let gift = self.gifts.first(where: { $0.reference == reference }) {
if !gift.savedToProfile {
saveToProfile = true
}
} else if let gift = self.filteredGifts.first(where: { $0.reference == reference }) {
if !gift.savedToProfile {
saveToProfile = true
}
}
var signal = _internal_updateStarGiftResalePrice(account: self.account, reference: reference, price: price)
if saveToProfile {
signal = _internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: true)
|> castError(UpdateStarGiftPriceError.self)
|> then(signal)
}
let disposable = MetaDisposable()
disposable.set(
(_internal_updateStarGiftResalePrice(
account: self.account,
reference: reference,
price: price
)
(signal
|> deliverOn(self.queue)).startStrict(error: { error in
subscriber.putError(error)
}, completed: {
@ -1562,7 +1577,7 @@ private final class ProfileGiftsContextImpl {
}) {
if case let .unique(uniqueGift) = self.gifts[index].gift {
let updatedUniqueGift = uniqueGift.withResellStars(price)
let updatedGift = self.gifts[index].withGift(.unique(updatedUniqueGift))
let updatedGift = self.gifts[index].withGift(.unique(updatedUniqueGift)).withSavedToProfile(true)
self.gifts[index] = updatedGift
}
}
@ -1585,7 +1600,7 @@ private final class ProfileGiftsContextImpl {
}) {
if case let .unique(uniqueGift) = self.filteredGifts[index].gift {
let updatedUniqueGift = uniqueGift.withResellStars(price)
let updatedGift = self.filteredGifts[index].withGift(.unique(updatedUniqueGift))
let updatedGift = self.filteredGifts[index].withGift(.unique(updatedUniqueGift)).withSavedToProfile(true)
self.filteredGifts[index] = updatedGift
}
}

View File

@ -1190,8 +1190,12 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
} else if message.author?.id == accountPeerId {
if let resaleStars {
let starsString = strings.Notification_StarsGift_Bought_Stars(Int32(resaleStars))
let giftTitle = "\(gift.title) #\(presentationStringsFormattedNumber(gift.number, dateTimeFormat.groupingSeparator))"
attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGift_BoughtYou(giftTitle, starsString)._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes, 1: boldAttributes])
if message.id.peerId == accountPeerId {
attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGift_BoughtForYouself(starsString)._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
} else {
let giftTitle = "\(gift.title) #\(presentationStringsFormattedNumber(gift.number, dateTimeFormat.groupingSeparator))"
attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGift_BoughtYou(giftTitle, starsString)._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes, 1: boldAttributes])
}
} else {
attributedString = NSAttributedString(string: strings.Notification_StarsGift_TransferYou, font: titleFont, textColor: primaryTextColor)
}

View File

@ -801,7 +801,7 @@ final class GiftSetupScreenComponent: Component {
title: AnyComponent(VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(
MultilineTextComponent(
text: .plain(NSAttributedString(string: "Available for Resale", font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: environment.theme.list.itemPrimaryTextColor))
text: .plain(NSAttributedString(string: environment.strings.Gift_Send_AvailableForResale, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: environment.theme.list.itemPrimaryTextColor))
)
)),
], alignment: .left, spacing: 2.0)),
@ -1770,6 +1770,8 @@ public final class GiftSetupScreen: ViewControllerComponentContainer {
self.title = ""
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.context.sharedContext.currentPresentationData.with { $0 }.strings.Common_Back, style: .plain, target: nil, action: nil)
self.scrollToTop = { [weak self] in
guard let self, let componentView = self.node.hostView.componentView as? GiftSetupScreenComponent.View else {
return

View File

@ -218,8 +218,7 @@ private final class GiftAttributeListContextItemNode: ASDisplayNode, ContextMenu
let selectedAttributes = Set(item.selectedAttributes)
//TODO:localize
let selectAllAction = ContextMenuActionItem(text: "Select All", icon: { theme in
let selectAllAction = ContextMenuActionItem(text: presentationData.strings.Gift_Store_SelectAll, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor)
}, iconPosition: .left, action: { _, f in
getController()?.dismiss(result: .dismissWithoutContent, completion: nil)
@ -248,7 +247,7 @@ private final class GiftAttributeListContextItemNode: ASDisplayNode, ContextMenu
}
let nopAction: ((ContextControllerProtocol?, @escaping (ContextMenuActionResult) -> Void) -> Void)? = nil
let emptyResultsAction = ContextMenuActionItem(text: "No Results", textFont: .small, icon: { _ in return nil }, action: nopAction)
let emptyResultsAction = ContextMenuActionItem(text: presentationData.strings.Gift_Store_NoResults, textFont: .small, icon: { _ in return nil }, action: nopAction)
let emptyResultsActionNode = ContextControllerActionsListActionItemNode(context: item.context, getController: getController, requestDismiss: actionSelected, requestUpdateAction: { _, _ in }, item: emptyResultsAction)
actionNodes.append(emptyResultsActionNode)
@ -412,12 +411,6 @@ private final class GiftAttributeListContextItemNode: ASDisplayNode, ContextMenu
}
func actionNode(at point: CGPoint) -> ContextActionNodeProtocol {
// for actionNode in self.actionNodes {
// let frame = actionNode.convert(actionNode.bounds, to: self)
// if frame.contains(point) {
// return actionNode
// }
// }
return self
}

View File

@ -302,7 +302,7 @@ final class GiftStoreScreenComponent: Component {
PlainButtonComponent(
content: AnyComponent(
MultilineTextComponent(
text: .plain(NSAttributedString(string: "Clear Filters", font: Font.regular(17.0), textColor: environment.theme.list.itemAccentColor)),
text: .plain(NSAttributedString(string: environment.strings.Gift_Store_ClearFilters, font: Font.regular(17.0), textColor: environment.theme.list.itemAccentColor)),
horizontalAlignment: .center,
maximumNumberOfLines: 0
)
@ -349,7 +349,7 @@ final class GiftStoreScreenComponent: Component {
transition: .immediate,
component: AnyComponent(
MultilineTextComponent(
text: .plain(NSAttributedString(string: "No Matching Gifts", font: Font.semibold(17.0), textColor: environment.theme.list.itemPrimaryTextColor)),
text: .plain(NSAttributedString(string: environment.strings.Gift_Store_EmptyResults, font: Font.semibold(17.0), textColor: environment.theme.list.itemPrimaryTextColor)),
horizontalAlignment: .center
)
),
@ -441,21 +441,21 @@ final class GiftStoreScreenComponent: Component {
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: "Sort by Price", icon: { theme in
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_Store_SortByPrice, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SortValue"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.default)
self?.state?.starGiftsContext.updateSorting(.value)
})))
items.append(.action(ContextMenuActionItem(text: "Sort by Date", icon: { theme in
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_Store_SortByDate, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SortDate"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.default)
self?.state?.starGiftsContext.updateSorting(.date)
})))
items.append(.action(ContextMenuActionItem(text: "Sort by Number", icon: { theme in
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_Store_SortByNumber, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SortNumber"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in
f(.default)
@ -493,12 +493,11 @@ final class GiftStoreScreenComponent: Component {
}
}
//TODO:localize
var items: [ContextMenuItem] = []
if modelAttributes.count >= 8 {
items.append(.custom(SearchContextItem(
context: component.context,
placeholder: "Search",
placeholder: presentationData.strings.Gift_Store_Search,
value: "",
valueChanged: { value in
searchQueryPromise.set(value)
@ -585,12 +584,11 @@ final class GiftStoreScreenComponent: Component {
}
}
//TODO:localize
var items: [ContextMenuItem] = []
if backdropAttributes.count >= 8 {
items.append(.custom(SearchContextItem(
context: component.context,
placeholder: "Search",
placeholder: presentationData.strings.Gift_Store_Search,
value: "",
valueChanged: { value in
searchQueryPromise.set(value)
@ -677,12 +675,11 @@ final class GiftStoreScreenComponent: Component {
}
}
//TODO:localize
var items: [ContextMenuItem] = []
if patternAttributes.count >= 8 {
items.append(.custom(SearchContextItem(
context: component.context,
placeholder: "Search",
placeholder: presentationData.strings.Gift_Store_Search,
value: "",
valueChanged: { value in
searchQueryPromise.set(value)
@ -814,35 +811,7 @@ final class GiftStoreScreenComponent: Component {
transition.setFrame(view: topPanelView, frame: topPanelFrame)
transition.setFrame(view: topSeparatorView, frame: topSeparatorFrame)
}
// let cancelButtonSize = self.cancelButton.update(
// transition: transition,
// component: AnyComponent(
// PlainButtonComponent(
// content: AnyComponent(
// MultilineTextComponent(
// text: .plain(NSAttributedString(string: strings.Common_Cancel, font: Font.regular(17.0), textColor: theme.rootController.navigationBar.accentTextColor)),
// horizontalAlignment: .center
// )
// ),
// effectAlignment: .center,
// action: {
// controller()?.dismiss()
// },
// animateScale: false
// )
// ),
// environment: {},
// containerSize: CGSize(width: availableSize.width, height: 100.0)
// )
// let cancelButtonFrame = CGRect(origin: CGPoint(x: environment.safeInsets.left + 16.0, y: environment.statusBarHeight + (environment.navigationHeight - environment.statusBarHeight) / 2.0 - cancelButtonSize.height / 2.0), size: cancelButtonSize)
// if let cancelButtonView = self.cancelButton.view {
// if cancelButtonView.superview == nil {
// self.addSubview(cancelButtonView)
// }
// transition.setFrame(view: cancelButtonView, frame: cancelButtonFrame)
// }
let balanceTitleSize = self.balanceTitle.update(
transition: .immediate,
component: AnyComponent(MultilineTextComponent(
@ -922,7 +891,7 @@ final class GiftStoreScreenComponent: Component {
let subtitleSize = self.subtitle.update(
transition: transition,
component: AnyComponent(BalancedTextComponent(
text: .plain(NSAttributedString(string: "\(effectiveCount) for resale", font: Font.regular(13.0), textColor: theme.rootController.navigationBar.secondaryTextColor)),
text: .plain(NSAttributedString(string: environment.strings.Gift_Store_ForResale(effectiveCount), font: Font.regular(13.0), textColor: theme.rootController.navigationBar.secondaryTextColor)),
horizontalAlignment: .center,
maximumNumberOfLines: 1
)),
@ -940,18 +909,18 @@ final class GiftStoreScreenComponent: Component {
let optionSpacing: CGFloat = 10.0
let optionWidth = (availableSize.width - sideInset * 2.0 - optionSpacing * 2.0) / 3.0
var sortingTitle = "Date"
var sortingTitle = environment.strings.Gift_Store_Sort_Date
var sortingIcon: String = "Peer Info/SortDate"
if let sorting = self.state?.starGiftsState?.sorting {
switch sorting {
case .date:
sortingTitle = "Date"
sortingTitle = environment.strings.Gift_Store_Sort_Date
sortingIcon = "Peer Info/SortDate"
case .value:
sortingTitle = "Price"
sortingTitle = environment.strings.Gift_Store_Sort_Price
sortingIcon = "Peer Info/SortValue"
case .number:
sortingTitle = "Number"
sortingTitle = environment.strings.Gift_Store_Sort_Number
sortingIcon = "Peer Info/SortNumber"
}
}
@ -968,13 +937,13 @@ final class GiftStoreScreenComponent: Component {
}
))
var modelTitle = "Model"
var backdropTitle = "Backdrop"
var symbolTitle = "Symbol"
var modelTitle = environment.strings.Gift_Store_Filter_Model
var backdropTitle = environment.strings.Gift_Store_Filter_Backdrop
var symbolTitle = environment.strings.Gift_Store_Filter_Symbol
if let filterAttributes = self.state?.starGiftsState?.filterAttributes {
var modelCount = 0
var backdropCount = 0
var symbolCount = 0
var modelCount: Int32 = 0
var backdropCount: Int32 = 0
var symbolCount: Int32 = 0
for attribute in filterAttributes {
switch attribute {
@ -988,25 +957,13 @@ final class GiftStoreScreenComponent: Component {
}
if modelCount > 0 {
if modelCount > 1 {
modelTitle = "\(modelCount) Models"
} else {
modelTitle = "1 Model"
}
modelTitle = environment.strings.Gift_Store_Filter_Selected_Model(modelCount)
}
if backdropCount > 0 {
if backdropCount > 1 {
backdropTitle = "\(backdropCount) Backdrops"
} else {
backdropTitle = "1 Backdrop"
}
backdropTitle = environment.strings.Gift_Store_Filter_Selected_Backdrop(modelCount)
}
if symbolCount > 0 {
if symbolCount > 1 {
symbolTitle = "\(symbolCount) Symbols"
} else {
symbolTitle = "1 Symbol"
}
symbolTitle = environment.strings.Gift_Store_Filter_Selected_Symbol(modelCount)
}
}

View File

@ -407,7 +407,6 @@ private final class GiftViewSheetContent: CombinedComponent {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let mode = ContactSelectionControllerMode.starsGifting(birthdays: nil, hasActions: false, showSelf: true, selfSubtitle: presentationData.strings.Premium_Gift_ContactSelection_BuySelf)
//TODO:localize
let controller = self.context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(
context: context,
mode: mode,
@ -476,14 +475,13 @@ private final class GiftViewSheetContent: CombinedComponent {
controllers = controllers.filter({ !($0 is GiftViewScreen) })
navigationController.setViewControllers(controllers, animated: true)
//TODO:localize
navigationController.view.addSubview(ConfettiView(frame: navigationController.view.bounds))
Queue.mainQueue().after(0.5, {
if let lastController = navigationController.viewControllers.last as? ViewController, let animationFile {
let resultController = UndoOverlayController(
presentationData: presentationData,
content: .sticker(context: context, file: animationFile, loop: false, title: "Gift Acquired", text: "\(giftTitle) is now yours.", undoText: nil, customAction: nil),
content: .sticker(context: context, file: animationFile, loop: false, title: presentationData.strings.Gift_View_Resale_SuccessYou_Title, text: presentationData.strings.Gift_View_Resale_SuccessYou_Text(giftTitle).string, undoText: nil, customAction: nil),
elevatedLayout: lastController is ChatController,
action: { _ in
return true
@ -505,7 +503,7 @@ private final class GiftViewSheetContent: CombinedComponent {
if let peer, let lastController = navigationController?.viewControllers.last as? ViewController, let animationFile {
let resultController = UndoOverlayController(
presentationData: presentationData,
content: .sticker(context: context, file: animationFile, loop: false, title: "Gift Sent", text: "\(peer.compactDisplayTitle) has been notified about your gift.", undoText: nil, customAction: nil),
content: .sticker(context: context, file: animationFile, loop: false, title: presentationData.strings.Gift_View_Resale_Success_Title, text: presentationData.strings.Gift_View_Resale_Success_Text(peer.compactDisplayTitle).string, undoText: nil, customAction: nil),
elevatedLayout: lastController is ChatController,
action: { _ in
return true
@ -1848,12 +1846,11 @@ private final class GiftViewSheetContent: CombinedComponent {
)
buttonOriginX += buttonWidth + buttonSpacing
//TODO:localize
let resellButton = resellButton.update(
component: PlainButtonComponent(
content: AnyComponent(
HeaderButtonComponent(
title: uniqueGift.resellStars == nil ? "sell" : "unlist",
title: uniqueGift.resellStars == nil ? strings.Gift_View_Sell : strings.Gift_View_Unlist,
iconName: uniqueGift.resellStars == nil ? "Premium/Collectible/Sell" : "Premium/Collectible/Unlist"
)
),
@ -2250,7 +2247,7 @@ private final class GiftViewSheetContent: CombinedComponent {
)
}
if case let .uniqueGift(_, recipientPeerId) = component.subject, recipientPeerId != nil {
} else {
} else if ownerPeerId != component.context.account.peerId {
selling = true
}
}
@ -2264,14 +2261,13 @@ private final class GiftViewSheetContent: CombinedComponent {
var addressToOpen: String?
var descriptionText: String
if let uniqueGift, selling {
//TODO:localize
let ownerName: String
if case let .peerId(peerId) = uniqueGift.owner {
ownerName = state.peerMap[peerId]?.compactDisplayTitle ?? ""
} else {
ownerName = ""
}
descriptionText = "\(ownerName) is selling this gift and you can buy it."
descriptionText = strings.Gift_View_SellingGiftInfo(ownerName).string
} else if let uniqueGift, let address = uniqueGift.giftAddress, case .address = uniqueGift.owner {
addressToOpen = address
descriptionText = strings.Gift_View_TonGiftAddressInfo
@ -2568,8 +2564,7 @@ private final class GiftViewSheetContent: CombinedComponent {
if state.cachedStarImage == nil || state.cachedStarImage?.1 !== theme {
state.cachedStarImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/PremiumIcon"), color: theme.list.itemCheckColors.foregroundColor)!, theme)
}
//TODO:localize
var upgradeString = "Buy for"
var upgradeString = strings.Gift_View_BuyFor
upgradeString += " # \(presentationStringsFormattedNumber(Int32(resellStars), environment.dateTimeFormat.groupingSeparator))"
let buttonTitle = subject.arguments?.upgradeStars != nil ? strings.Gift_Upgrade_Confirm : upgradeString
@ -3412,14 +3407,13 @@ public class GiftViewScreen: ViewControllerComponentContainer {
let giftTitle = "\(gift.title) #\(presentationStringsFormattedNumber(gift.number, presentationData.dateTimeFormat.groupingSeparator))"
let reference = arguments.reference ?? .slug(slug: gift.slug)
//TODO:localize
if let resellStars = gift.resellStars, resellStars > 0, !update {
let alertController = textAlertController(
context: context,
title: "Unlist This Item?",
text: "It will no longer be for sale.",
title: presentationData.strings.Gift_View_Resale_Unlist_Title,
text: presentationData.strings.Gift_View_Resale_Unlist_Text,
actions: [
TextAlertAction(type: .defaultAction, title: "Unlist", action: { [weak self] in
TextAlertAction(type: .defaultAction, title: presentationData.strings.Gift_View_Resale_Unlist_Unlist, action: { [weak self] in
guard let self else {
return
}
@ -3436,7 +3430,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
break
}
let text = "\(giftTitle) is removed from sale."
let text = presentationData.strings.Gift_View_Resale_Unlist_Success(giftTitle).string
let tooltipController = UndoOverlayController(
presentationData: presentationData,
content: .universalImage(
@ -3486,9 +3480,10 @@ public class GiftViewScreen: ViewControllerComponentContainer {
break
}
var text = "\(giftTitle) is now for sale!"
var text = presentationData.strings.Gift_View_Resale_List_Success(giftTitle).string
if update {
text = "\(giftTitle) is relisted for \(presentationStringsFormattedNumber(Int32(price), presentationData.dateTimeFormat.groupingSeparator)) Stars."
let starsString = presentationData.strings.Gift_View_Resale_Relist_Success_Stars(Int32(price))
text = presentationData.strings.Gift_View_Resale_Relist_Success(giftTitle, starsString).string
}
let tooltipController = UndoOverlayController(
@ -3588,6 +3583,16 @@ public class GiftViewScreen: ViewControllerComponentContainer {
})))
}
if case let .unique(gift) = arguments.gift, let resellStars = gift.resellStars, resellStars > 0 {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_ChangePrice, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Paid"), color: theme.contextMenu.primaryColor)
}, action: { c, _ in
c?.dismiss(completion: nil)
resellGiftImpl?(true)
})))
}
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_CopyLink, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] c, _ in
@ -3625,8 +3630,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
}
if let _ = arguments.resellStars, case let .uniqueGift(uniqueGift, recipientPeerId) = subject, let _ = recipientPeerId {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "View in Profile", icon: { theme in
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_ViewInProfile, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/ShowIcon"), color: theme.contextMenu.primaryColor)
}, action: { c, _ in
c?.dismiss(completion: nil)

View File

@ -502,8 +502,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
resellPrice = gift.resellStars
if let _ = resellPrice {
//TODO:localize
ribbonText = "sale"
ribbonText = params.presentationData.strings.PeerInfo_Gifts_Sale
ribbonFont = .larger
ribbonColor = .green
ribbonOutline = params.presentationData.theme.list.blocksBackgroundColor

View File

@ -148,10 +148,9 @@ private final class SheetContent: CombinedComponent {
maxAmount = withdrawConfiguration.maxPaidMediaAmount.flatMap { StarsAmount(value: $0, nanos: 0) }
amountLabel = nil
case let .starGiftResell(update):
//TODO:localize
titleString = update ? "Edit Price" : "Sell Gift"
amountTitle = "PRICE IN STARS"
amountPlaceholder = "Enter Price"
titleString = update ? environment.strings.Stars_SellGift_EditTitle : environment.strings.Stars_SellGift_Title
amountTitle = environment.strings.Stars_SellGift_AmountTitle
amountPlaceholder = environment.strings.Stars_SellGift_AmountPlaceholder
minAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMinAmount, nanos: 0)
maxAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMaxAmount, nanos: 0)
@ -269,12 +268,13 @@ private final class SheetContent: CombinedComponent {
maximumNumberOfLines: 0
))
case .starGiftResell:
//TODO:localize
let amountInfoString: NSAttributedString
if let value = state.amount?.value, value > 0 {
amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString("You will receive **\(Int32(floor(Float(value) * 0.8))) Stars**.", attributes: amountMarkdownAttributes, textAlignment: .natural))
let starsValue = Int32(floor(Float(value) * Float(resaleConfiguration.paidMessageCommissionPermille) / 1000.0))
let starsString = environment.strings.Stars_SellGift_AmountInfo_Stars(starsValue)
amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.Stars_SellGift_AmountInfo(starsString).string, attributes: amountMarkdownAttributes, textAlignment: .natural))
} else {
amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString("You will receive **80%**.", attributes: amountMarkdownAttributes, textAlignment: .natural))
amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.Stars_SellGift_AmountInfo("\(resaleConfiguration.paidMessageCommissionPermille / 10)%").string, attributes: amountMarkdownAttributes, textAlignment: .natural))
}
amountFooter = AnyComponent(MultilineTextComponent(
text: .plain(amountInfoString),
@ -334,11 +334,10 @@ private final class SheetContent: CombinedComponent {
if case .paidMedia = component.mode {
buttonString = environment.strings.Stars_PaidContent_Create
} else if case .starGiftResell = component.mode {
//TODO:localize
if let amount = state.amount, amount.value > 0 {
buttonString = "Sell for # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))"
buttonString = "\(environment.strings.Stars_SellGift_SellFor) # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))"
} else {
buttonString = "Sell"
buttonString = environment.strings.Stars_SellGift_Sell
}
} else if let amount = state.amount {
buttonString = "\(environment.strings.Stars_Withdraw_Withdraw) # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))"

View File

@ -124,6 +124,7 @@ public enum DeviceModel: CaseIterable, Equatable {
case iPhone16Plus
case iPhone16Pro
case iPhone16ProMax
case iPhone16e
case unknown(String)
@ -235,6 +236,8 @@ public enum DeviceModel: CaseIterable, Equatable {
return ["iPhone17,1"]
case .iPhone16ProMax:
return ["iPhone17,2"]
case .iPhone16e:
return ["iPhone17,5"]
case let .unknown(modelId):
return [modelId]
}
@ -348,6 +351,8 @@ public enum DeviceModel: CaseIterable, Equatable {
return "iPhone 16 Pro"
case .iPhone16ProMax:
return "iPhone 16 Pro Max"
case .iPhone16e:
return "iPhone 16e"
case let .unknown(modelId):
if modelId.hasPrefix("iPhone") {
return "Unknown iPhone"

View File

@ -103,7 +103,6 @@ private final class SheetContent: CombinedComponent {
.position(CGPoint(x: environment.safeInsets.left + 16.0 + closeButton.size.width / 2.0, y: 28.0))
)
//TODO:localize
let title = title.update(
component: MultilineTextComponent(
text: .plain(NSAttributedString(string: strings.WebApp_ImportData_Title, font: titleFont, textColor: textColor)),