Various improvements

This commit is contained in:
Ilya Laktyushin 2025-01-19 22:18:44 +04:00
parent 4ffb0e697e
commit a663ea50cd
14 changed files with 263 additions and 40 deletions

View File

@ -13743,3 +13743,12 @@ Sorry for the inconvenience.";
"Media.ChooseFromGallery" = "Choose From Gallery";
"Media.SelectFrame" = "Select Frame";
"Media.SaveCover" = "Save Cover";
"Gift.Withdraw.SecurityCheck" = "Security Check";
"Gift.Withdraw.SecurityRequirements" = "Gift withdrawals are available if:\n\n• 2-Step verification was enabled for your account more than **7 days** ago.\n\n• You have logged in on this device more than **24 hours** ago.";
"Gift.Withdraw.ComeBackLater" = "\n\nPlease come back later.";
"Gift.Withdraw.SetupTwoStepAuth" = "Enable 2-Step Verification";
"Gift.Withdraw.EnterPassword.Title" = "Enter Password";
"Gift.Withdraw.EnterPassword.Text" = "Please enter your Two-Step Verification password to complete this action.";
"Gift.Withdraw.EnterPassword.Done" = "Proceed";

View File

@ -20,9 +20,15 @@ public class ContactListActionItem: ListViewItem, ListViewItemWithHeader {
case generic
}
public enum Height {
case generic
case tall
}
let presentationData: ItemListPresentationData
let title: String
let subtitle: String?
let height: Height
let icon: ContactListActionItemIcon
let style: Style
let highlight: ContactListActionItemHighlight
@ -31,12 +37,13 @@ public class ContactListActionItem: ListViewItem, ListViewItemWithHeader {
let action: () -> Void
public let header: ListViewItemHeader?
public init(presentationData: ItemListPresentationData, title: String, subtitle: String? = nil, icon: ContactListActionItemIcon, style: Style = .accent, highlight: ContactListActionItemHighlight = .cell, clearHighlightAutomatically: Bool = true, accessible: Bool = true, header: ListViewItemHeader?, action: @escaping () -> Void) {
public init(presentationData: ItemListPresentationData, title: String, subtitle: String? = nil, icon: ContactListActionItemIcon, style: Style = .accent, height: Height = .generic, highlight: ContactListActionItemHighlight = .cell, clearHighlightAutomatically: Bool = true, accessible: Bool = true, header: ListViewItemHeader?, action: @escaping () -> Void) {
self.presentationData = presentationData
self.title = title
self.subtitle = subtitle
self.icon = icon
self.style = style
self.height = height
self.highlight = highlight
self.header = header
self.clearHighlightAutomatically = clearHighlightAutomatically
@ -223,7 +230,9 @@ class ContactListActionItemNode: ListViewItemNode {
let contentHeight: CGFloat
let verticalInset: CGFloat = subtitleAttributedString != nil ? 6.0 : 12.0
if case .alpha = item.highlight {
if case .tall = item.height {
contentHeight = 50.0
} else if case .alpha = item.highlight {
contentHeight = 50.0
} else {
contentHeight = verticalInset * 2.0 + titleLayout.size.height + subtitleHeightComponent

View File

@ -145,13 +145,16 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
})
case let .option(_, option, header, _, _):
let style: ContactListActionItem.Style
let height: ContactListActionItem.Height
switch option.style {
case .accent:
style = .accent
height = .generic
case .generic:
style = .generic
height = .tall
}
return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: option.title, subtitle: option.subtitle, icon: option.icon, style: style, clearHighlightAutomatically: option.clearHighlightAutomatically, header: header, action: option.action)
return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: option.title, subtitle: option.subtitle, icon: option.icon, style: style, height: height, clearHighlightAutomatically: option.clearHighlightAutomatically, header: header, action: option.action)
case let .peer(_, peer, presence, header, selection, _, strings, dateTimeFormat, nameSortOrder, nameDisplayOrder, displayCallIcons, hasMoreButton, enabled, storyData, requiresPremiumForMessaging, customSubtitle):
var status: ContactsPeerItemStatus
let itemPeer: ContactsPeerItemPeer

View File

@ -1381,7 +1381,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1314881805] = { return Api.payments.PaymentResult.parse_paymentResult($0) }
dict[-666824391] = { return Api.payments.PaymentResult.parse_paymentVerificationNeeded($0) }
dict[-74456004] = { return Api.payments.SavedInfo.parse_savedInfo($0) }
dict[1154859627] = { return Api.payments.SavedStarGifts.parse_savedStarGifts($0) }
dict[-1779201615] = { return Api.payments.SavedStarGifts.parse_savedStarGifts($0) }
dict[377215243] = { return Api.payments.StarGiftUpgradePreview.parse_starGiftUpgradePreview($0) }
dict[-2069218660] = { return Api.payments.StarGiftWithdrawalUrl.parse_starGiftWithdrawalUrl($0) }
dict[-1877571094] = { return Api.payments.StarGifts.parse_starGifts($0) }

View File

@ -1404,16 +1404,17 @@ public extension Api.payments {
}
public extension Api.payments {
enum SavedStarGifts: TypeConstructorDescription {
case savedStarGifts(flags: Int32, count: Int32, gifts: [Api.SavedStarGift], nextOffset: String?, chats: [Api.Chat], users: [Api.User])
case savedStarGifts(flags: Int32, count: Int32, chatNotificationsEnabled: Api.Bool?, gifts: [Api.SavedStarGift], nextOffset: String?, chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .savedStarGifts(let flags, let count, let gifts, let nextOffset, let chats, let users):
case .savedStarGifts(let flags, let count, let chatNotificationsEnabled, let gifts, let nextOffset, let chats, let users):
if boxed {
buffer.appendInt32(1154859627)
buffer.appendInt32(-1779201615)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {chatNotificationsEnabled!.serialize(buffer, true)}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(gifts.count))
for item in gifts {
@ -1436,8 +1437,8 @@ public extension Api.payments {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .savedStarGifts(let flags, let count, let gifts, let nextOffset, let chats, let users):
return ("savedStarGifts", [("flags", flags as Any), ("count", count as Any), ("gifts", gifts as Any), ("nextOffset", nextOffset as Any), ("chats", chats as Any), ("users", users as Any)])
case .savedStarGifts(let flags, let count, let chatNotificationsEnabled, let gifts, let nextOffset, let chats, let users):
return ("savedStarGifts", [("flags", flags as Any), ("count", count as Any), ("chatNotificationsEnabled", chatNotificationsEnabled as Any), ("gifts", gifts as Any), ("nextOffset", nextOffset as Any), ("chats", chats as Any), ("users", users as Any)])
}
}
@ -1446,28 +1447,33 @@ public extension Api.payments {
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: [Api.SavedStarGift]?
var _3: Api.Bool?
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Bool
} }
var _4: [Api.SavedStarGift]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SavedStarGift.self)
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SavedStarGift.self)
}
var _4: String?
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) }
var _5: [Api.Chat]?
var _5: String?
if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) }
var _6: [Api.Chat]?
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _6: [Api.User]?
var _7: [Api.User]?
if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
let _c5 = _5 != nil
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
let _c6 = _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.payments.SavedStarGifts.savedStarGifts(flags: _1!, count: _2!, gifts: _3!, nextOffset: _4, chats: _5!, users: _6!)
let _c7 = _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.payments.SavedStarGifts.savedStarGifts(flags: _1!, count: _2!, chatNotificationsEnabled: _3, gifts: _4!, nextOffset: _5, chats: _6!, users: _7!)
}
else {
return nil

View File

@ -9647,6 +9647,22 @@ public extension Api.functions.payments {
})
}
}
public extension Api.functions.payments {
static func toggleChatStarGiftNotifications(flags: Int32, peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(1626009505)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
return (FunctionDescription(name: "payments.toggleChatStarGiftNotifications", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer))]), 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.payments {
static func transferStarGift(stargift: Api.InputSavedStarGift, toId: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()

View File

@ -866,14 +866,17 @@ private final class CachedProfileGifts: Codable {
enum CodingKeys: String, CodingKey {
case gifts
case count
case notificationsEnabled
}
var gifts: [ProfileGiftsContext.State.StarGift]
let count: Int32
let notificationsEnabled: Bool?
init(gifts: [ProfileGiftsContext.State.StarGift], count: Int32) {
init(gifts: [ProfileGiftsContext.State.StarGift], count: Int32, notificationsEnabled: Bool?) {
self.gifts = gifts
self.count = count
self.notificationsEnabled = notificationsEnabled
}
init(from decoder: Decoder) throws {
@ -881,6 +884,7 @@ private final class CachedProfileGifts: Codable {
self.gifts = try container.decode([ProfileGiftsContext.State.StarGift].self, forKey: .gifts)
self.count = try container.decode(Int32.self, forKey: .count)
self.notificationsEnabled = try container.decodeIfPresent(Bool.self, forKey: .notificationsEnabled)
}
func encode(to encoder: Encoder) throws {
@ -888,6 +892,7 @@ private final class CachedProfileGifts: Codable {
try container.encode(self.gifts, forKey: .gifts)
try container.encode(self.count, forKey: .count)
try container.encodeIfPresent(self.notificationsEnabled, forKey: .notificationsEnabled)
}
func render(transaction: Transaction) {
@ -918,6 +923,7 @@ private final class ProfileGiftsContextImpl {
private var gifts: [ProfileGiftsContext.State.StarGift] = []
private var count: Int32?
private var dataState: ProfileGiftsContext.State.DataState = .ready(canLoadMore: true, nextOffset: nil)
private var notificationsEnabled: Bool?
var _state: ProfileGiftsContext.State?
private let stateValue = Promise<ProfileGiftsContext.State>()
@ -958,6 +964,7 @@ private final class ProfileGiftsContextImpl {
if case .loading = self.dataState {
self.gifts = cachedGifts.gifts
self.count = cachedGifts.count
self.notificationsEnabled = cachedGifts.notificationsEnabled
self.pushState()
}
}))
@ -966,12 +973,12 @@ private final class ProfileGiftsContextImpl {
self.dataState = .loading
self.pushState()
let signal: Signal<([ProfileGiftsContext.State.StarGift], Int32, String?), NoError> = self.account.postbox.transaction { transaction -> Api.InputPeer? in
let signal: Signal<([ProfileGiftsContext.State.StarGift], Int32, String?, Bool?), NoError> = self.account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
|> mapToSignal { inputPeer -> Signal<([ProfileGiftsContext.State.StarGift], Int32, String?), NoError> in
|> mapToSignal { inputPeer -> Signal<([ProfileGiftsContext.State.StarGift], Int32, String?, Bool?), NoError> in
guard let inputPeer else {
return .single(([], 0, nil))
return .single(([], 0, nil, nil))
}
let flags: Int32 = 0
return network.request(Api.functions.payments.getSavedStarGifts(flags: flags, peer: inputPeer, offset: initialNextOffset ?? "", limit: 32))
@ -979,25 +986,34 @@ private final class ProfileGiftsContextImpl {
|> `catch` { _ -> Signal<Api.payments.SavedStarGifts?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<([ProfileGiftsContext.State.StarGift], Int32, String?), NoError> in
|> mapToSignal { result -> Signal<([ProfileGiftsContext.State.StarGift], Int32, String?, Bool?), NoError> in
guard let result else {
return .single(([], 0, nil))
return .single(([], 0, nil, nil))
}
return postbox.transaction { transaction -> ([ProfileGiftsContext.State.StarGift], Int32, String?) in
return postbox.transaction { transaction -> ([ProfileGiftsContext.State.StarGift], Int32, String?, Bool?) in
switch result {
case let .savedStarGifts(_, count, apiGifts, nextOffset, chats, users):
case let .savedStarGifts(_, count, apiNotificationsEnabled, apiGifts, nextOffset, chats, users):
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
var notificationsEnabled: Bool?
if let apiNotificationsEnabled {
if case .boolTrue = apiNotificationsEnabled {
notificationsEnabled = true
} else {
notificationsEnabled = false
}
}
let gifts = apiGifts.compactMap { ProfileGiftsContext.State.StarGift(apiSavedStarGift: $0, peerId: peerId, transaction: transaction) }
return (gifts, count, nextOffset)
return (gifts, count, nextOffset, notificationsEnabled)
}
}
}
}
self.disposable.set((signal
|> deliverOn(self.queue)).start(next: { [weak self] (gifts, count, nextOffset) in
|> deliverOn(self.queue)).start(next: { [weak self] (gifts, count, nextOffset, notificationsEnabled) in
guard let strongSelf = self else {
return
}
@ -1005,7 +1021,7 @@ private final class ProfileGiftsContextImpl {
strongSelf.gifts = gifts
strongSelf.cacheDisposable.set(strongSelf.account.postbox.transaction { transaction in
if let entry = CodableEntry(CachedProfileGifts(gifts: gifts, count: count)) {
if let entry = CodableEntry(CachedProfileGifts(gifts: gifts, count: count, notificationsEnabled: notificationsEnabled)) {
transaction.putItemCacheEntry(id: entryId(peerId: peerId), entry: entry)
}
}.start())
@ -1018,6 +1034,7 @@ private final class ProfileGiftsContextImpl {
let updatedCount = max(Int32(strongSelf.gifts.count), count)
strongSelf.count = updatedCount
strongSelf.dataState = .ready(canLoadMore: count != 0 && updatedCount > strongSelf.gifts.count && nextOffset != nil, nextOffset: nextOffset)
strongSelf.notificationsEnabled = notificationsEnabled
strongSelf.pushState()
}))
}
@ -1082,8 +1099,8 @@ private final class ProfileGiftsContextImpl {
}
private func pushState() {
self._state = ProfileGiftsContext.State(gifts: self.gifts, count: self.count, dataState: self.dataState)
self.stateValue.set(.single(ProfileGiftsContext.State(gifts: self.gifts, count: self.count, dataState: self.dataState)))
self._state = ProfileGiftsContext.State(gifts: self.gifts, count: self.count, dataState: self.dataState, notificationsEnabled: self.notificationsEnabled)
self.stateValue.set(.single(ProfileGiftsContext.State(gifts: self.gifts, count: self.count, dataState: self.dataState, notificationsEnabled: self.notificationsEnabled)))
}
}
@ -1246,6 +1263,7 @@ public final class ProfileGiftsContext {
public var gifts: [ProfileGiftsContext.State.StarGift]
public var count: Int32?
public var dataState: ProfileGiftsContext.State.DataState
public var notificationsEnabled: Bool?
}
private let queue: Queue = .mainQueue()
@ -1591,3 +1609,24 @@ func _internal_requestStarGiftWithdrawalUrl(account: Account, reference: StarGif
|> mapError { _ -> RequestStarGiftWithdrawalError in }
|> switchToLatest
}
func _internal_toggleStarGiftsNotifications(account: Account, peerId: EnginePeer.Id, enabled: Bool) -> Signal<Never, NoError> {
return account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
|> mapToSignal { inputPeer in
guard let inputPeer else {
return .complete()
}
var flags: Int32 = 0
if enabled {
flags |= (1 << 0)
}
return account.network.request(Api.functions.payments.toggleChatStarGiftNotifications(flags: flags, peer: inputPeer))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Bool?, NoError> in
return .single(nil)
}
|> ignoreValues
}
}

View File

@ -140,5 +140,13 @@ public extension TelegramEngine {
public func checkStarGiftWithdrawalAvailability(reference: StarGiftReference) -> Signal<Never, RequestStarGiftWithdrawalError> {
return _internal_checkStarGiftWithdrawalAvailability(account: self.account, reference: reference)
}
public func requestStarGiftWithdrawalUrl(reference: StarGiftReference, password: String) -> Signal<String, RequestStarGiftWithdrawalError> {
return _internal_requestStarGiftWithdrawalUrl(account: account, reference: reference, password: password)
}
public func toggleStarGiftsNotifications(peerId: EnginePeer.Id, enabled: Bool) -> Signal<Never, NoError> {
return _internal_toggleStarGiftsNotifications(account: self.account, peerId: peerId, enabled: enabled)
}
}
}

View File

@ -26,6 +26,7 @@ public final class GiftItemComponent: Component {
public enum Color: Equatable {
case red
case blue
case purple
case custom(Int32, Int32)
func colors(theme: PresentationTheme) -> [UIColor] {
@ -54,6 +55,11 @@ public final class GiftItemComponent: Component {
UIColor(rgb: 0x6fd3ff)
]
}
case .purple:
return [
UIColor(rgb: 0x747bf6),
UIColor(rgb: 0xe367d8)
]
case let .custom(topColor, _):
return [
UIColor(rgb: UInt32(bitPattern: topColor)).withMultiplied(hue: 0.97, saturation: 1.45, brightness: 0.89),
@ -489,7 +495,7 @@ public final class GiftItemComponent: Component {
ribbonTextView.bounds = CGRect(origin: .zero, size: ribbonTextSize)
if self.ribbon.image == nil || themeUpdated || previousComponent?.ribbon?.color != component.ribbon?.color {
var direction: GradientImageDirection = .diagonal
var direction: GradientImageDirection = .mirroredDiagonal
if case .custom = ribbon.color {
direction = .mirroredDiagonal
}

View File

@ -781,7 +781,7 @@ final class GiftOptionsScreenComponent: Component {
ribbon: product.discount.flatMap {
GiftItemComponent.Ribbon(
text: "-\($0)%",
color: .red
color: .purple
)
},
isLoading: self.inProgressPremiumGift == product.id

View File

@ -44,6 +44,8 @@ swift_library(
"//submodules/TelegramUI/Components/Gifts/GiftItemComponent",
"//submodules/MoreButtonNode",
"//submodules/TelegramUI/Components/EmojiStatusComponent",
"//submodules/PasswordSetupUI",
"//submodules/TelegramUI/Components/PeerManagement/OwnershipTransferController",
],
visibility = [
"//visibility:public",

View File

@ -3,6 +3,7 @@ import UIKit
import AsyncDisplayKit
import Display
import ComponentFlow
import SwiftSignalKit
import Postbox
import TelegramCore
import TelegramPresentationData
@ -12,6 +13,9 @@ import AppBundle
import Markdown
import GiftItemComponent
import StarsAvatarComponent
import PasswordSetupUI
import OwnershipTransferController
import PresentationDataUtils
private final class GiftWithdrawAlertContentNode: AlertContentNode {
private let context: AccountContext
@ -292,3 +296,104 @@ public func giftWithdrawAlertController(context: AccountContext, gift: StarGift.
}
return controller
}
public func confirmGiftWithdrawalController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, reference: StarGiftReference, present: @escaping (ViewController, Any?) -> Void, completion: @escaping (String) -> Void) -> ViewController {
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
var dismissImpl: (() -> Void)?
var proceedImpl: (() -> Void)?
let disposable = MetaDisposable()
let contentNode = ChannelOwnershipTransferAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), ptheme: presentationData.theme, strings: presentationData.strings, title: presentationData.strings.Gift_Withdraw_EnterPassword_Title, text: presentationData.strings.Gift_Withdraw_EnterPassword_Text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
dismissImpl?()
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Gift_Withdraw_EnterPassword_Done, action: {
proceedImpl?()
})])
contentNode.complete = {
proceedImpl?()
}
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
let presentationDataDisposable = (updatedPresentationData?.signal ?? context.sharedContext.presentationData).start(next: { [weak controller, weak contentNode] presentationData in
controller?.theme = AlertControllerTheme(presentationData: presentationData)
contentNode?.theme = presentationData.theme
})
controller.dismissed = { _ in
presentationDataDisposable.dispose()
disposable.dispose()
}
dismissImpl = { [weak controller, weak contentNode] in
contentNode?.dismissInput()
controller?.dismissAnimated()
}
proceedImpl = { [weak contentNode] in
guard let contentNode = contentNode else {
return
}
contentNode.updateIsChecking(true)
let signal = context.engine.payments.requestStarGiftWithdrawalUrl(reference: reference, password: contentNode.password)
disposable.set((signal |> deliverOnMainQueue).start(next: { url in
dismissImpl?()
completion(url)
}, error: { [weak contentNode] error in
var errorTextAndActions: (String, [TextAlertAction])?
switch error {
case .invalidPassword:
contentNode?.animateError()
case .limitExceeded:
errorTextAndActions = (presentationData.strings.TwoStepAuth_FloodError, [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
default:
errorTextAndActions = (presentationData.strings.Login_UnknownError, [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
}
contentNode?.updateIsChecking(false)
if let (text, actions) = errorTextAndActions {
dismissImpl?()
present(textAlertController(context: context, title: nil, text: text, actions: actions), nil)
}
}))
}
return controller
}
public func giftWithdrawalController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, reference: StarGiftReference, initialError: RequestStarGiftWithdrawalError, present: @escaping (ViewController, Any?) -> Void, completion: @escaping (String) -> Void) -> ViewController {
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
let theme = AlertControllerTheme(presentationData: presentationData)
var title: NSAttributedString? = NSAttributedString(string: presentationData.strings.Gift_Withdraw_SecurityCheck, font: Font.semibold(presentationData.listsFontSize.itemListBaseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center)
var text = presentationData.strings.Gift_Withdraw_SecurityRequirements
let textFontSize = presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0
var actions: [TextAlertAction] = []
switch initialError {
case .requestPassword:
return confirmGiftWithdrawalController(context: context, updatedPresentationData: updatedPresentationData, reference: reference, present: present, completion: completion)
case .twoStepAuthTooFresh, .authSessionTooFresh:
text = text + presentationData.strings.Gift_Withdraw_ComeBackLater
actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]
case .twoStepAuthMissing:
actions = [TextAlertAction(type: .genericAction, title: presentationData.strings.Gift_Withdraw_SetupTwoStepAuth, action: {
let controller = SetupTwoStepVerificationController(context: context, initialState: .automatic, stateUpdated: { update, shouldDismiss, controller in
if shouldDismiss {
controller.dismiss()
}
})
present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {})]
default:
title = nil
text = presentationData.strings.Login_UnknownError
actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]
}
let body = MarkdownAttributeSet(font: Font.regular(textFontSize), textColor: theme.primaryColor)
let bold = MarkdownAttributeSet(font: Font.semibold(textFontSize), textColor: theme.primaryColor)
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
return richTextAlertController(context: context, title: title, text: attributedText, actions: actions)
}

View File

@ -72,7 +72,6 @@ public func confirmStarsRevenueWithdrawalController(context: AccountContext, upd
return controller
}
public func starsRevenueWithdrawalController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id, amount: Int64, initialError: RequestStarsRevenueWithdrawalError, present: @escaping (ViewController, Any?) -> Void, completion: @escaping (String) -> Void) -> ViewController {
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
let theme = AlertControllerTheme(presentationData: presentationData)

View File

@ -2450,13 +2450,34 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}
presentExportAlertImpl = { [weak controller] in
guard let controller, case let .starGiftTransfer(_, _, gift, _, canExportDate) = source, let canExportDate else {
guard let controller, case let .starGiftTransfer(_, reference, gift, _, canExportDate) = source, let canExportDate else {
return
}
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
if currentTime > canExportDate || "".isEmpty {
let alertController = giftWithdrawAlertController(context: context, gift: gift, commit: {
let _ = (context.engine.payments.checkStarGiftWithdrawalAvailability(reference: reference)
|> deliverOnMainQueue).start(error: { [weak controller] error in
switch error {
case .serverProvided:
return
case .requestPassword:
let alertController = confirmGiftWithdrawalController(context: context, reference: reference, present: { [weak controller] c, a in
controller?.present(c, in: .window(.root))
}, completion: { url in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
})
controller?.present(alertController, in: .window(.root))
default:
let alertController = giftWithdrawalController(context: context, reference: reference, initialError: error, present: { [weak controller] c, a in
controller?.present(c, in: .window(.root))
}, completion: { _ in
})
controller?.present(alertController, in: .window(.root))
}
})
})
controller.present(alertController, in: .window(.root))
} else {