mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Various improvements
This commit is contained in:
parent
4ffb0e697e
commit
a663ea50cd
@ -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";
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) }
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user