diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 4c3fc5ab92..e5b1e5f7ad 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -13226,3 +13226,8 @@ Sorry for the inconvenience."; "Stars.Transaction.Subscription.CancelledByBot" = "Your subscription was cancelled by the bot."; "Stars.Transaction.Subscription.CancelledByBusiness" = "Your subscription was cancelled by the business."; + +"Gift.View.BotDescription" = "You can keep this gift in your Profile or hide it."; + +"Notification.StarGift.Bot.Subtitle" = "Display this gift on your page."; +"Notification.StarGift.Bot.Subtitle.Displaying" = "You are displaying this gift on your page."; diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 6123e14b94..3e1a76fec9 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -575,7 +575,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1434950843] = { return Api.MessageAction.parse_messageActionSetChatTheme($0) } dict[1348510708] = { return Api.MessageAction.parse_messageActionSetChatWallPaper($0) } dict[1007897979] = { return Api.MessageAction.parse_messageActionSetMessagesTTL($0) } - dict[-1682706620] = { return Api.MessageAction.parse_messageActionStarGift($0) } + dict[139818551] = { return Api.MessageAction.parse_messageActionStarGift($0) } dict[1474192222] = { return Api.MessageAction.parse_messageActionSuggestProfilePhoto($0) } dict[228168278] = { return Api.MessageAction.parse_messageActionTopicCreate($0) } dict[-1064024032] = { return Api.MessageAction.parse_messageActionTopicEdit($0) } diff --git a/submodules/TelegramApi/Sources/Api14.swift b/submodules/TelegramApi/Sources/Api14.swift index ef5c9801fb..95c641d701 100644 --- a/submodules/TelegramApi/Sources/Api14.swift +++ b/submodules/TelegramApi/Sources/Api14.swift @@ -1009,7 +1009,7 @@ public extension Api { case messageActionSetChatTheme(emoticon: String) case messageActionSetChatWallPaper(flags: Int32, wallpaper: Api.WallPaper) case messageActionSetMessagesTTL(flags: Int32, period: Int32, autoSettingFrom: Int64?) - case messageActionStarGift(flags: Int32, gift: Api.StarGift, message: Api.TextWithEntities?, convertStars: Int64) + case messageActionStarGift(flags: Int32, gift: Api.StarGift, message: Api.TextWithEntities?, convertStars: Int64?) case messageActionSuggestProfilePhoto(photo: Api.Photo) case messageActionTopicCreate(flags: Int32, title: String, iconColor: Int32, iconEmojiId: Int64?) case messageActionTopicEdit(flags: Int32, title: String?, iconEmojiId: Int64?, closed: Api.Bool?, hidden: Api.Bool?) @@ -1355,12 +1355,12 @@ public extension Api { break case .messageActionStarGift(let flags, let gift, let message, let convertStars): if boxed { - buffer.appendInt32(-1682706620) + buffer.appendInt32(139818551) } serializeInt32(flags, buffer: buffer, boxed: false) gift.serialize(buffer, true) if Int(flags) & Int(1 << 1) != 0 {message!.serialize(buffer, true)} - serializeInt64(convertStars, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 4) != 0 {serializeInt64(convertStars!, buffer: buffer, boxed: false)} break case .messageActionSuggestProfilePhoto(let photo): if boxed { @@ -2142,13 +2142,13 @@ public extension Api { _3 = Api.parse(reader, signature: signature) as? Api.TextWithEntities } } var _4: Int64? - _4 = reader.readInt64() + if Int(_1!) & Int(1 << 4) != 0 {_4 = reader.readInt64() } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil - let _c4 = _4 != nil + let _c4 = (Int(_1!) & Int(1 << 4) == 0) || _4 != nil if _c1 && _c2 && _c3 && _c4 { - return Api.MessageAction.messageActionStarGift(flags: _1!, gift: _2!, message: _3, convertStars: _4!) + return Api.MessageAction.messageActionStarGift(flags: _1!, gift: _2!, message: _3, convertStars: _4) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api36.swift b/submodules/TelegramApi/Sources/Api36.swift index a2de7f78eb..01150ca3ba 100644 --- a/submodules/TelegramApi/Sources/Api36.swift +++ b/submodules/TelegramApi/Sources/Api36.swift @@ -2263,6 +2263,23 @@ public extension Api.functions.bots { }) } } +public extension Api.functions.bots { + static func checkDownloadFileParams(bot: Api.InputUser, fileName: String, url: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1342666121) + bot.serialize(buffer, true) + serializeString(fileName, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + return (FunctionDescription(name: "bots.checkDownloadFileParams", parameters: [("bot", String(describing: bot)), ("fileName", String(describing: fileName)), ("url", String(describing: url))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} public extension Api.functions.bots { static func deletePreviewMedia(bot: Api.InputUser, langCode: String, media: [Api.InputMedia]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramCore/Sources/State/Serialization.swift b/submodules/TelegramCore/Sources/State/Serialization.swift index bc0dc07962..488600f5c7 100644 --- a/submodules/TelegramCore/Sources/State/Serialization.swift +++ b/submodules/TelegramCore/Sources/State/Serialization.swift @@ -210,7 +210,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 194 + return 193 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift index 8fb86d7327..552e8b9718 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift @@ -130,7 +130,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { case paymentRefunded(peerId: PeerId, currency: String, totalAmount: Int64, payload: Data?, transactionId: String) case giftStars(currency: String, amount: Int64, count: Int64, cryptoCurrency: String?, cryptoAmount: Int64?, transactionId: String?) case prizeStars(amount: Int64, isUnclaimed: Bool, boostPeerId: PeerId?, transactionId: String?, giveawayMessageId: MessageId?) - case starGift(gift: StarGift, convertStars: Int64, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool) + case starGift(gift: StarGift, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool) public init(decoder: PostboxDecoder) { let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0) @@ -252,7 +252,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { } self = .prizeStars(amount: decoder.decodeInt64ForKey("amount", orElse: 0), isUnclaimed: decoder.decodeBoolForKey("unclaimed", orElse: false), boostPeerId: boostPeerId, transactionId: decoder.decodeOptionalStringForKey("transactionId"), giveawayMessageId: giveawayMessageId) case 44: - self = .starGift(gift: decoder.decodeObjectForKey("gift", decoder: { StarGift(decoder: $0) }) as! StarGift, convertStars: decoder.decodeInt64ForKey("convertStars", orElse: 0), text: decoder.decodeOptionalStringForKey("text"), entities: decoder.decodeOptionalObjectArrayWithDecoderForKey("entities"), nameHidden: decoder.decodeBoolForKey("nameHidden", orElse: false), savedToProfile: decoder.decodeBoolForKey("savedToProfile", orElse: false), converted: decoder.decodeBoolForKey("converted", orElse: false)) + self = .starGift(gift: decoder.decodeObjectForKey("gift", decoder: { StarGift(decoder: $0) }) as! StarGift, convertStars: decoder.decodeOptionalInt64ForKey("convertStars"), text: decoder.decodeOptionalStringForKey("text"), entities: decoder.decodeOptionalObjectArrayWithDecoderForKey("entities"), nameHidden: decoder.decodeBoolForKey("nameHidden", orElse: false), savedToProfile: decoder.decodeBoolForKey("savedToProfile", orElse: false), converted: decoder.decodeBoolForKey("converted", orElse: false)) default: self = .unknown } @@ -548,7 +548,11 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted): encoder.encodeInt32(44, forKey: "_rawValue") encoder.encodeObject(gift, forKey: "gift") - encoder.encodeInt64(convertStars, forKey: "convertStars") + if let convertStars { + encoder.encodeInt64(convertStars, forKey: "convertStars") + } else { + encoder.encodeNil(forKey: "convertStars") + } if let text, let entities { encoder.encodeString(text, forKey: "text") encoder.encodeObjectArray(entities, forKey: "entities") diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift index 85a0117c97..c791d4c2f7 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift @@ -28,6 +28,16 @@ public final class StarGiftsList: Codable, Equatable { } public struct StarGift: Equatable, Codable, PostboxCoding { + public struct Flags: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let isBirthdayGift = Flags(rawValue: 1 << 0) + } + enum CodingKeys: String, CodingKey { case id case file @@ -35,6 +45,7 @@ public struct StarGift: Equatable, Codable, PostboxCoding { case convertStars case availability case soldOut + case flags } public struct Availability: Equatable, Codable, PostboxCoding { @@ -97,14 +108,16 @@ public struct StarGift: Equatable, Codable, PostboxCoding { public let convertStars: Int64 public let availability: Availability? public let soldOut: SoldOut? + public let flags: Flags - public init(id: Int64, file: TelegramMediaFile, price: Int64, convertStars: Int64, availability: Availability?, soldOut: SoldOut?) { + public init(id: Int64, file: TelegramMediaFile, price: Int64, convertStars: Int64, availability: Availability?, soldOut: SoldOut?, flags: Flags) { self.id = id self.file = file self.price = price self.convertStars = convertStars self.availability = availability self.soldOut = soldOut + self.flags = flags } public init(from decoder: Decoder) throws { @@ -121,6 +134,7 @@ public struct StarGift: Equatable, Codable, PostboxCoding { self.convertStars = try container.decodeIfPresent(Int64.self, forKey: .convertStars) ?? 0 self.availability = try container.decodeIfPresent(Availability.self, forKey: .availability) self.soldOut = try container.decodeIfPresent(SoldOut.self, forKey: .soldOut) + self.flags = Flags(rawValue: try container .decodeIfPresent(Int32.self, forKey: .flags) ?? 0) } public init(decoder: PostboxDecoder) { @@ -130,6 +144,7 @@ public struct StarGift: Equatable, Codable, PostboxCoding { self.convertStars = decoder.decodeInt64ForKey(CodingKeys.convertStars.rawValue, orElse: 0) self.availability = decoder.decodeObjectForKey(CodingKeys.availability.rawValue, decoder: { StarGift.Availability(decoder: $0) }) as? StarGift.Availability self.soldOut = decoder.decodeObjectForKey(CodingKeys.soldOut.rawValue, decoder: { StarGift.SoldOut(decoder: $0) }) as? StarGift.SoldOut + self.flags = Flags(rawValue: decoder.decodeInt32ForKey(CodingKeys.flags.rawValue, orElse: 0)) } public func encode(to encoder: Encoder) throws { @@ -145,6 +160,7 @@ public struct StarGift: Equatable, Codable, PostboxCoding { try container.encode(self.convertStars, forKey: .convertStars) try container.encodeIfPresent(self.availability, forKey: .availability) try container.encodeIfPresent(self.soldOut, forKey: .soldOut) + try container.encode(self.flags.rawValue, forKey: .flags) } public func encode(_ encoder: PostboxEncoder) { @@ -162,13 +178,19 @@ public struct StarGift: Equatable, Codable, PostboxCoding { } else { encoder.encodeNil(forKey: CodingKeys.soldOut.rawValue) } + encoder.encodeInt32(self.flags.rawValue, forKey: CodingKeys.flags.rawValue) } } extension StarGift { init?(apiStarGift: Api.StarGift) { switch apiStarGift { - case let .starGift(_, id, sticker, stars, availabilityRemains, availabilityTotal, convertStars, firstSale, lastSale): + case let .starGift(apiFlags, id, sticker, stars, availabilityRemains, availabilityTotal, convertStars, firstSale, lastSale): + var flags = Flags() + if (apiFlags & (1 << 2)) != 0 { + flags.insert(.isBirthdayGift) + } + var availability: Availability? if let availabilityRemains, let availabilityTotal { availability = Availability(remains: availabilityRemains, total: availabilityTotal) @@ -180,7 +202,7 @@ extension StarGift { guard let file = telegramMediaFileFromApiDocument(sticker, altDocuments: nil) else { return nil } - self.init(id: id, file: file, price: stars, convertStars: convertStars, availability: availability, soldOut: soldOut) + self.init(id: id, file: file, price: stars, convertStars: convertStars, availability: availability, soldOut: soldOut, flags: flags) } } } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift index b4eaa8b264..2c93fa33a5 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift @@ -416,11 +416,19 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { } else { if incoming { if converted { - text = item.presentationData.strings.Notification_StarGift_Subtitle_Converted(item.presentationData.strings.Notification_StarGift_Subtitle_Converted_Stars(Int32(convertStars))).string + text = item.presentationData.strings.Notification_StarGift_Subtitle_Converted(item.presentationData.strings.Notification_StarGift_Subtitle_Converted_Stars(Int32(convertStars ?? 0))).string } else if savedToProfile { - text = item.presentationData.strings.Notification_StarGift_Subtitle_Displaying(item.presentationData.strings.Notification_StarGift_Subtitle_Displaying_Stars(Int32(convertStars))).string + if let convertStars { + text = item.presentationData.strings.Notification_StarGift_Subtitle_Displaying(item.presentationData.strings.Notification_StarGift_Subtitle_Displaying_Stars(Int32(convertStars))).string + } else { + text = item.presentationData.strings.Notification_StarGift_Bot_Subtitle_Displaying + } } else { - text = item.presentationData.strings.Notification_StarGift_Subtitle(item.presentationData.strings.Notification_StarGift_Subtitle_Stars(Int32(convertStars))).string + if let convertStars { + text = item.presentationData.strings.Notification_StarGift_Subtitle(item.presentationData.strings.Notification_StarGift_Subtitle_Stars(Int32(convertStars))).string + } else { + text = item.presentationData.strings.Notification_StarGift_Bot_Subtitle + } } } else { var peerName = "" @@ -428,9 +436,13 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { peerName = EnginePeer(peer).compactDisplayTitle } if peerName.isEmpty { - text = item.presentationData.strings.Notification_StarGift_Subtitle(item.presentationData.strings.Notification_StarGift_Subtitle_Stars(Int32(convertStars))).string + if let convertStars { + text = item.presentationData.strings.Notification_StarGift_Subtitle(item.presentationData.strings.Notification_StarGift_Subtitle_Stars(Int32(convertStars))).string + } else { + text = item.presentationData.strings.Notification_StarGift_Bot_Subtitle + } } else { - text = item.presentationData.strings.Notification_StarGift_Subtitle_Other(peerName, item.presentationData.strings.Notification_StarGift_Subtitle_Other_Stars(Int32(convertStars))).string + text = item.presentationData.strings.Notification_StarGift_Subtitle_Other(peerName, item.presentationData.strings.Notification_StarGift_Subtitle_Other_Stars(Int32(convertStars ?? 0))).string } } } diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index 355df664b2..176791b187 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -182,7 +182,7 @@ private final class GiftViewSheetContent: CombinedComponent { let titleString: String let animationFile: TelegramMediaFile? let stars: Int64 - let convertStars: Int64 + let convertStars: Int64? let text: String? let entities: [MessageTextEntity]? let limitTotal: Int32? @@ -199,7 +199,7 @@ private final class GiftViewSheetContent: CombinedComponent { text = nil entities = nil limitTotal = gift.availability?.total - convertStars = 0 + convertStars = nil soldOut = true titleString = strings.Gift_View_UnavailableTitle } else if let arguments = component.subject.arguments { @@ -222,7 +222,7 @@ private final class GiftViewSheetContent: CombinedComponent { text = nil entities = nil limitTotal = nil - convertStars = 0 + convertStars = nil titleString = "" } @@ -230,13 +230,17 @@ private final class GiftViewSheetContent: CombinedComponent { if soldOut { descriptionText = strings.Gift_View_UnavailableDescription } else if incoming { - if !converted { - descriptionText = strings.Gift_View_KeepOrConvertDescription(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(convertStars))).string + if let convertStars { + if !converted { + descriptionText = strings.Gift_View_KeepOrConvertDescription(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(convertStars))).string + } else { + descriptionText = strings.Gift_View_ConvertedDescription(strings.Gift_View_ConvertedDescription_Stars(Int32(convertStars))).string + } } else { - descriptionText = strings.Gift_View_ConvertedDescription(strings.Gift_View_ConvertedDescription_Stars(Int32(convertStars))).string + descriptionText = strings.Gift_View_BotDescription } } else if let peerId = component.subject.arguments?.peerId, let peer = state.peerMap[peerId] { - if case .message = component.subject { + if case .message = component.subject, let convertStars { descriptionText = strings.Gift_View_OtherDescription(peer.compactDisplayTitle, strings.Gift_View_OtherDescription_Stars(Int32(convertStars))).string } else { descriptionText = "" @@ -494,7 +498,7 @@ private final class GiftViewSheetContent: CombinedComponent { } let valueComponent: AnyComponent - if incoming && !converted { + if let convertStars, incoming && !converted { valueComponent = AnyComponent( HStack([ AnyComponentWithIdentity( @@ -881,14 +885,14 @@ public class GiftViewScreen: ViewControllerComponentContainer { case profileGift(EnginePeer.Id, ProfileGiftsContext.State.StarGift) case soldOutGift(StarGift) - var arguments: (peerId: EnginePeer.Id, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool)? { + var arguments: (peerId: EnginePeer.Id, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool)? { switch self { case let .message(message): if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction, case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted) = action.action { return (message.id.peerId, message.author?.id, message.author?.compactDisplayTitle, message.id, message.flags.contains(.Incoming), gift, message.timestamp, convertStars, text, entities, nameHidden, savedToProfile, converted) } case let .profileGift(peerId, gift): - return (peerId, gift.fromPeer?.id, gift.fromPeer?.compactDisplayTitle, gift.messageId, false, gift.gift, gift.date, gift.convertStars ?? 0, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, false) + return (peerId, gift.fromPeer?.id, gift.fromPeer?.compactDisplayTitle, gift.messageId, false, gift.gift, gift.date, gift.convertStars, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, false) case .soldOutGift: return nil } @@ -1018,7 +1022,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { } convertToStarsImpl = { [weak self] in - guard let self, let arguments = subject.arguments, let messageId = arguments.messageId, let fromPeerName = arguments.fromPeerName, let navigationController = self.navigationController as? NavigationController else { + guard let self, let arguments = subject.arguments, let messageId = arguments.messageId, let fromPeerName = arguments.fromPeerName, let convertStars = arguments.convertStars, let navigationController = self.navigationController as? NavigationController else { return } @@ -1043,7 +1047,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { let delta = starsConvertMaxDate - currentTime let days: Int32 = Int32(ceil(Float(delta) / 86400.0)) - let text = presentationData.strings.Gift_Convert_Period_Text(fromPeerName, presentationData.strings.Gift_Convert_Period_Stars(Int32(arguments.convertStars)), presentationData.strings.Gift_Convert_Period_Days(days)).string + let text = presentationData.strings.Gift_Convert_Period_Text(fromPeerName, presentationData.strings.Gift_Convert_Period_Stars(Int32(convertStars)), presentationData.strings.Gift_Convert_Period_Days(days)).string let controller = textAlertController( context: self.context, title: presentationData.strings.Gift_Convert_Title, @@ -1073,7 +1077,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { scale: 0.066, colors: [:], title: presentationData.strings.Gift_Convert_Success_Title, - text: presentationData.strings.Gift_Convert_Success_Text(presentationData.strings.Gift_Convert_Success_Text_Stars(Int32(arguments.convertStars))).string, + text: presentationData.strings.Gift_Convert_Success_Text(presentationData.strings.Gift_Convert_Success_Text_Stars(Int32(convertStars))).string, customUndoText: nil, timeout: nil ),