mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various improvements
This commit is contained in:
parent
80cd8f7b32
commit
bafbe20063
Telegram/Telegram-iOS/en.lproj
submodules
AccountContext/Sources
AuthorizationUI/Sources
ChatListUI/Sources
Components
SolidRoundedButtonComponent/Sources
ViewControllerComponent/Sources
LegacyComponents/PublicHeaders/LegacyComponents
PremiumUI/Sources
SettingsUI/Sources/Privacy and Security
SolidRoundedButtonNode/Sources
TelegramApi/Sources
TelegramCore/Sources
ApiUtils
SyncCore
TelegramEngine/Messages
TelegramPresentationData/Sources
TelegramStringFormatting/Sources
TelegramUI
Components
Chat/ChatMessageDateAndStatusNode/Sources
PeerInfo
PeerInfoCoverComponent/Sources
PeerInfoScreen/Sources
Settings/AccountFreezeInfoScreen/Sources
Images.xcassets
Account Freeze
Chat/Message/StarsCount.imageset
Sources
@ -13996,3 +13996,13 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Stars.AccountRevenue.Proceeds.Info" = "Stars from your total balance can be withdrawn as rewards 21 days after they are earned.";
|
||||
"Stars.AccountRevenue.Withdraw.Info" = "You can collect rewards for Stars using Fragment. You cannot withdraw less than 1000 stars. [Learn More >]()";
|
||||
|
||||
"Notification.PaidMessageRefund.Stars_1" = "%@ Star";
|
||||
"Notification.PaidMessageRefund.Stars_any" = "%@ Stars";
|
||||
"Notification.PaidMessageRefund" = "%1$@ refunded you %2$@";
|
||||
"Notification.PaidMessageRefundYou" = "You refunded %1$@ to %2$@";
|
||||
|
||||
"Notification.PaidMessagePriceChanged.Stars_1" = "%@ Star";
|
||||
"Notification.PaidMessagePriceChanged.Stars_any" = "%@ Stars";
|
||||
"Notification.PaidMessagePriceChanged" = "%1$@ changed price to %2$@ per message";
|
||||
"Notification.PaidMessagePriceChangedYou" = "You changed price to %1$@ per message";
|
||||
|
@ -1053,7 +1053,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||
func makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?, temporary: Bool) -> ViewController
|
||||
|
||||
func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool, dismissed: (() -> Void)?) -> ViewController
|
||||
func makePremiumIntroController(sharedContext: SharedAccountContext, engine: TelegramEngineUnauthorized, inAppPurchaseManager: InAppPurchaseManager, source: PremiumIntroSource, dismissed: (() -> Void)?) -> ViewController
|
||||
func makePremiumIntroController(sharedContext: SharedAccountContext, engine: TelegramEngineUnauthorized, inAppPurchaseManager: InAppPurchaseManager, source: PremiumIntroSource, proceed: (() -> Void)?) -> ViewController
|
||||
|
||||
func makePremiumDemoController(context: AccountContext, subject: PremiumDemoSubject, forceDark: Bool, action: @escaping () -> Void, dismissed: (() -> Void)?) -> ViewController
|
||||
func makePremiumLimitController(context: AccountContext, subject: PremiumLimitSubject, count: Int32, forceDark: Bool, cancel: @escaping () -> Void, action: @escaping () -> Bool) -> ViewController
|
||||
@ -1232,6 +1232,7 @@ public protocol AccountContext: AnyObject {
|
||||
var availableMessageEffects: Signal<AvailableMessageEffects?, NoError> { get }
|
||||
|
||||
var isPremium: Bool { get }
|
||||
var isFrozen: Bool { get }
|
||||
var userLimits: EngineConfiguration.UserLimits { get }
|
||||
var peerNameColors: PeerNameColors { get }
|
||||
|
||||
|
@ -43,6 +43,7 @@ public enum PremiumIntroSource {
|
||||
case animatedEmoji
|
||||
case messageEffects
|
||||
case paidMessages
|
||||
case auth(String)
|
||||
}
|
||||
|
||||
public enum PremiumGiftSource: Equatable {
|
||||
|
@ -251,15 +251,17 @@ final class AuthorizationSequencePaymentScreenComponent: Component {
|
||||
iconName: "Premium/Authorization/Support",
|
||||
iconColor: linkColor,
|
||||
action: { [weak self] in
|
||||
guard let self, let controller = self.environment?.controller() else {
|
||||
guard let self, let controller = self.environment?.controller(), let product = self.products.first(where: { $0.id == component.storeProduct }) else {
|
||||
return
|
||||
}
|
||||
let introController = component.sharedContext.makePremiumIntroController(
|
||||
sharedContext: component.sharedContext,
|
||||
engine: component.engine,
|
||||
inAppPurchaseManager: component.inAppPurchaseManager,
|
||||
source: .about,
|
||||
dismissed: nil
|
||||
source: .auth(product.price),
|
||||
proceed: { [weak self] in
|
||||
self?.proceed()
|
||||
}
|
||||
)
|
||||
controller.push(introController)
|
||||
}
|
||||
@ -274,11 +276,13 @@ final class AuthorizationSequencePaymentScreenComponent: Component {
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: availableSize.height)
|
||||
)
|
||||
|
||||
let buttonHeight: CGFloat = 50.0
|
||||
let bottomPanelPadding: CGFloat = 12.0
|
||||
let titleSpacing: CGFloat = -24.0
|
||||
let listSpacing: CGFloat = 12.0
|
||||
let totalHeight = animationSize.height + titleSpacing + titleSize.height + listSpacing + listSize.height
|
||||
|
||||
var originY = floor((availableSize.height - totalHeight) / 2.0)
|
||||
var originY = floor((availableSize.height - buttonHeight - bottomPanelPadding * 2.0 - totalHeight) / 2.0)
|
||||
|
||||
if let animationView = self.animation.view {
|
||||
if animationView.superview == nil {
|
||||
@ -302,8 +306,6 @@ final class AuthorizationSequencePaymentScreenComponent: Component {
|
||||
listView.frame = CGRect(origin: CGPoint(x: floor((availableSize.width - listSize.width) / 2.0), y: originY), size: listSize)
|
||||
}
|
||||
|
||||
let buttonHeight: CGFloat = 50.0
|
||||
let bottomPanelPadding: CGFloat = 12.0
|
||||
let bottomInset: CGFloat = environment.safeInsets.bottom > 0.0 ? environment.safeInsets.bottom + 5.0 : bottomPanelPadding
|
||||
let bottomPanelHeight = bottomPanelPadding + buttonHeight + bottomInset
|
||||
|
||||
@ -329,7 +331,7 @@ final class AuthorizationSequencePaymentScreenComponent: Component {
|
||||
component: AnyComponent(
|
||||
VStack([
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))),
|
||||
AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: "Get Telegram Premium for 1 week", font: Font.regular(11.0), textColor: environment.theme.list.itemCheckColors.foregroundColor.withAlphaComponent(0.7), paragraphAlignment: .center)))))
|
||||
AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: "Get Telegram Premium for 1 week", font: Font.medium(11.0), textColor: environment.theme.list.itemCheckColors.foregroundColor.withAlphaComponent(0.7), paragraphAlignment: .center)))))
|
||||
], spacing: 1.0)
|
||||
)
|
||||
),
|
||||
@ -410,6 +412,10 @@ public final class AuthorizationSequencePaymentScreen: ViewControllerComponentCo
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override public func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
}
|
||||
|
||||
@objc private func cancelPressed() {
|
||||
self.dismiss()
|
||||
}
|
||||
|
@ -2794,6 +2794,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
private weak var storyCameraTooltip: TooltipScreen?
|
||||
fileprivate func openStoryCamera(fromList: Bool) {
|
||||
guard !self.context.isFrozen else {
|
||||
let controller = self.context.sharedContext.makeAccountFreezeInfoScreen(context: self.context)
|
||||
self.push(controller)
|
||||
return
|
||||
}
|
||||
|
||||
var reachedCountLimit = false
|
||||
var premiumNeeded = false
|
||||
var hasActiveCall = false
|
||||
@ -4641,6 +4647,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
|
||||
@objc fileprivate func composePressed() {
|
||||
guard !self.context.isFrozen else {
|
||||
let controller = self.context.sharedContext.makeAccountFreezeInfoScreen(context: self.context)
|
||||
self.push(controller)
|
||||
return
|
||||
}
|
||||
|
||||
guard let navigationController = self.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ public final class SolidRoundedButtonComponent: Component {
|
||||
public typealias Theme = SolidRoundedButtonTheme
|
||||
|
||||
public let title: String?
|
||||
public let subtitle: String?
|
||||
public let label: String?
|
||||
public let badge: String?
|
||||
public let icon: UIImage?
|
||||
@ -28,6 +29,7 @@ public final class SolidRoundedButtonComponent: Component {
|
||||
|
||||
public init(
|
||||
title: String? = nil,
|
||||
subtitle: String? = nil,
|
||||
label: String? = nil,
|
||||
badge: String? = nil,
|
||||
icon: UIImage? = nil,
|
||||
@ -46,6 +48,7 @@ public final class SolidRoundedButtonComponent: Component {
|
||||
action: @escaping () -> Void
|
||||
) {
|
||||
self.title = title
|
||||
self.subtitle = subtitle
|
||||
self.label = label
|
||||
self.badge = badge
|
||||
self.icon = icon
|
||||
@ -68,6 +71,9 @@ public final class SolidRoundedButtonComponent: Component {
|
||||
if lhs.title != rhs.title {
|
||||
return false
|
||||
}
|
||||
if lhs.subtitle != rhs.subtitle {
|
||||
return false
|
||||
}
|
||||
if lhs.label != rhs.label {
|
||||
return false
|
||||
}
|
||||
@ -147,6 +153,7 @@ public final class SolidRoundedButtonComponent: Component {
|
||||
|
||||
if let button = self.button {
|
||||
button.title = component.title
|
||||
button.subtitle = component.subtitle
|
||||
button.label = component.label
|
||||
button.badge = component.badge
|
||||
button.iconPosition = component.iconPosition
|
||||
|
@ -242,6 +242,7 @@ open class ViewControllerComponentContainer: ViewController {
|
||||
public private(set) var validLayout: ContainerViewLayout?
|
||||
|
||||
public var wasDismissed: (() -> Void)?
|
||||
public var customProceed: (() -> Void)?
|
||||
|
||||
public init<C: Component>(
|
||||
context: AccountContext,
|
||||
|
@ -67,9 +67,7 @@
|
||||
- (SSignal *)coverImageSignalForItem:(NSObject<TGMediaEditableItem> *)item;
|
||||
- (void)setCoverImage:(UIImage *)image position:(NSNumber *)position forItem:(id<TGMediaEditableItem>)item;
|
||||
- (UIImage *)coverImageForItem:(NSObject<TGMediaEditableItem> *)item;
|
||||
|
||||
- (NSNumber *)coverPositionForItem:(NSObject<TGMediaEditableItem> *)item;
|
||||
- (void)setCoverImage:(UIImage *)image position:(NSNumber *)position forItem:(id<TGMediaEditableItem>)item;
|
||||
|
||||
- (void)setTemporaryRep:(id)rep forItem:(id<TGMediaEditableItem>)item;
|
||||
|
||||
|
@ -309,6 +309,12 @@ public enum PremiumSource: Equatable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .auth(lhsPrice):
|
||||
if case let .auth(rhsPrice) = rhs, lhsPrice == rhsPrice {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,6 +363,7 @@ public enum PremiumSource: Equatable {
|
||||
case folderTags
|
||||
case messageEffects
|
||||
case paidMessages
|
||||
case auth(String)
|
||||
|
||||
var identifier: String? {
|
||||
switch self {
|
||||
@ -452,6 +459,8 @@ public enum PremiumSource: Equatable {
|
||||
return "effects"
|
||||
case .paidMessages:
|
||||
return "paid_messages"
|
||||
case .auth:
|
||||
return "auth"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1214,6 +1223,7 @@ final class PerkComponent: CombinedComponent {
|
||||
let subtitleColor: UIColor
|
||||
let arrowColor: UIColor
|
||||
let accentColor: UIColor
|
||||
let displayArrow: Bool
|
||||
let badge: String?
|
||||
|
||||
init(
|
||||
@ -1225,6 +1235,7 @@ final class PerkComponent: CombinedComponent {
|
||||
subtitleColor: UIColor,
|
||||
arrowColor: UIColor,
|
||||
accentColor: UIColor,
|
||||
displayArrow: Bool = true,
|
||||
badge: String? = nil
|
||||
) {
|
||||
self.iconName = iconName
|
||||
@ -1235,6 +1246,7 @@ final class PerkComponent: CombinedComponent {
|
||||
self.subtitleColor = subtitleColor
|
||||
self.arrowColor = arrowColor
|
||||
self.accentColor = accentColor
|
||||
self.displayArrow = displayArrow
|
||||
self.badge = badge
|
||||
}
|
||||
|
||||
@ -1263,6 +1275,9 @@ final class PerkComponent: CombinedComponent {
|
||||
if lhs.accentColor != rhs.accentColor {
|
||||
return false
|
||||
}
|
||||
if lhs.displayArrow != rhs.displayArrow {
|
||||
return false
|
||||
}
|
||||
if lhs.badge != rhs.badge {
|
||||
return false
|
||||
}
|
||||
@ -1305,16 +1320,7 @@ final class PerkComponent: CombinedComponent {
|
||||
availableSize: iconSize,
|
||||
transition: context.transition
|
||||
)
|
||||
|
||||
let arrow = arrow.update(
|
||||
component: BundleIconComponent(
|
||||
name: "Item List/DisclosureArrow",
|
||||
tintColor: component.arrowColor
|
||||
),
|
||||
availableSize: context.availableSize,
|
||||
transition: context.transition
|
||||
)
|
||||
|
||||
|
||||
let title = title.update(
|
||||
component: MultilineTextComponent(
|
||||
text: .plain(
|
||||
@ -1391,9 +1397,20 @@ final class PerkComponent: CombinedComponent {
|
||||
)
|
||||
|
||||
let size = CGSize(width: context.availableSize.width, height: textTopInset + title.size.height + spacing + subtitle.size.height + textBottomInset)
|
||||
context.add(arrow
|
||||
.position(CGPoint(x: context.availableSize.width - 7.0 - arrow.size.width / 2.0, y: size.height / 2.0))
|
||||
)
|
||||
|
||||
if component.displayArrow {
|
||||
let arrow = arrow.update(
|
||||
component: BundleIconComponent(
|
||||
name: "Item List/DisclosureArrow",
|
||||
tintColor: component.arrowColor
|
||||
),
|
||||
availableSize: context.availableSize,
|
||||
transition: context.transition
|
||||
)
|
||||
context.add(arrow
|
||||
.position(CGPoint(x: context.availableSize.width - 7.0 - arrow.size.width / 2.0, y: size.height / 2.0))
|
||||
)
|
||||
}
|
||||
|
||||
return size
|
||||
}
|
||||
@ -2086,6 +2103,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
foregroundColor: .white,
|
||||
iconName: perk.iconName
|
||||
))), false),
|
||||
accessory: accountContext != nil ? .arrow : nil,
|
||||
action: { [weak state] _ in
|
||||
guard let accountContext else {
|
||||
return
|
||||
@ -2162,7 +2180,8 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
updateIsFocused(true)
|
||||
|
||||
addAppLogEvent(postbox: accountContext.account.postbox, type: "premium.promo_screen_tap", data: ["item": perk.identifier])
|
||||
}
|
||||
},
|
||||
highlighting: accountContext != nil ? .default : .disabled
|
||||
))))
|
||||
i += 1
|
||||
}
|
||||
@ -3660,7 +3679,11 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
|
||||
if !buttonIsHidden {
|
||||
let buttonTitle: String
|
||||
if isUnusedGift {
|
||||
var buttonSubtitle: String?
|
||||
if case let .auth(price) = context.component.source {
|
||||
buttonTitle = "Sign up for \(price)"
|
||||
buttonSubtitle = "Get Telegram Premium for 1 week"
|
||||
} else if isUnusedGift {
|
||||
buttonTitle = environment.strings.Premium_Gift_ApplyLink
|
||||
} else if state.isPremium == true && state.canUpgrade {
|
||||
buttonTitle = state.isAnnual ? environment.strings.Premium_UpgradeForAnnual(state.price ?? "—").string : environment.strings.Premium_UpgradeFor(state.price ?? "—").string
|
||||
@ -3668,10 +3691,12 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
buttonTitle = state.isAnnual ? environment.strings.Premium_SubscribeForAnnual(state.price ?? "—").string : environment.strings.Premium_SubscribeFor(state.price ?? "—").string
|
||||
}
|
||||
|
||||
let controller = environment.controller
|
||||
let sideInset: CGFloat = 16.0
|
||||
let button = button.update(
|
||||
component: SolidRoundedButtonComponent(
|
||||
title: buttonTitle,
|
||||
subtitle: buttonSubtitle,
|
||||
theme: SolidRoundedButtonComponent.Theme(
|
||||
backgroundColor: UIColor(rgb: 0x8878ff),
|
||||
backgroundColors: [
|
||||
@ -3687,7 +3712,12 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
gloss: true,
|
||||
isLoading: state.inProgress,
|
||||
action: {
|
||||
state.buy()
|
||||
if let controller = controller() as? PremiumIntroScreen, let customProceed = controller.customProceed {
|
||||
controller.dismiss()
|
||||
customProceed()
|
||||
} else {
|
||||
state.buy()
|
||||
}
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - environment.safeInsets.left - environment.safeInsets.right, height: 50.0),
|
||||
|
@ -315,7 +315,7 @@ private func selectivePrivacyPeersControllerEntries(presentationData: Presentati
|
||||
entries.append(.footerItem(footer))
|
||||
}
|
||||
|
||||
if !peers.isEmpty {
|
||||
if !peers.isEmpty || state.enableForPremium || state.enableForBots {
|
||||
entries.append(.deleteItem(presentationData.strings.Privacy_Exceptions_DeleteAllExceptions))
|
||||
}
|
||||
|
||||
|
@ -1412,7 +1412,7 @@ public final class SolidRoundedButtonView: UIView {
|
||||
}
|
||||
|
||||
self.titleNode.attributedText = titleText
|
||||
self.subtitleNode.attributedText = NSAttributedString(string: self.subtitle ?? "", font: Font.regular(14.0), textColor: theme.foregroundColor)
|
||||
self.subtitleNode.attributedText = NSAttributedString(string: self.subtitle ?? "", font: Font.medium(11.0), textColor: theme.foregroundColor.withAlphaComponent(0.7))
|
||||
|
||||
self.iconNode.image = generateTintedImage(image: self.iconNode.image, color: theme.foregroundColor)
|
||||
|
||||
@ -1472,7 +1472,7 @@ public final class SolidRoundedButtonView: UIView {
|
||||
}
|
||||
let titleSize = self.titleNode.updateLayout(buttonSize)
|
||||
|
||||
let spacingOffset: CGFloat = 9.0
|
||||
let spacingOffset: CGFloat = 7.0
|
||||
let verticalInset: CGFloat = self.subtitle == nil ? floor((buttonFrame.height - titleSize.height) / 2.0) : floor((buttonFrame.height - titleSize.height) / 2.0) - spacingOffset
|
||||
let iconSpacing: CGFloat = self.iconSpacing
|
||||
let badgeSpacing: CGFloat = 6.0
|
||||
@ -1533,11 +1533,11 @@ public final class SolidRoundedButtonView: UIView {
|
||||
}
|
||||
|
||||
if self.subtitle != self.subtitleNode.attributedText?.string {
|
||||
self.subtitleNode.attributedText = NSAttributedString(string: self.subtitle ?? "", font: Font.regular(14.0), textColor: self.theme.foregroundColor)
|
||||
self.subtitleNode.attributedText = NSAttributedString(string: self.subtitle ?? "", font: Font.medium(11.0), textColor: self.theme.foregroundColor.withAlphaComponent(0.7))
|
||||
}
|
||||
|
||||
let subtitleSize = self.subtitleNode.updateLayout(buttonSize)
|
||||
let subtitleFrame = CGRect(origin: CGPoint(x: buttonFrame.minX + floor((buttonFrame.width - subtitleSize.width) / 2.0), y: buttonFrame.minY + floor((buttonFrame.height - titleSize.height) / 2.0) + spacingOffset + 2.0), size: subtitleSize)
|
||||
let subtitleFrame = CGRect(origin: CGPoint(x: buttonFrame.minX + floor((buttonFrame.width - subtitleSize.width) / 2.0), y: buttonFrame.minY + floor((buttonFrame.height - titleSize.height) / 2.0) + spacingOffset + 7.0), size: subtitleSize)
|
||||
transition.updateFrame(view: self.subtitleNode, frame: subtitleFrame)
|
||||
|
||||
if previousSubtitle == nil && self.subtitle != nil {
|
||||
|
@ -577,6 +577,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1281329567] = { return Api.MessageAction.parse_messageActionGroupCallScheduled($0) }
|
||||
dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) }
|
||||
dict[1345295095] = { return Api.MessageAction.parse_messageActionInviteToGroupCall($0) }
|
||||
dict[-1126755303] = { return Api.MessageAction.parse_messageActionPaidMessagesPrice($0) }
|
||||
dict[-1407246387] = { return Api.MessageAction.parse_messageActionPaidMessagesRefunded($0) }
|
||||
dict[1102307842] = { return Api.MessageAction.parse_messageActionPaymentRefunded($0) }
|
||||
dict[-970673810] = { return Api.MessageAction.parse_messageActionPaymentSent($0) }
|
||||
dict[-6288180] = { return Api.MessageAction.parse_messageActionPaymentSentMe($0) }
|
||||
|
@ -363,6 +363,8 @@ public extension Api {
|
||||
case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32)
|
||||
case messageActionHistoryClear
|
||||
case messageActionInviteToGroupCall(call: Api.InputGroupCall, users: [Int64])
|
||||
case messageActionPaidMessagesPrice(stars: Int64)
|
||||
case messageActionPaidMessagesRefunded(count: Int32, stars: Int64)
|
||||
case messageActionPaymentRefunded(flags: Int32, peer: Api.Peer, currency: String, totalAmount: Int64, payload: Buffer?, charge: Api.PaymentCharge)
|
||||
case messageActionPaymentSent(flags: Int32, currency: String, totalAmount: Int64, invoiceSlug: String?, subscriptionUntilDate: Int32?)
|
||||
case messageActionPaymentSentMe(flags: Int32, currency: String, totalAmount: Int64, payload: Buffer, info: Api.PaymentRequestedInfo?, shippingOptionId: String?, charge: Api.PaymentCharge, subscriptionUntilDate: Int32?)
|
||||
@ -595,6 +597,19 @@ public extension Api {
|
||||
serializeInt64(item, buffer: buffer, boxed: false)
|
||||
}
|
||||
break
|
||||
case .messageActionPaidMessagesPrice(let stars):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1126755303)
|
||||
}
|
||||
serializeInt64(stars, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .messageActionPaidMessagesRefunded(let count, let stars):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1407246387)
|
||||
}
|
||||
serializeInt32(count, buffer: buffer, boxed: false)
|
||||
serializeInt64(stars, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .messageActionPaymentRefunded(let flags, let peer, let currency, let totalAmount, let payload, let charge):
|
||||
if boxed {
|
||||
buffer.appendInt32(1102307842)
|
||||
@ -847,6 +862,10 @@ public extension Api {
|
||||
return ("messageActionHistoryClear", [])
|
||||
case .messageActionInviteToGroupCall(let call, let users):
|
||||
return ("messageActionInviteToGroupCall", [("call", call as Any), ("users", users as Any)])
|
||||
case .messageActionPaidMessagesPrice(let stars):
|
||||
return ("messageActionPaidMessagesPrice", [("stars", stars as Any)])
|
||||
case .messageActionPaidMessagesRefunded(let count, let stars):
|
||||
return ("messageActionPaidMessagesRefunded", [("count", count as Any), ("stars", stars as Any)])
|
||||
case .messageActionPaymentRefunded(let flags, let peer, let currency, let totalAmount, let payload, let charge):
|
||||
return ("messageActionPaymentRefunded", [("flags", flags as Any), ("peer", peer as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("payload", payload as Any), ("charge", charge as Any)])
|
||||
case .messageActionPaymentSent(let flags, let currency, let totalAmount, let invoiceSlug, let subscriptionUntilDate):
|
||||
@ -1277,6 +1296,31 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_messageActionPaidMessagesPrice(_ reader: BufferReader) -> MessageAction? {
|
||||
var _1: Int64?
|
||||
_1 = reader.readInt64()
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.MessageAction.messageActionPaidMessagesPrice(stars: _1!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_messageActionPaidMessagesRefunded(_ reader: BufferReader) -> MessageAction? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int64?
|
||||
_2 = reader.readInt64()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.MessageAction.messageActionPaidMessagesRefunded(count: _1!, stars: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_messageActionPaymentRefunded(_ reader: BufferReader) -> MessageAction? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
|
@ -227,7 +227,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
|
||||
}
|
||||
|
||||
switch action {
|
||||
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall, .messageActionSetMessagesTTL, .messageActionGroupCallScheduled, .messageActionSetChatTheme, .messageActionChatJoinedByRequest, .messageActionWebViewDataSent, .messageActionWebViewDataSentMe, .messageActionGiftPremium, .messageActionGiftStars, .messageActionTopicCreate, .messageActionTopicEdit, .messageActionSuggestProfilePhoto, .messageActionSetChatWallPaper, .messageActionGiveawayLaunch, .messageActionGiveawayResults, .messageActionBoostApply, .messageActionRequestedPeerSentMe, .messageActionStarGift, .messageActionStarGiftUnique:
|
||||
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall, .messageActionSetMessagesTTL, .messageActionGroupCallScheduled, .messageActionSetChatTheme, .messageActionChatJoinedByRequest, .messageActionWebViewDataSent, .messageActionWebViewDataSentMe, .messageActionGiftPremium, .messageActionGiftStars, .messageActionTopicCreate, .messageActionTopicEdit, .messageActionSuggestProfilePhoto, .messageActionSetChatWallPaper, .messageActionGiveawayLaunch, .messageActionGiveawayResults, .messageActionBoostApply, .messageActionRequestedPeerSentMe, .messageActionStarGift, .messageActionStarGiftUnique, .messageActionPaidMessagesRefunded, .messageActionPaidMessagesPrice:
|
||||
break
|
||||
case let .messageActionChannelMigrateFrom(_, chatId):
|
||||
result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId)))
|
||||
|
@ -191,6 +191,10 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
||||
return nil
|
||||
}
|
||||
return TelegramMediaAction(action: .starGiftUnique(gift: gift, isUpgrade: (flags & (1 << 0)) != 0, isTransferred: (flags & (1 << 1)) != 0, savedToProfile: (flags & (1 << 2)) != 0, canExportDate: canExportAt, transferStars: transferStars, isRefunded: (flags & (1 << 5)) != 0, peerId: peer?.peerId, senderId: fromId?.peerId, savedId: savedId))
|
||||
case let .messageActionPaidMessagesRefunded(count, stars):
|
||||
return TelegramMediaAction(action: .paidMessagesRefunded(count: count, stars: stars))
|
||||
case let .messageActionPaidMessagesPrice(stars):
|
||||
return TelegramMediaAction(action: .paidMessagesPriceEdited(stars: stars))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,6 +132,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
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, upgraded: Bool, canUpgrade: Bool, upgradeStars: Int64?, isRefunded: Bool, upgradeMessageId: Int32?, peerId: EnginePeer.Id?, senderId: EnginePeer.Id?, savedId: Int64?)
|
||||
case starGiftUnique(gift: StarGift, isUpgrade: Bool, isTransferred: Bool, savedToProfile: Bool, canExportDate: Int32?, transferStars: Int64?, isRefunded: Bool, peerId: EnginePeer.Id?, senderId: EnginePeer.Id?, savedId: Int64?)
|
||||
case paidMessagesRefunded(count: Int32, stars: Int64)
|
||||
case paidMessagesPriceEdited(stars: Int64)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0)
|
||||
@ -256,6 +258,10 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
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), upgraded: decoder.decodeBoolForKey("upgraded", orElse: false), canUpgrade: decoder.decodeBoolForKey("canUpgrade", orElse: false), upgradeStars: decoder.decodeOptionalInt64ForKey("upgradeStars"), isRefunded: decoder.decodeBoolForKey("isRefunded", orElse: false), upgradeMessageId: decoder.decodeOptionalInt32ForKey("upgradeMessageId"), peerId: decoder.decodeOptionalInt64ForKey("peerId").flatMap { EnginePeer.Id($0) }, senderId: decoder.decodeOptionalInt64ForKey("senderId").flatMap { EnginePeer.Id($0) }, savedId: decoder.decodeOptionalInt64ForKey("savedId"))
|
||||
case 45:
|
||||
self = .starGiftUnique(gift: decoder.decodeObjectForKey("gift", decoder: { StarGift(decoder: $0) }) as! StarGift, isUpgrade: decoder.decodeBoolForKey("isUpgrade", orElse: false), isTransferred: decoder.decodeBoolForKey("isTransferred", orElse: false), savedToProfile: decoder.decodeBoolForKey("savedToProfile", orElse: false), canExportDate: decoder.decodeOptionalInt32ForKey("canExportDate"), transferStars: decoder.decodeOptionalInt64ForKey("transferStars"), isRefunded: decoder.decodeBoolForKey("isRefunded", orElse: false), peerId: decoder.decodeOptionalInt64ForKey("peerId").flatMap { EnginePeer.Id($0) }, senderId: decoder.decodeOptionalInt64ForKey("senderId").flatMap { EnginePeer.Id($0) }, savedId: decoder.decodeOptionalInt64ForKey("savedId"))
|
||||
case 46:
|
||||
self = .paidMessagesRefunded(count: decoder.decodeInt32ForKey("count", orElse: 0), stars: decoder.decodeInt64ForKey("stars", orElse: 0))
|
||||
case 47:
|
||||
self = .paidMessagesPriceEdited(stars: decoder.decodeInt64ForKey("stars", orElse: 0))
|
||||
default:
|
||||
self = .unknown
|
||||
}
|
||||
@ -626,6 +632,13 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "savedId")
|
||||
}
|
||||
case let .paidMessagesRefunded(count, stars):
|
||||
encoder.encodeInt32(46, forKey: "_rawValue")
|
||||
encoder.encodeInt32(count, forKey: "count")
|
||||
encoder.encodeInt64(stars, forKey: "stars")
|
||||
case let .paidMessagesPriceEdited(stars):
|
||||
encoder.encodeInt32(47, forKey: "_rawValue")
|
||||
encoder.encodeInt64(stars, forKey: "stars")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,14 @@ func _internal_peerSendAsAvailablePeers(accountPeerId: PeerId, network: Network,
|
||||
return .single([])
|
||||
}
|
||||
|
||||
if let channel = peer as? TelegramChannel, case .group = channel.info {
|
||||
if let channel = peer as? TelegramChannel {
|
||||
if case .group = channel.info {
|
||||
|
||||
} else if channel.adminRights != nil || channel.flags.contains(.isCreator) {
|
||||
|
||||
} else {
|
||||
return .single([])
|
||||
}
|
||||
} else {
|
||||
return .single([])
|
||||
}
|
||||
|
@ -170,6 +170,12 @@ public final class PrincipalThemeEssentialGraphics {
|
||||
public let outgoingDateAndStatusRepliesIcon: UIImage
|
||||
public let mediaRepliesIcon: UIImage
|
||||
public let freeRepliesIcon: UIImage
|
||||
|
||||
public let incomingDateAndStatusStarsIcon: UIImage
|
||||
public let outgoingDateAndStatusStarsIcon: UIImage
|
||||
public let mediaStarsIcon: UIImage
|
||||
public let freeStarsIcon: UIImage
|
||||
|
||||
public let incomingDateAndStatusPinnedIcon: UIImage
|
||||
public let outgoingDateAndStatusPinnedIcon: UIImage
|
||||
public let mediaPinnedIcon: UIImage
|
||||
@ -358,6 +364,12 @@ public final class PrincipalThemeEssentialGraphics {
|
||||
self.mediaRepliesIcon = generateTintedImage(image: repliesImage, color: .white)!
|
||||
self.freeRepliesIcon = generateTintedImage(image: repliesImage, color: serviceColor.primaryText)!
|
||||
|
||||
let starsImage = UIImage(bundleImageName: "Chat/Message/StarsCount")!
|
||||
self.incomingDateAndStatusStarsIcon = generateTintedImage(image: starsImage, color: theme.message.incoming.secondaryTextColor)!
|
||||
self.outgoingDateAndStatusStarsIcon = generateTintedImage(image: starsImage, color: theme.message.outgoing.secondaryTextColor)!
|
||||
self.mediaStarsIcon = generateTintedImage(image: starsImage, color: .white)!
|
||||
self.freeStarsIcon = generateTintedImage(image: starsImage, color: serviceColor.primaryText)!
|
||||
|
||||
let pinnedImage = UIImage(bundleImageName: "Chat/Message/Pinned")!
|
||||
self.incomingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.incoming.secondaryTextColor)!
|
||||
self.outgoingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.outgoing.secondaryTextColor)!
|
||||
@ -479,6 +491,12 @@ public final class PrincipalThemeEssentialGraphics {
|
||||
self.mediaRepliesIcon = generateTintedImage(image: repliesImage, color: .white)!
|
||||
self.freeRepliesIcon = generateTintedImage(image: repliesImage, color: serviceColor.primaryText)!
|
||||
|
||||
let starsImage = UIImage(bundleImageName: "Chat/Message/StarsCount")!
|
||||
self.incomingDateAndStatusStarsIcon = generateTintedImage(image: starsImage, color: theme.message.incoming.secondaryTextColor)!
|
||||
self.outgoingDateAndStatusStarsIcon = generateTintedImage(image: starsImage, color: theme.message.outgoing.secondaryTextColor)!
|
||||
self.mediaStarsIcon = generateTintedImage(image: starsImage, color: .white)!
|
||||
self.freeStarsIcon = generateTintedImage(image: starsImage, color: serviceColor.primaryText)!
|
||||
|
||||
let pinnedImage = UIImage(bundleImageName: "Chat/Message/Pinned")!
|
||||
self.incomingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.incoming.secondaryTextColor)!
|
||||
self.outgoingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.outgoing.secondaryTextColor)!
|
||||
|
@ -1196,6 +1196,33 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .paidMessagesRefunded(_, stars):
|
||||
let starsString = strings.Notification_PaidMessageRefund_Stars(Int32(stars))
|
||||
if message.author?.id == accountPeerId, let messagePeer = message.peers[message.id.peerId] {
|
||||
let peerName = EnginePeer(messagePeer).compactDisplayTitle
|
||||
var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(1, messagePeer.id)])
|
||||
attributes[0] = boldAttributes
|
||||
let resultString = strings.Notification_PaidMessageRefundYou(starsString, peerName)
|
||||
attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: attributes)
|
||||
} else {
|
||||
let peerName = message.author?.compactDisplayTitle ?? ""
|
||||
var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])
|
||||
attributes[1] = boldAttributes
|
||||
let resultString = strings.Notification_PaidMessageRefund(peerName, starsString)
|
||||
attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: attributes)
|
||||
}
|
||||
case let .paidMessagesPriceEdited(stars):
|
||||
let starsString = strings.Notification_PaidMessagePriceChanged_Stars(Int32(stars))
|
||||
if message.author?.id == accountPeerId {
|
||||
let resultString = strings.Notification_PaidMessagePriceChangedYou(starsString)
|
||||
attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
|
||||
} else {
|
||||
let peerName = message.author?.compactDisplayTitle ?? ""
|
||||
var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])
|
||||
attributes[1] = boldAttributes
|
||||
let resultString = strings.Notification_PaidMessagePriceChanged(peerName, starsString)
|
||||
attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: attributes)
|
||||
}
|
||||
case .unknown:
|
||||
attributedString = nil
|
||||
}
|
||||
|
@ -413,7 +413,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
repliesImage = graphics.incomingDateAndStatusPinnedIcon
|
||||
}
|
||||
if (arguments.starsCount ?? 0) != 0 {
|
||||
starsImage = graphics.incomingDateAndStatusRepliesIcon
|
||||
starsImage = graphics.incomingDateAndStatusStarsIcon
|
||||
}
|
||||
case let .BubbleOutgoing(status):
|
||||
dateColor = arguments.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor
|
||||
@ -432,7 +432,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
repliesImage = graphics.outgoingDateAndStatusPinnedIcon
|
||||
}
|
||||
if (arguments.starsCount ?? 0) != 0 {
|
||||
starsImage = graphics.outgoingDateAndStatusRepliesIcon
|
||||
starsImage = graphics.outgoingDateAndStatusStarsIcon
|
||||
}
|
||||
case .ImageIncoming:
|
||||
dateColor = arguments.presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor
|
||||
@ -451,7 +451,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
repliesImage = graphics.mediaPinnedIcon
|
||||
}
|
||||
if (arguments.starsCount ?? 0) != 0 {
|
||||
starsImage = graphics.mediaRepliesIcon
|
||||
starsImage = graphics.mediaStarsIcon
|
||||
}
|
||||
case let .ImageOutgoing(status):
|
||||
dateColor = arguments.presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor
|
||||
@ -471,7 +471,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
repliesImage = graphics.mediaPinnedIcon
|
||||
}
|
||||
if (arguments.starsCount ?? 0) != 0 {
|
||||
starsImage = graphics.mediaRepliesIcon
|
||||
starsImage = graphics.mediaStarsIcon
|
||||
}
|
||||
case .FreeIncoming:
|
||||
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
|
||||
@ -492,7 +492,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
repliesImage = graphics.freePinnedIcon
|
||||
}
|
||||
if (arguments.starsCount ?? 0) != 0 {
|
||||
starsImage = graphics.freeRepliesIcon
|
||||
starsImage = graphics.freeStarsIcon
|
||||
}
|
||||
case let .FreeOutgoing(status):
|
||||
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
|
||||
@ -513,7 +513,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
repliesImage = graphics.freePinnedIcon
|
||||
}
|
||||
if (arguments.starsCount ?? 0) != 0 {
|
||||
starsImage = graphics.freeRepliesIcon
|
||||
starsImage = graphics.freeStarsIcon
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -516,7 +516,7 @@ public final class PeerInfoCoverComponent: Component {
|
||||
let baseItemDistance: CGFloat = baseDistance + CGFloat(row) * baseRowDistance
|
||||
|
||||
let itemDistanceFraction = max(0.0, min(1.0, baseItemDistance / (baseDistance * 2.0)))
|
||||
let itemScaleFraction = patternScaleValueAt(fraction: component.avatarTransitionFraction, t: itemDistanceFraction, reverse: false)
|
||||
let itemScaleFraction = patternScaleValueAt(fraction: min(1.0, component.avatarTransitionFraction * 1.56), t: itemDistanceFraction, reverse: false)
|
||||
let itemDistance = baseItemDistance * (1.0 - itemScaleFraction) + 20.0 * itemScaleFraction
|
||||
|
||||
var itemAngle: CGFloat
|
||||
|
@ -19,6 +19,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
||||
public let giftsContext: ProfileGiftsContext
|
||||
public let hasBackground: Bool
|
||||
public let avatarCenter: CGPoint
|
||||
public let avatarSize: CGSize
|
||||
public let defaultHeight: CGFloat
|
||||
public let avatarTransitionFraction: CGFloat
|
||||
public let statusBarHeight: CGFloat
|
||||
@ -34,6 +35,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
||||
giftsContext: ProfileGiftsContext,
|
||||
hasBackground: Bool,
|
||||
avatarCenter: CGPoint,
|
||||
avatarSize: CGSize,
|
||||
defaultHeight: CGFloat,
|
||||
avatarTransitionFraction: CGFloat,
|
||||
statusBarHeight: CGFloat,
|
||||
@ -48,6 +50,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
||||
self.giftsContext = giftsContext
|
||||
self.hasBackground = hasBackground
|
||||
self.avatarCenter = avatarCenter
|
||||
self.avatarSize = avatarSize
|
||||
self.defaultHeight = defaultHeight
|
||||
self.avatarTransitionFraction = avatarTransitionFraction
|
||||
self.statusBarHeight = statusBarHeight
|
||||
@ -71,6 +74,9 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
||||
if lhs.avatarCenter != rhs.avatarCenter {
|
||||
return false
|
||||
}
|
||||
if lhs.avatarSize != rhs.avatarSize {
|
||||
return false
|
||||
}
|
||||
if lhs.defaultHeight != rhs.defaultHeight {
|
||||
return false
|
||||
}
|
||||
@ -298,26 +304,25 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
||||
}
|
||||
iconLayer.glowing = component.hasBackground
|
||||
|
||||
let centerPosition = component.avatarCenter
|
||||
let finalPosition = iconPosition.center.offsetBy(dx: component.avatarCenter.x, dy: component.avatarCenter.y)
|
||||
let itemScaleFraction = patternScaleValueAt(fraction: component.avatarTransitionFraction, t: 0.0, reverse: false)
|
||||
let itemDistanceFraction = max(0.0, min(1.0, iconPosition.distance / 100.0))
|
||||
let itemScaleFraction = patternScaleValueAt(fraction: min(1.0, component.avatarTransitionFraction * 1.56), t: itemDistanceFraction, reverse: false)
|
||||
|
||||
func interpolateRect(from: CGPoint, to: CGPoint, t: CGFloat) -> CGPoint {
|
||||
func interpolatePosition(from: PositionGenerator.Position, to: PositionGenerator.Position, t: CGFloat) -> PositionGenerator.Position {
|
||||
let clampedT = max(0, min(1, t))
|
||||
|
||||
let interpolatedX = from.x + (to.x - from.x) * clampedT
|
||||
let interpolatedY = from.y + (to.y - from.y) * clampedT
|
||||
let interpolatedDistance = from.distance + (to.distance - from.distance) * clampedT
|
||||
let interpolatedAngle = from.angle + (to.angle - from.angle) * clampedT
|
||||
|
||||
return CGPoint(
|
||||
x: interpolatedX,
|
||||
y: interpolatedY
|
||||
)
|
||||
return PositionGenerator.Position(distance: interpolatedDistance, angle: interpolatedAngle, scale: from.scale)
|
||||
}
|
||||
|
||||
let effectivePosition = interpolateRect(from: finalPosition, to: centerPosition, t: itemScaleFraction)
|
||||
let centerPosition = PositionGenerator.Position(distance: 0.0, angle: iconPosition.angle + .pi * 0.18, scale: iconPosition.scale)
|
||||
let effectivePosition = interpolatePosition(from: iconPosition, to: centerPosition, t: itemScaleFraction)
|
||||
|
||||
let position = getAbsolutePosition(position: effectivePosition, centerPoint: component.avatarCenter)
|
||||
|
||||
iconTransition.setBounds(layer: iconLayer, bounds: CGRect(origin: .zero, size: iconSize))
|
||||
iconTransition.setPosition(layer: iconLayer, position: effectivePosition)
|
||||
iconTransition.setPosition(layer: iconLayer, position: position)
|
||||
iconTransition.setScale(layer: iconLayer, scale: iconPosition.scale * (1.0 - itemScaleFraction))
|
||||
iconTransition.setAlpha(layer: iconLayer, alpha: 1.0 - itemScaleFraction)
|
||||
|
||||
@ -638,8 +643,16 @@ private class GiftIconLayer: SimpleLayer {
|
||||
|
||||
private struct PositionGenerator {
|
||||
struct Position {
|
||||
let center: CGPoint
|
||||
let distance: CGFloat
|
||||
let angle: CGFloat
|
||||
let scale: CGFloat
|
||||
|
||||
var relativeCartesian: CGPoint {
|
||||
return CGPoint(
|
||||
x: self.distance * cos(self.angle),
|
||||
y: self.distance * sin(self.angle)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let containerSize: CGSize
|
||||
@ -700,15 +713,14 @@ private struct PositionGenerator {
|
||||
|
||||
let orbitRangeSize = self.innerOrbitRange.max - self.innerOrbitRange.min
|
||||
let orbitDistanceFactor = self.innerOrbitRange.min + orbitRangeSize * CGFloat(self.lokiRng.next())
|
||||
let orbitDistance = orbitDistanceFactor * centerRadius
|
||||
let distance = orbitDistanceFactor * centerRadius
|
||||
|
||||
let angleRange: CGFloat = placeOnLeftSide ? .pi : .pi
|
||||
let angleOffset: CGFloat = placeOnLeftSide ? .pi/2 : -(.pi/2)
|
||||
let angle = angleOffset + angleRange * CGFloat(self.lokiRng.next())
|
||||
|
||||
let absoluteX = centerPoint.x + orbitDistance * cos(angle)
|
||||
let absoluteY = centerPoint.y + orbitDistance * sin(angle)
|
||||
let absolutePosition = CGPoint(x: absoluteX, y: absoluteY)
|
||||
// Get the absolute position to check boundaries and collisions
|
||||
let absolutePosition = getAbsolutePosition(distance: distance, angle: angle, centerPoint: centerPoint)
|
||||
|
||||
if absolutePosition.x - itemSize.width/2 < self.edgePadding ||
|
||||
absolutePosition.x + itemSize.width/2 > self.containerSize.width - self.edgePadding ||
|
||||
@ -717,11 +729,6 @@ private struct PositionGenerator {
|
||||
continue
|
||||
}
|
||||
|
||||
let relativePosition = CGPoint(
|
||||
x: absolutePosition.x - centerPoint.x,
|
||||
y: absolutePosition.y - centerPoint.y
|
||||
)
|
||||
|
||||
let itemRect = CGRect(
|
||||
x: absolutePosition.x - itemSize.width/2,
|
||||
y: absolutePosition.y - itemSize.height/2,
|
||||
@ -729,10 +736,12 @@ private struct PositionGenerator {
|
||||
height: itemSize.height
|
||||
)
|
||||
|
||||
if self.isValidPosition(itemRect, existingPositions: positions.map { self.posToAbsolute($0.center, centerPoint: centerPoint) }, itemSize: itemSize) {
|
||||
if self.isValidPosition(itemRect, existingPositions: positions.map {
|
||||
getAbsolutePosition(distance: $0.distance, angle: $0.angle, centerPoint: centerPoint)
|
||||
}, itemSize: itemSize) {
|
||||
let scaleRangeSize = max(self.scaleRange.min + 0.1, 0.75) - self.scaleRange.max
|
||||
let scale = self.scaleRange.max + scaleRangeSize * CGFloat(self.lokiRng.next())
|
||||
positions.append(Position(center: relativePosition, scale: scale))
|
||||
positions.append(Position(distance: distance, angle: angle, scale: scale))
|
||||
|
||||
if absolutePosition.x < centerPoint.x {
|
||||
leftPositions += 1
|
||||
@ -751,15 +760,14 @@ private struct PositionGenerator {
|
||||
|
||||
let orbitRangeSize = self.outerOrbitRange.max - self.outerOrbitRange.min
|
||||
let orbitDistanceFactor = self.outerOrbitRange.min + orbitRangeSize * CGFloat(self.lokiRng.next())
|
||||
let orbitDistance = orbitDistanceFactor * centerRadius
|
||||
let distance = orbitDistanceFactor * centerRadius
|
||||
|
||||
let angleRange: CGFloat = placeOnLeftSide ? .pi : .pi
|
||||
let angleOffset: CGFloat = placeOnLeftSide ? .pi/2 : -(.pi/2)
|
||||
let angle = angleOffset + angleRange * CGFloat(self.lokiRng.next())
|
||||
|
||||
let absoluteX = centerPoint.x + orbitDistance * cos(angle)
|
||||
let absoluteY = centerPoint.y + orbitDistance * sin(angle)
|
||||
let absolutePosition = CGPoint(x: absoluteX, y: absoluteY)
|
||||
// Get the absolute position to check boundaries and collisions
|
||||
let absolutePosition = getAbsolutePosition(distance: distance, angle: angle, centerPoint: centerPoint)
|
||||
|
||||
if absolutePosition.x - itemSize.width/2 < self.edgePadding ||
|
||||
absolutePosition.x + itemSize.width/2 > self.containerSize.width - self.edgePadding ||
|
||||
@ -768,11 +776,6 @@ private struct PositionGenerator {
|
||||
continue
|
||||
}
|
||||
|
||||
let relativePosition = CGPoint(
|
||||
x: absolutePosition.x - centerPoint.x,
|
||||
y: absolutePosition.y - centerPoint.y
|
||||
)
|
||||
|
||||
let itemRect = CGRect(
|
||||
x: absolutePosition.x - itemSize.width/2,
|
||||
y: absolutePosition.y - itemSize.height/2,
|
||||
@ -780,12 +783,12 @@ private struct PositionGenerator {
|
||||
height: itemSize.height
|
||||
)
|
||||
|
||||
if self.isValidPosition(itemRect, existingPositions: positions.map { self.posToAbsolute($0.center, centerPoint: centerPoint) }, itemSize: itemSize) {
|
||||
let distance = hypot(absolutePosition.x - centerPoint.x, absolutePosition.y - centerPoint.y)
|
||||
|
||||
if self.isValidPosition(itemRect, existingPositions: positions.map {
|
||||
getAbsolutePosition(distance: $0.distance, angle: $0.angle, centerPoint: centerPoint)
|
||||
}, itemSize: itemSize) {
|
||||
let normalizedDistance = min(distance / maxPossibleDistance, 1.0)
|
||||
let scale = self.scaleRange.max - normalizedDistance * (self.scaleRange.max - self.scaleRange.min)
|
||||
positions.append(Position(center: relativePosition, scale: scale))
|
||||
positions.append(Position(distance: distance, angle: angle, scale: scale))
|
||||
|
||||
if absolutePosition.x < centerPoint.x {
|
||||
leftPositions += 1
|
||||
@ -798,8 +801,11 @@ private struct PositionGenerator {
|
||||
return positions
|
||||
}
|
||||
|
||||
private func posToAbsolute(_ relativePos: CGPoint, centerPoint: CGPoint) -> CGPoint {
|
||||
return CGPoint(x: relativePos.x + centerPoint.x, y: relativePos.y + centerPoint.y)
|
||||
func getAbsolutePosition(distance: CGFloat, angle: CGFloat, centerPoint: CGPoint) -> CGPoint {
|
||||
return CGPoint(
|
||||
x: centerPoint.x + distance * cos(angle),
|
||||
y: centerPoint.y + distance * sin(angle)
|
||||
)
|
||||
}
|
||||
|
||||
private func isValidPosition(_ rect: CGRect, existingPositions: [CGPoint], itemSize: CGSize) -> Bool {
|
||||
@ -827,6 +833,20 @@ private struct PositionGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
private func getAbsolutePosition(position: PositionGenerator.Position, centerPoint: CGPoint) -> CGPoint {
|
||||
return CGPoint(
|
||||
x: centerPoint.x + position.distance * cos(position.angle),
|
||||
y: centerPoint.y + position.distance * sin(position.angle)
|
||||
)
|
||||
}
|
||||
|
||||
private func getAbsolutePosition(distance: CGFloat, angle: CGFloat, centerPoint: CGPoint) -> CGPoint {
|
||||
return CGPoint(
|
||||
x: centerPoint.x + distance * cos(angle),
|
||||
y: centerPoint.y + distance * sin(angle)
|
||||
)
|
||||
}
|
||||
|
||||
private func windowFunction(t: CGFloat) -> CGFloat {
|
||||
return bezierPoint(0.6, 0.0, 0.4, 1.0, t)
|
||||
}
|
||||
|
@ -2352,6 +2352,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
giftsContext: profileGiftsContext,
|
||||
hasBackground: hasBackground,
|
||||
avatarCenter: apparentAvatarFrame.center,
|
||||
avatarSize: apparentAvatarFrame.size,
|
||||
defaultHeight: backgroundDefaultHeight,
|
||||
avatarTransitionFraction: max(0.0, min(1.0, titleCollapseFraction + transitionFraction * 2.0)),
|
||||
statusBarHeight: statusBarHeight,
|
||||
|
@ -165,9 +165,9 @@ private final class SheetContent: CombinedComponent {
|
||||
iconName: "Account Freeze/Appeal",
|
||||
iconColor: linkColor,
|
||||
action: {
|
||||
component.submitAppeal()
|
||||
Queue.mainQueue().after(1.0) {
|
||||
component.dismiss()
|
||||
component.dismiss()
|
||||
Queue.mainQueue().after(0.5) {
|
||||
component.submitAppeal()
|
||||
}
|
||||
}
|
||||
))
|
||||
@ -201,9 +201,9 @@ private final class SheetContent: CombinedComponent {
|
||||
isEnabled: true,
|
||||
displaysProgress: false,
|
||||
action: {
|
||||
component.submitAppeal()
|
||||
Queue.mainQueue().after(1.0) {
|
||||
component.dismiss()
|
||||
component.dismiss()
|
||||
Queue.mainQueue().after(0.5) {
|
||||
component.submitAppeal()
|
||||
}
|
||||
}
|
||||
),
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "hand_30.pdf",
|
||||
"filename" : "sandtimer_30.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "sandtimer_30.pdf",
|
||||
"filename" : "hand_30.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Chat/Message/StarsCount.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Message/StarsCount.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "msgstar.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Chat/Message/StarsCount.imageset/msgstar.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Message/StarsCount.imageset/msgstar.pdf
vendored
Normal file
Binary file not shown.
@ -266,6 +266,9 @@ public final class AccountContextImpl: AccountContext {
|
||||
|
||||
public private(set) var isPremium: Bool
|
||||
|
||||
private var isFrozenDisposable: Disposable?
|
||||
public private(set) var isFrozen: Bool
|
||||
|
||||
public let imageCache: AnyObject?
|
||||
|
||||
public init(sharedContext: SharedAccountContextImpl, account: Account, limitsConfiguration: LimitsConfiguration, contentSettings: ContentSettings, appConfiguration: AppConfiguration, availableReplyColors: EngineAvailableColorOptions, availableProfileColors: EngineAvailableColorOptions, temp: Bool = false)
|
||||
@ -280,6 +283,7 @@ public final class AccountContextImpl: AccountContext {
|
||||
self.peerNameColors = PeerNameColors.with(availableReplyColors: availableReplyColors, availableProfileColors: availableProfileColors)
|
||||
self.audioTranscriptionTrial = AudioTranscription.TrialState.defaultValue
|
||||
self.isPremium = false
|
||||
self.isFrozen = false
|
||||
|
||||
self.downloadedMediaStoreManager = DownloadedMediaStoreManagerImpl(postbox: account.postbox, accountManager: sharedContext.accountManager)
|
||||
|
||||
@ -452,6 +456,18 @@ public final class AccountContextImpl: AccountContext {
|
||||
}
|
||||
self.audioTranscriptionTrial = audioTranscriptionTrial
|
||||
})
|
||||
|
||||
self.isFrozenDisposable = (self.appConfiguration
|
||||
|> map { appConfiguration in
|
||||
return AccountFreezeConfiguration.with(appConfiguration: appConfiguration).freezeUntilDate != nil
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] isFrozen in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
self.isFrozen = isFrozen
|
||||
})
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -464,6 +480,7 @@ public final class AccountContextImpl: AccountContext {
|
||||
self.animatedEmojiStickersDisposable?.dispose()
|
||||
self.userLimitsConfigurationDisposable?.dispose()
|
||||
self.peerNameColorsConfigurationDisposable?.dispose()
|
||||
self.isFrozenDisposable?.dispose()
|
||||
}
|
||||
|
||||
public func storeSecureIdPassword(password: String) {
|
||||
|
@ -0,0 +1,32 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import ContextUI
|
||||
import UndoUI
|
||||
import AccountContext
|
||||
import ChatControllerInteraction
|
||||
import AnimatedTextComponent
|
||||
import ChatMessagePaymentAlertController
|
||||
import TelegramPresentationData
|
||||
import TelegramNotices
|
||||
|
||||
extension ChatControllerImpl {
|
||||
func presentAccountFrozenInfoIfNeeded() -> Bool {
|
||||
if self.context.isFrozen {
|
||||
let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
|
||||
if let freezeAppealUrl = accountFreezeConfiguration.freezeAppealUrl {
|
||||
let components = freezeAppealUrl.components(separatedBy: "/")
|
||||
if let username = components.last, let peer = self.presentationInterfaceState.renderedPeer?.peer, peer.addressName == username {
|
||||
return false
|
||||
}
|
||||
}
|
||||
self.push(self.context.sharedContext.makeAccountFreezeInfoScreen(context: self.context))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
@ -1865,6 +1865,12 @@ extension ChatControllerImpl {
|
||||
guard let strongSelf = self, strongSelf.isNodeLoaded else {
|
||||
return
|
||||
}
|
||||
|
||||
guard !strongSelf.presentAccountFrozenInfoIfNeeded() else {
|
||||
completion(.immediate, {})
|
||||
return
|
||||
}
|
||||
|
||||
if let messageId = messageId {
|
||||
let intrinsicCanSendMessagesHere = canSendMessagesToChat(strongSelf.presentationInterfaceState)
|
||||
var canSendMessagesHere = intrinsicCanSendMessagesHere
|
||||
@ -2114,6 +2120,11 @@ extension ChatControllerImpl {
|
||||
})
|
||||
}, deleteMessages: { [weak self] messages, contextController, completion in
|
||||
if let strongSelf = self, !messages.isEmpty {
|
||||
guard !strongSelf.presentAccountFrozenInfoIfNeeded() else {
|
||||
completion(.default)
|
||||
return
|
||||
}
|
||||
|
||||
let messageIds = Set(messages.map { $0.id })
|
||||
strongSelf.messageContextDisposable.set((strongSelf.context.sharedContext.chatAvailableMessageActions(engine: strongSelf.context.engine, accountPeerId: strongSelf.context.account.peerId, messageIds: messageIds, keepUpdated: false)
|
||||
|> deliverOnMainQueue).startStrict(next: { actions in
|
||||
@ -4416,13 +4427,10 @@ extension ChatControllerImpl {
|
||||
return
|
||||
}
|
||||
|
||||
let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
|
||||
if let _ = accountFreezeConfiguration.freezeUntilDate {
|
||||
let controller = self.context.sharedContext.makeAccountFreezeInfoScreen(context: self.context)
|
||||
self.push(controller)
|
||||
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
guard let peerId = self.chatLocation.peerId, let cachedData = self.peerView?.cachedData as? CachedChannelData, let boostToUnrestrict = cachedData.boostsToUnrestrict else {
|
||||
return
|
||||
}
|
||||
|
@ -333,6 +333,9 @@ extension ChatControllerImpl {
|
||||
}
|
||||
|
||||
controller?.dismissWithoutContent()
|
||||
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||
return
|
||||
}
|
||||
self.presentTagPremiumPaywall()
|
||||
}
|
||||
|
||||
@ -341,6 +344,11 @@ extension ChatControllerImpl {
|
||||
return
|
||||
}
|
||||
|
||||
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||
controller?.dismiss(completion: {})
|
||||
return
|
||||
}
|
||||
|
||||
guard let message = messages.first else {
|
||||
return
|
||||
}
|
||||
|
@ -3399,42 +3399,51 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
}, scheduleCurrentMessage: { [weak self] params in
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentScheduleTimePicker(completion: { [weak self] time in
|
||||
if let strongSelf = self {
|
||||
if let _ = strongSelf.presentationInterfaceState.interfaceState.mediaDraftState {
|
||||
strongSelf.sendMediaRecording(scheduleTime: time, messageEffect: (params?.effect).flatMap {
|
||||
return ChatSendMessageEffect(id: $0.id)
|
||||
})
|
||||
} else {
|
||||
let silentPosting = strongSelf.presentationInterfaceState.interfaceState.silentPosting
|
||||
strongSelf.chatDisplayNode.sendCurrentMessage(silentPosting: silentPosting, scheduleTime: time, messageEffect: (params?.effect).flatMap {
|
||||
return ChatSendMessageEffect(id: $0.id)
|
||||
}) { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, saveInterfaceState: strongSelf.presentationInterfaceState.subject != .scheduledMessages, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardOptionsState(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))) }
|
||||
})
|
||||
|
||||
if strongSelf.presentationInterfaceState.subject != .scheduledMessages && time != scheduleWhenOnlineTimestamp {
|
||||
strongSelf.openScheduledMessages()
|
||||
}
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||
return
|
||||
}
|
||||
self.presentScheduleTimePicker(completion: { [weak self] time in
|
||||
if let strongSelf = self {
|
||||
if let _ = strongSelf.presentationInterfaceState.interfaceState.mediaDraftState {
|
||||
strongSelf.sendMediaRecording(scheduleTime: time, messageEffect: (params?.effect).flatMap {
|
||||
return ChatSendMessageEffect(id: $0.id)
|
||||
})
|
||||
} else {
|
||||
let silentPosting = strongSelf.presentationInterfaceState.interfaceState.silentPosting
|
||||
strongSelf.chatDisplayNode.sendCurrentMessage(silentPosting: silentPosting, scheduleTime: time, messageEffect: (params?.effect).flatMap {
|
||||
return ChatSendMessageEffect(id: $0.id)
|
||||
}) { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, saveInterfaceState: strongSelf.presentationInterfaceState.subject != .scheduledMessages, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardOptionsState(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))) }
|
||||
})
|
||||
|
||||
if strongSelf.presentationInterfaceState.subject != .scheduledMessages && time != scheduleWhenOnlineTimestamp {
|
||||
strongSelf.openScheduledMessages()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}, sendScheduledMessagesNow: { [weak self] messageIds in
|
||||
if let strongSelf = self {
|
||||
if let _ = strongSelf.presentationInterfaceState.slowmodeState {
|
||||
if let rect = strongSelf.chatDisplayNode.frameForInputActionButton() {
|
||||
strongSelf.interfaceInteraction?.displaySlowmodeTooltip(strongSelf.chatDisplayNode.view, rect)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
let _ = strongSelf.context.engine.messages.sendScheduledMessageNowInteractively(messageId: messageIds.first!).startStandalone()
|
||||
}
|
||||
})
|
||||
}, sendScheduledMessagesNow: { [weak self] messageIds in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||
return
|
||||
}
|
||||
|
||||
if let _ = self.presentationInterfaceState.slowmodeState {
|
||||
if let rect = self.chatDisplayNode.frameForInputActionButton() {
|
||||
self.interfaceInteraction?.displaySlowmodeTooltip(self.chatDisplayNode.view, rect)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
let _ = self.context.engine.messages.sendScheduledMessageNowInteractively(messageId: messageIds.first!).startStandalone()
|
||||
}
|
||||
}, editScheduledMessagesTime: { [weak self] messageIds in
|
||||
if let strongSelf = self, let messageId = messageIds.first {
|
||||
|
@ -21,15 +21,24 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
|
||||
return (nil, nil)
|
||||
}
|
||||
|
||||
let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||
if let _ = accountFreezeConfiguration.freezeUntilDate {
|
||||
if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) {
|
||||
return (currentPanel, nil)
|
||||
} else {
|
||||
let panel = ChatRestrictedInputPanelNode()
|
||||
panel.context = context
|
||||
panel.interfaceInteraction = interfaceInteraction
|
||||
return (panel, nil)
|
||||
if context.isFrozen {
|
||||
var isActuallyFrozen = true
|
||||
let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||
if let freezeAppealUrl = accountFreezeConfiguration.freezeAppealUrl {
|
||||
let components = freezeAppealUrl.components(separatedBy: "/")
|
||||
if let username = components.last, let peer = chatPresentationInterfaceState.renderedPeer?.peer, peer.addressName == username {
|
||||
isActuallyFrozen = false
|
||||
}
|
||||
}
|
||||
if isActuallyFrozen {
|
||||
if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) {
|
||||
return (currentPanel, nil)
|
||||
} else {
|
||||
let panel = ChatRestrictedInputPanelNode()
|
||||
panel.context = context
|
||||
panel.interfaceInteraction = interfaceInteraction
|
||||
return (panel, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -644,7 +644,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
||||
return self.actionButtons.micButton
|
||||
}
|
||||
|
||||
private let startingBotDisposable = MetaDisposable()
|
||||
private let statusDisposable = MetaDisposable()
|
||||
override var interfaceInteraction: ChatPanelInterfaceInteraction? {
|
||||
didSet {
|
||||
@ -655,28 +654,9 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
||||
self?.updateIsProcessingInlineRequest(value)
|
||||
}).strict())
|
||||
}
|
||||
if let startingBot = self.interfaceInteraction?.statuses?.startingBot {
|
||||
self.startingBotDisposable.set((startingBot |> deliverOnMainQueue).startStrict(next: { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.startingBotProgress = value
|
||||
}
|
||||
}).strict())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var startingBotProgress = false {
|
||||
didSet {
|
||||
// if self.startingBotProgress != oldValue {
|
||||
// if self.startingBotProgress {
|
||||
// self.startButton.transitionToProgress()
|
||||
// } else {
|
||||
// self.startButton.transitionFromProgress()
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func updateInputTextState(_ state: ChatTextInputState, keepSendButtonEnabled: Bool, extendedSearchLayout: Bool, accessoryItems: [ChatTextInputAccessoryItem], animated: Bool) {
|
||||
if let currentState = self.presentationInterfaceState {
|
||||
var updateAccessoryButtons = false
|
||||
@ -1130,7 +1110,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
||||
|
||||
deinit {
|
||||
self.statusDisposable.dispose()
|
||||
self.startingBotDisposable.dispose()
|
||||
self.tooltipController?.dismiss()
|
||||
self.currentEmojiSuggestion?.disposable.dispose()
|
||||
}
|
||||
|
@ -2451,6 +2451,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
mappedSource = .animatedEmoji
|
||||
case .paidMessages:
|
||||
mappedSource = .paidMessages
|
||||
case let .auth(price):
|
||||
mappedSource = .auth(price)
|
||||
}
|
||||
return mappedSource
|
||||
}
|
||||
@ -2465,13 +2467,13 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
return controller
|
||||
}
|
||||
|
||||
public func makePremiumIntroController(sharedContext: SharedAccountContext, engine: TelegramEngineUnauthorized, inAppPurchaseManager: InAppPurchaseManager, source: PremiumIntroSource, dismissed: (() -> Void)?) -> ViewController {
|
||||
public func makePremiumIntroController(sharedContext: SharedAccountContext, engine: TelegramEngineUnauthorized, inAppPurchaseManager: InAppPurchaseManager, source: PremiumIntroSource, proceed: (() -> Void)?) -> ViewController {
|
||||
var modal = true
|
||||
if case .settings = source {
|
||||
modal = false
|
||||
}
|
||||
let controller = PremiumIntroScreen(screenContext: .sharedContext(sharedContext, engine, inAppPurchaseManager), source: self.mapIntroSource(source: source), modal: modal)
|
||||
controller.wasDismissed = dismissed
|
||||
controller.customProceed = proceed
|
||||
return controller
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user