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
@ -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.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 >]()";
|
"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 makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?, temporary: Bool) -> ViewController
|
||||||
|
|
||||||
func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool, dismissed: (() -> Void)?) -> 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 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
|
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 availableMessageEffects: Signal<AvailableMessageEffects?, NoError> { get }
|
||||||
|
|
||||||
var isPremium: Bool { get }
|
var isPremium: Bool { get }
|
||||||
|
var isFrozen: Bool { get }
|
||||||
var userLimits: EngineConfiguration.UserLimits { get }
|
var userLimits: EngineConfiguration.UserLimits { get }
|
||||||
var peerNameColors: PeerNameColors { get }
|
var peerNameColors: PeerNameColors { get }
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ public enum PremiumIntroSource {
|
|||||||
case animatedEmoji
|
case animatedEmoji
|
||||||
case messageEffects
|
case messageEffects
|
||||||
case paidMessages
|
case paidMessages
|
||||||
|
case auth(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PremiumGiftSource: Equatable {
|
public enum PremiumGiftSource: Equatable {
|
||||||
|
@ -251,15 +251,17 @@ final class AuthorizationSequencePaymentScreenComponent: Component {
|
|||||||
iconName: "Premium/Authorization/Support",
|
iconName: "Premium/Authorization/Support",
|
||||||
iconColor: linkColor,
|
iconColor: linkColor,
|
||||||
action: { [weak self] in
|
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
|
return
|
||||||
}
|
}
|
||||||
let introController = component.sharedContext.makePremiumIntroController(
|
let introController = component.sharedContext.makePremiumIntroController(
|
||||||
sharedContext: component.sharedContext,
|
sharedContext: component.sharedContext,
|
||||||
engine: component.engine,
|
engine: component.engine,
|
||||||
inAppPurchaseManager: component.inAppPurchaseManager,
|
inAppPurchaseManager: component.inAppPurchaseManager,
|
||||||
source: .about,
|
source: .auth(product.price),
|
||||||
dismissed: nil
|
proceed: { [weak self] in
|
||||||
|
self?.proceed()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
controller.push(introController)
|
controller.push(introController)
|
||||||
}
|
}
|
||||||
@ -274,11 +276,13 @@ final class AuthorizationSequencePaymentScreenComponent: Component {
|
|||||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: availableSize.height)
|
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 titleSpacing: CGFloat = -24.0
|
||||||
let listSpacing: CGFloat = 12.0
|
let listSpacing: CGFloat = 12.0
|
||||||
let totalHeight = animationSize.height + titleSpacing + titleSize.height + listSpacing + listSize.height
|
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 let animationView = self.animation.view {
|
||||||
if animationView.superview == nil {
|
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)
|
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 bottomInset: CGFloat = environment.safeInsets.bottom > 0.0 ? environment.safeInsets.bottom + 5.0 : bottomPanelPadding
|
||||||
let bottomPanelHeight = bottomPanelPadding + buttonHeight + bottomInset
|
let bottomPanelHeight = bottomPanelPadding + buttonHeight + bottomInset
|
||||||
|
|
||||||
@ -329,7 +331,7 @@ final class AuthorizationSequencePaymentScreenComponent: Component {
|
|||||||
component: AnyComponent(
|
component: AnyComponent(
|
||||||
VStack([
|
VStack([
|
||||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))),
|
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)
|
], spacing: 1.0)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
@ -410,6 +412,10 @@ public final class AuthorizationSequencePaymentScreen: ViewControllerComponentCo
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override public func viewWillAppear(_ animated: Bool) {
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
}
|
||||||
|
|
||||||
@objc private func cancelPressed() {
|
@objc private func cancelPressed() {
|
||||||
self.dismiss()
|
self.dismiss()
|
||||||
}
|
}
|
||||||
|
@ -2794,6 +2794,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
|
|
||||||
private weak var storyCameraTooltip: TooltipScreen?
|
private weak var storyCameraTooltip: TooltipScreen?
|
||||||
fileprivate func openStoryCamera(fromList: Bool) {
|
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 reachedCountLimit = false
|
||||||
var premiumNeeded = false
|
var premiumNeeded = false
|
||||||
var hasActiveCall = false
|
var hasActiveCall = false
|
||||||
@ -4641,6 +4647,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc fileprivate func composePressed() {
|
@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 {
|
guard let navigationController = self.navigationController as? NavigationController else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ public final class SolidRoundedButtonComponent: Component {
|
|||||||
public typealias Theme = SolidRoundedButtonTheme
|
public typealias Theme = SolidRoundedButtonTheme
|
||||||
|
|
||||||
public let title: String?
|
public let title: String?
|
||||||
|
public let subtitle: String?
|
||||||
public let label: String?
|
public let label: String?
|
||||||
public let badge: String?
|
public let badge: String?
|
||||||
public let icon: UIImage?
|
public let icon: UIImage?
|
||||||
@ -28,6 +29,7 @@ public final class SolidRoundedButtonComponent: Component {
|
|||||||
|
|
||||||
public init(
|
public init(
|
||||||
title: String? = nil,
|
title: String? = nil,
|
||||||
|
subtitle: String? = nil,
|
||||||
label: String? = nil,
|
label: String? = nil,
|
||||||
badge: String? = nil,
|
badge: String? = nil,
|
||||||
icon: UIImage? = nil,
|
icon: UIImage? = nil,
|
||||||
@ -46,6 +48,7 @@ public final class SolidRoundedButtonComponent: Component {
|
|||||||
action: @escaping () -> Void
|
action: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
self.title = title
|
self.title = title
|
||||||
|
self.subtitle = subtitle
|
||||||
self.label = label
|
self.label = label
|
||||||
self.badge = badge
|
self.badge = badge
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
@ -68,6 +71,9 @@ public final class SolidRoundedButtonComponent: Component {
|
|||||||
if lhs.title != rhs.title {
|
if lhs.title != rhs.title {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.subtitle != rhs.subtitle {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.label != rhs.label {
|
if lhs.label != rhs.label {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -147,6 +153,7 @@ public final class SolidRoundedButtonComponent: Component {
|
|||||||
|
|
||||||
if let button = self.button {
|
if let button = self.button {
|
||||||
button.title = component.title
|
button.title = component.title
|
||||||
|
button.subtitle = component.subtitle
|
||||||
button.label = component.label
|
button.label = component.label
|
||||||
button.badge = component.badge
|
button.badge = component.badge
|
||||||
button.iconPosition = component.iconPosition
|
button.iconPosition = component.iconPosition
|
||||||
|
@ -242,6 +242,7 @@ open class ViewControllerComponentContainer: ViewController {
|
|||||||
public private(set) var validLayout: ContainerViewLayout?
|
public private(set) var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
public var wasDismissed: (() -> Void)?
|
public var wasDismissed: (() -> Void)?
|
||||||
|
public var customProceed: (() -> Void)?
|
||||||
|
|
||||||
public init<C: Component>(
|
public init<C: Component>(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
|
@ -67,9 +67,7 @@
|
|||||||
- (SSignal *)coverImageSignalForItem:(NSObject<TGMediaEditableItem> *)item;
|
- (SSignal *)coverImageSignalForItem:(NSObject<TGMediaEditableItem> *)item;
|
||||||
- (void)setCoverImage:(UIImage *)image position:(NSNumber *)position forItem:(id<TGMediaEditableItem>)item;
|
- (void)setCoverImage:(UIImage *)image position:(NSNumber *)position forItem:(id<TGMediaEditableItem>)item;
|
||||||
- (UIImage *)coverImageForItem:(NSObject<TGMediaEditableItem> *)item;
|
- (UIImage *)coverImageForItem:(NSObject<TGMediaEditableItem> *)item;
|
||||||
|
|
||||||
- (NSNumber *)coverPositionForItem:(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;
|
- (void)setTemporaryRep:(id)rep forItem:(id<TGMediaEditableItem>)item;
|
||||||
|
|
||||||
|
@ -309,6 +309,12 @@ public enum PremiumSource: Equatable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
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 folderTags
|
||||||
case messageEffects
|
case messageEffects
|
||||||
case paidMessages
|
case paidMessages
|
||||||
|
case auth(String)
|
||||||
|
|
||||||
var identifier: String? {
|
var identifier: String? {
|
||||||
switch self {
|
switch self {
|
||||||
@ -452,6 +459,8 @@ public enum PremiumSource: Equatable {
|
|||||||
return "effects"
|
return "effects"
|
||||||
case .paidMessages:
|
case .paidMessages:
|
||||||
return "paid_messages"
|
return "paid_messages"
|
||||||
|
case .auth:
|
||||||
|
return "auth"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1214,6 +1223,7 @@ final class PerkComponent: CombinedComponent {
|
|||||||
let subtitleColor: UIColor
|
let subtitleColor: UIColor
|
||||||
let arrowColor: UIColor
|
let arrowColor: UIColor
|
||||||
let accentColor: UIColor
|
let accentColor: UIColor
|
||||||
|
let displayArrow: Bool
|
||||||
let badge: String?
|
let badge: String?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
@ -1225,6 +1235,7 @@ final class PerkComponent: CombinedComponent {
|
|||||||
subtitleColor: UIColor,
|
subtitleColor: UIColor,
|
||||||
arrowColor: UIColor,
|
arrowColor: UIColor,
|
||||||
accentColor: UIColor,
|
accentColor: UIColor,
|
||||||
|
displayArrow: Bool = true,
|
||||||
badge: String? = nil
|
badge: String? = nil
|
||||||
) {
|
) {
|
||||||
self.iconName = iconName
|
self.iconName = iconName
|
||||||
@ -1235,6 +1246,7 @@ final class PerkComponent: CombinedComponent {
|
|||||||
self.subtitleColor = subtitleColor
|
self.subtitleColor = subtitleColor
|
||||||
self.arrowColor = arrowColor
|
self.arrowColor = arrowColor
|
||||||
self.accentColor = accentColor
|
self.accentColor = accentColor
|
||||||
|
self.displayArrow = displayArrow
|
||||||
self.badge = badge
|
self.badge = badge
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1263,6 +1275,9 @@ final class PerkComponent: CombinedComponent {
|
|||||||
if lhs.accentColor != rhs.accentColor {
|
if lhs.accentColor != rhs.accentColor {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.displayArrow != rhs.displayArrow {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.badge != rhs.badge {
|
if lhs.badge != rhs.badge {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -1306,15 +1321,6 @@ final class PerkComponent: CombinedComponent {
|
|||||||
transition: context.transition
|
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(
|
let title = title.update(
|
||||||
component: MultilineTextComponent(
|
component: MultilineTextComponent(
|
||||||
text: .plain(
|
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)
|
let size = CGSize(width: context.availableSize.width, height: textTopInset + title.size.height + spacing + subtitle.size.height + textBottomInset)
|
||||||
|
|
||||||
|
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
|
context.add(arrow
|
||||||
.position(CGPoint(x: context.availableSize.width - 7.0 - arrow.size.width / 2.0, y: size.height / 2.0))
|
.position(CGPoint(x: context.availableSize.width - 7.0 - arrow.size.width / 2.0, y: size.height / 2.0))
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
@ -2086,6 +2103,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
|||||||
foregroundColor: .white,
|
foregroundColor: .white,
|
||||||
iconName: perk.iconName
|
iconName: perk.iconName
|
||||||
))), false),
|
))), false),
|
||||||
|
accessory: accountContext != nil ? .arrow : nil,
|
||||||
action: { [weak state] _ in
|
action: { [weak state] _ in
|
||||||
guard let accountContext else {
|
guard let accountContext else {
|
||||||
return
|
return
|
||||||
@ -2162,7 +2180,8 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
|||||||
updateIsFocused(true)
|
updateIsFocused(true)
|
||||||
|
|
||||||
addAppLogEvent(postbox: accountContext.account.postbox, type: "premium.promo_screen_tap", data: ["item": perk.identifier])
|
addAppLogEvent(postbox: accountContext.account.postbox, type: "premium.promo_screen_tap", data: ["item": perk.identifier])
|
||||||
}
|
},
|
||||||
|
highlighting: accountContext != nil ? .default : .disabled
|
||||||
))))
|
))))
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
@ -3660,7 +3679,11 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||||||
|
|
||||||
if !buttonIsHidden {
|
if !buttonIsHidden {
|
||||||
let buttonTitle: String
|
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
|
buttonTitle = environment.strings.Premium_Gift_ApplyLink
|
||||||
} else if state.isPremium == true && state.canUpgrade {
|
} else if state.isPremium == true && state.canUpgrade {
|
||||||
buttonTitle = state.isAnnual ? environment.strings.Premium_UpgradeForAnnual(state.price ?? "—").string : environment.strings.Premium_UpgradeFor(state.price ?? "—").string
|
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
|
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 sideInset: CGFloat = 16.0
|
||||||
let button = button.update(
|
let button = button.update(
|
||||||
component: SolidRoundedButtonComponent(
|
component: SolidRoundedButtonComponent(
|
||||||
title: buttonTitle,
|
title: buttonTitle,
|
||||||
|
subtitle: buttonSubtitle,
|
||||||
theme: SolidRoundedButtonComponent.Theme(
|
theme: SolidRoundedButtonComponent.Theme(
|
||||||
backgroundColor: UIColor(rgb: 0x8878ff),
|
backgroundColor: UIColor(rgb: 0x8878ff),
|
||||||
backgroundColors: [
|
backgroundColors: [
|
||||||
@ -3687,8 +3712,13 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||||||
gloss: true,
|
gloss: true,
|
||||||
isLoading: state.inProgress,
|
isLoading: state.inProgress,
|
||||||
action: {
|
action: {
|
||||||
|
if let controller = controller() as? PremiumIntroScreen, let customProceed = controller.customProceed {
|
||||||
|
controller.dismiss()
|
||||||
|
customProceed()
|
||||||
|
} else {
|
||||||
state.buy()
|
state.buy()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
),
|
),
|
||||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - environment.safeInsets.left - environment.safeInsets.right, height: 50.0),
|
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - environment.safeInsets.left - environment.safeInsets.right, height: 50.0),
|
||||||
transition: context.transition)
|
transition: context.transition)
|
||||||
|
@ -315,7 +315,7 @@ private func selectivePrivacyPeersControllerEntries(presentationData: Presentati
|
|||||||
entries.append(.footerItem(footer))
|
entries.append(.footerItem(footer))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !peers.isEmpty {
|
if !peers.isEmpty || state.enableForPremium || state.enableForBots {
|
||||||
entries.append(.deleteItem(presentationData.strings.Privacy_Exceptions_DeleteAllExceptions))
|
entries.append(.deleteItem(presentationData.strings.Privacy_Exceptions_DeleteAllExceptions))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1412,7 +1412,7 @@ public final class SolidRoundedButtonView: UIView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.titleNode.attributedText = titleText
|
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)
|
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 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 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 iconSpacing: CGFloat = self.iconSpacing
|
||||||
let badgeSpacing: CGFloat = 6.0
|
let badgeSpacing: CGFloat = 6.0
|
||||||
@ -1533,11 +1533,11 @@ public final class SolidRoundedButtonView: UIView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.subtitle != self.subtitleNode.attributedText?.string {
|
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 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)
|
transition.updateFrame(view: self.subtitleNode, frame: subtitleFrame)
|
||||||
|
|
||||||
if previousSubtitle == nil && self.subtitle != nil {
|
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[-1281329567] = { return Api.MessageAction.parse_messageActionGroupCallScheduled($0) }
|
||||||
dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) }
|
dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) }
|
||||||
dict[1345295095] = { return Api.MessageAction.parse_messageActionInviteToGroupCall($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[1102307842] = { return Api.MessageAction.parse_messageActionPaymentRefunded($0) }
|
||||||
dict[-970673810] = { return Api.MessageAction.parse_messageActionPaymentSent($0) }
|
dict[-970673810] = { return Api.MessageAction.parse_messageActionPaymentSent($0) }
|
||||||
dict[-6288180] = { return Api.MessageAction.parse_messageActionPaymentSentMe($0) }
|
dict[-6288180] = { return Api.MessageAction.parse_messageActionPaymentSentMe($0) }
|
||||||
|
@ -363,6 +363,8 @@ public extension Api {
|
|||||||
case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32)
|
case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32)
|
||||||
case messageActionHistoryClear
|
case messageActionHistoryClear
|
||||||
case messageActionInviteToGroupCall(call: Api.InputGroupCall, users: [Int64])
|
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 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 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?)
|
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)
|
serializeInt64(item, buffer: buffer, boxed: false)
|
||||||
}
|
}
|
||||||
break
|
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):
|
case .messageActionPaymentRefunded(let flags, let peer, let currency, let totalAmount, let payload, let charge):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(1102307842)
|
buffer.appendInt32(1102307842)
|
||||||
@ -847,6 +862,10 @@ public extension Api {
|
|||||||
return ("messageActionHistoryClear", [])
|
return ("messageActionHistoryClear", [])
|
||||||
case .messageActionInviteToGroupCall(let call, let users):
|
case .messageActionInviteToGroupCall(let call, let users):
|
||||||
return ("messageActionInviteToGroupCall", [("call", call as Any), ("users", users as Any)])
|
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):
|
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)])
|
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):
|
case .messageActionPaymentSent(let flags, let currency, let totalAmount, let invoiceSlug, let subscriptionUntilDate):
|
||||||
@ -1277,6 +1296,31 @@ public extension Api {
|
|||||||
return nil
|
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? {
|
public static func parse_messageActionPaymentRefunded(_ reader: BufferReader) -> MessageAction? {
|
||||||
var _1: Int32?
|
var _1: Int32?
|
||||||
_1 = reader.readInt32()
|
_1 = reader.readInt32()
|
||||||
|
@ -227,7 +227,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch action {
|
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
|
break
|
||||||
case let .messageActionChannelMigrateFrom(_, chatId):
|
case let .messageActionChannelMigrateFrom(_, chatId):
|
||||||
result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(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 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))
|
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 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 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 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) {
|
public init(decoder: PostboxDecoder) {
|
||||||
let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0)
|
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"))
|
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:
|
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"))
|
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:
|
default:
|
||||||
self = .unknown
|
self = .unknown
|
||||||
}
|
}
|
||||||
@ -626,6 +632,13 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
|||||||
} else {
|
} else {
|
||||||
encoder.encodeNil(forKey: "savedId")
|
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([])
|
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 {
|
} else {
|
||||||
return .single([])
|
return .single([])
|
||||||
}
|
}
|
||||||
|
@ -170,6 +170,12 @@ public final class PrincipalThemeEssentialGraphics {
|
|||||||
public let outgoingDateAndStatusRepliesIcon: UIImage
|
public let outgoingDateAndStatusRepliesIcon: UIImage
|
||||||
public let mediaRepliesIcon: UIImage
|
public let mediaRepliesIcon: UIImage
|
||||||
public let freeRepliesIcon: 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 incomingDateAndStatusPinnedIcon: UIImage
|
||||||
public let outgoingDateAndStatusPinnedIcon: UIImage
|
public let outgoingDateAndStatusPinnedIcon: UIImage
|
||||||
public let mediaPinnedIcon: UIImage
|
public let mediaPinnedIcon: UIImage
|
||||||
@ -358,6 +364,12 @@ public final class PrincipalThemeEssentialGraphics {
|
|||||||
self.mediaRepliesIcon = generateTintedImage(image: repliesImage, color: .white)!
|
self.mediaRepliesIcon = generateTintedImage(image: repliesImage, color: .white)!
|
||||||
self.freeRepliesIcon = generateTintedImage(image: repliesImage, color: serviceColor.primaryText)!
|
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")!
|
let pinnedImage = UIImage(bundleImageName: "Chat/Message/Pinned")!
|
||||||
self.incomingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.incoming.secondaryTextColor)!
|
self.incomingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.incoming.secondaryTextColor)!
|
||||||
self.outgoingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.outgoing.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.mediaRepliesIcon = generateTintedImage(image: repliesImage, color: .white)!
|
||||||
self.freeRepliesIcon = generateTintedImage(image: repliesImage, color: serviceColor.primaryText)!
|
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")!
|
let pinnedImage = UIImage(bundleImageName: "Chat/Message/Pinned")!
|
||||||
self.incomingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.incoming.secondaryTextColor)!
|
self.incomingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.incoming.secondaryTextColor)!
|
||||||
self.outgoingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.outgoing.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:
|
case .unknown:
|
||||||
attributedString = nil
|
attributedString = nil
|
||||||
}
|
}
|
||||||
|
@ -413,7 +413,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
|||||||
repliesImage = graphics.incomingDateAndStatusPinnedIcon
|
repliesImage = graphics.incomingDateAndStatusPinnedIcon
|
||||||
}
|
}
|
||||||
if (arguments.starsCount ?? 0) != 0 {
|
if (arguments.starsCount ?? 0) != 0 {
|
||||||
starsImage = graphics.incomingDateAndStatusRepliesIcon
|
starsImage = graphics.incomingDateAndStatusStarsIcon
|
||||||
}
|
}
|
||||||
case let .BubbleOutgoing(status):
|
case let .BubbleOutgoing(status):
|
||||||
dateColor = arguments.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor
|
dateColor = arguments.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor
|
||||||
@ -432,7 +432,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
|||||||
repliesImage = graphics.outgoingDateAndStatusPinnedIcon
|
repliesImage = graphics.outgoingDateAndStatusPinnedIcon
|
||||||
}
|
}
|
||||||
if (arguments.starsCount ?? 0) != 0 {
|
if (arguments.starsCount ?? 0) != 0 {
|
||||||
starsImage = graphics.outgoingDateAndStatusRepliesIcon
|
starsImage = graphics.outgoingDateAndStatusStarsIcon
|
||||||
}
|
}
|
||||||
case .ImageIncoming:
|
case .ImageIncoming:
|
||||||
dateColor = arguments.presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor
|
dateColor = arguments.presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor
|
||||||
@ -451,7 +451,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
|||||||
repliesImage = graphics.mediaPinnedIcon
|
repliesImage = graphics.mediaPinnedIcon
|
||||||
}
|
}
|
||||||
if (arguments.starsCount ?? 0) != 0 {
|
if (arguments.starsCount ?? 0) != 0 {
|
||||||
starsImage = graphics.mediaRepliesIcon
|
starsImage = graphics.mediaStarsIcon
|
||||||
}
|
}
|
||||||
case let .ImageOutgoing(status):
|
case let .ImageOutgoing(status):
|
||||||
dateColor = arguments.presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor
|
dateColor = arguments.presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor
|
||||||
@ -471,7 +471,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
|||||||
repliesImage = graphics.mediaPinnedIcon
|
repliesImage = graphics.mediaPinnedIcon
|
||||||
}
|
}
|
||||||
if (arguments.starsCount ?? 0) != 0 {
|
if (arguments.starsCount ?? 0) != 0 {
|
||||||
starsImage = graphics.mediaRepliesIcon
|
starsImage = graphics.mediaStarsIcon
|
||||||
}
|
}
|
||||||
case .FreeIncoming:
|
case .FreeIncoming:
|
||||||
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
|
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
|
||||||
@ -492,7 +492,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
|||||||
repliesImage = graphics.freePinnedIcon
|
repliesImage = graphics.freePinnedIcon
|
||||||
}
|
}
|
||||||
if (arguments.starsCount ?? 0) != 0 {
|
if (arguments.starsCount ?? 0) != 0 {
|
||||||
starsImage = graphics.freeRepliesIcon
|
starsImage = graphics.freeStarsIcon
|
||||||
}
|
}
|
||||||
case let .FreeOutgoing(status):
|
case let .FreeOutgoing(status):
|
||||||
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
|
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
|
||||||
@ -513,7 +513,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
|||||||
repliesImage = graphics.freePinnedIcon
|
repliesImage = graphics.freePinnedIcon
|
||||||
}
|
}
|
||||||
if (arguments.starsCount ?? 0) != 0 {
|
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 baseItemDistance: CGFloat = baseDistance + CGFloat(row) * baseRowDistance
|
||||||
|
|
||||||
let itemDistanceFraction = max(0.0, min(1.0, baseItemDistance / (baseDistance * 2.0)))
|
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
|
let itemDistance = baseItemDistance * (1.0 - itemScaleFraction) + 20.0 * itemScaleFraction
|
||||||
|
|
||||||
var itemAngle: CGFloat
|
var itemAngle: CGFloat
|
||||||
|
@ -19,6 +19,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
|||||||
public let giftsContext: ProfileGiftsContext
|
public let giftsContext: ProfileGiftsContext
|
||||||
public let hasBackground: Bool
|
public let hasBackground: Bool
|
||||||
public let avatarCenter: CGPoint
|
public let avatarCenter: CGPoint
|
||||||
|
public let avatarSize: CGSize
|
||||||
public let defaultHeight: CGFloat
|
public let defaultHeight: CGFloat
|
||||||
public let avatarTransitionFraction: CGFloat
|
public let avatarTransitionFraction: CGFloat
|
||||||
public let statusBarHeight: CGFloat
|
public let statusBarHeight: CGFloat
|
||||||
@ -34,6 +35,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
|||||||
giftsContext: ProfileGiftsContext,
|
giftsContext: ProfileGiftsContext,
|
||||||
hasBackground: Bool,
|
hasBackground: Bool,
|
||||||
avatarCenter: CGPoint,
|
avatarCenter: CGPoint,
|
||||||
|
avatarSize: CGSize,
|
||||||
defaultHeight: CGFloat,
|
defaultHeight: CGFloat,
|
||||||
avatarTransitionFraction: CGFloat,
|
avatarTransitionFraction: CGFloat,
|
||||||
statusBarHeight: CGFloat,
|
statusBarHeight: CGFloat,
|
||||||
@ -48,6 +50,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
|||||||
self.giftsContext = giftsContext
|
self.giftsContext = giftsContext
|
||||||
self.hasBackground = hasBackground
|
self.hasBackground = hasBackground
|
||||||
self.avatarCenter = avatarCenter
|
self.avatarCenter = avatarCenter
|
||||||
|
self.avatarSize = avatarSize
|
||||||
self.defaultHeight = defaultHeight
|
self.defaultHeight = defaultHeight
|
||||||
self.avatarTransitionFraction = avatarTransitionFraction
|
self.avatarTransitionFraction = avatarTransitionFraction
|
||||||
self.statusBarHeight = statusBarHeight
|
self.statusBarHeight = statusBarHeight
|
||||||
@ -71,6 +74,9 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
|||||||
if lhs.avatarCenter != rhs.avatarCenter {
|
if lhs.avatarCenter != rhs.avatarCenter {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.avatarSize != rhs.avatarSize {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.defaultHeight != rhs.defaultHeight {
|
if lhs.defaultHeight != rhs.defaultHeight {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -298,26 +304,25 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
|||||||
}
|
}
|
||||||
iconLayer.glowing = component.hasBackground
|
iconLayer.glowing = component.hasBackground
|
||||||
|
|
||||||
let centerPosition = component.avatarCenter
|
let itemDistanceFraction = max(0.0, min(1.0, iconPosition.distance / 100.0))
|
||||||
let finalPosition = iconPosition.center.offsetBy(dx: component.avatarCenter.x, dy: component.avatarCenter.y)
|
let itemScaleFraction = patternScaleValueAt(fraction: min(1.0, component.avatarTransitionFraction * 1.56), t: itemDistanceFraction, reverse: false)
|
||||||
let itemScaleFraction = patternScaleValueAt(fraction: component.avatarTransitionFraction, t: 0.0, 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 clampedT = max(0, min(1, t))
|
||||||
|
|
||||||
let interpolatedX = from.x + (to.x - from.x) * clampedT
|
let interpolatedDistance = from.distance + (to.distance - from.distance) * clampedT
|
||||||
let interpolatedY = from.y + (to.y - from.y) * clampedT
|
let interpolatedAngle = from.angle + (to.angle - from.angle) * clampedT
|
||||||
|
|
||||||
return CGPoint(
|
return PositionGenerator.Position(distance: interpolatedDistance, angle: interpolatedAngle, scale: from.scale)
|
||||||
x: interpolatedX,
|
|
||||||
y: interpolatedY
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.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.setScale(layer: iconLayer, scale: iconPosition.scale * (1.0 - itemScaleFraction))
|
||||||
iconTransition.setAlpha(layer: iconLayer, alpha: 1.0 - itemScaleFraction)
|
iconTransition.setAlpha(layer: iconLayer, alpha: 1.0 - itemScaleFraction)
|
||||||
|
|
||||||
@ -638,8 +643,16 @@ private class GiftIconLayer: SimpleLayer {
|
|||||||
|
|
||||||
private struct PositionGenerator {
|
private struct PositionGenerator {
|
||||||
struct Position {
|
struct Position {
|
||||||
let center: CGPoint
|
let distance: CGFloat
|
||||||
|
let angle: CGFloat
|
||||||
let scale: CGFloat
|
let scale: CGFloat
|
||||||
|
|
||||||
|
var relativeCartesian: CGPoint {
|
||||||
|
return CGPoint(
|
||||||
|
x: self.distance * cos(self.angle),
|
||||||
|
y: self.distance * sin(self.angle)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let containerSize: CGSize
|
let containerSize: CGSize
|
||||||
@ -700,15 +713,14 @@ private struct PositionGenerator {
|
|||||||
|
|
||||||
let orbitRangeSize = self.innerOrbitRange.max - self.innerOrbitRange.min
|
let orbitRangeSize = self.innerOrbitRange.max - self.innerOrbitRange.min
|
||||||
let orbitDistanceFactor = self.innerOrbitRange.min + orbitRangeSize * CGFloat(self.lokiRng.next())
|
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 angleRange: CGFloat = placeOnLeftSide ? .pi : .pi
|
||||||
let angleOffset: CGFloat = placeOnLeftSide ? .pi/2 : -(.pi/2)
|
let angleOffset: CGFloat = placeOnLeftSide ? .pi/2 : -(.pi/2)
|
||||||
let angle = angleOffset + angleRange * CGFloat(self.lokiRng.next())
|
let angle = angleOffset + angleRange * CGFloat(self.lokiRng.next())
|
||||||
|
|
||||||
let absoluteX = centerPoint.x + orbitDistance * cos(angle)
|
// Get the absolute position to check boundaries and collisions
|
||||||
let absoluteY = centerPoint.y + orbitDistance * sin(angle)
|
let absolutePosition = getAbsolutePosition(distance: distance, angle: angle, centerPoint: centerPoint)
|
||||||
let absolutePosition = CGPoint(x: absoluteX, y: absoluteY)
|
|
||||||
|
|
||||||
if absolutePosition.x - itemSize.width/2 < self.edgePadding ||
|
if absolutePosition.x - itemSize.width/2 < self.edgePadding ||
|
||||||
absolutePosition.x + itemSize.width/2 > self.containerSize.width - self.edgePadding ||
|
absolutePosition.x + itemSize.width/2 > self.containerSize.width - self.edgePadding ||
|
||||||
@ -717,11 +729,6 @@ private struct PositionGenerator {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let relativePosition = CGPoint(
|
|
||||||
x: absolutePosition.x - centerPoint.x,
|
|
||||||
y: absolutePosition.y - centerPoint.y
|
|
||||||
)
|
|
||||||
|
|
||||||
let itemRect = CGRect(
|
let itemRect = CGRect(
|
||||||
x: absolutePosition.x - itemSize.width/2,
|
x: absolutePosition.x - itemSize.width/2,
|
||||||
y: absolutePosition.y - itemSize.height/2,
|
y: absolutePosition.y - itemSize.height/2,
|
||||||
@ -729,10 +736,12 @@ private struct PositionGenerator {
|
|||||||
height: itemSize.height
|
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 scaleRangeSize = max(self.scaleRange.min + 0.1, 0.75) - self.scaleRange.max
|
||||||
let scale = self.scaleRange.max + scaleRangeSize * CGFloat(self.lokiRng.next())
|
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 {
|
if absolutePosition.x < centerPoint.x {
|
||||||
leftPositions += 1
|
leftPositions += 1
|
||||||
@ -751,15 +760,14 @@ private struct PositionGenerator {
|
|||||||
|
|
||||||
let orbitRangeSize = self.outerOrbitRange.max - self.outerOrbitRange.min
|
let orbitRangeSize = self.outerOrbitRange.max - self.outerOrbitRange.min
|
||||||
let orbitDistanceFactor = self.outerOrbitRange.min + orbitRangeSize * CGFloat(self.lokiRng.next())
|
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 angleRange: CGFloat = placeOnLeftSide ? .pi : .pi
|
||||||
let angleOffset: CGFloat = placeOnLeftSide ? .pi/2 : -(.pi/2)
|
let angleOffset: CGFloat = placeOnLeftSide ? .pi/2 : -(.pi/2)
|
||||||
let angle = angleOffset + angleRange * CGFloat(self.lokiRng.next())
|
let angle = angleOffset + angleRange * CGFloat(self.lokiRng.next())
|
||||||
|
|
||||||
let absoluteX = centerPoint.x + orbitDistance * cos(angle)
|
// Get the absolute position to check boundaries and collisions
|
||||||
let absoluteY = centerPoint.y + orbitDistance * sin(angle)
|
let absolutePosition = getAbsolutePosition(distance: distance, angle: angle, centerPoint: centerPoint)
|
||||||
let absolutePosition = CGPoint(x: absoluteX, y: absoluteY)
|
|
||||||
|
|
||||||
if absolutePosition.x - itemSize.width/2 < self.edgePadding ||
|
if absolutePosition.x - itemSize.width/2 < self.edgePadding ||
|
||||||
absolutePosition.x + itemSize.width/2 > self.containerSize.width - self.edgePadding ||
|
absolutePosition.x + itemSize.width/2 > self.containerSize.width - self.edgePadding ||
|
||||||
@ -768,11 +776,6 @@ private struct PositionGenerator {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let relativePosition = CGPoint(
|
|
||||||
x: absolutePosition.x - centerPoint.x,
|
|
||||||
y: absolutePosition.y - centerPoint.y
|
|
||||||
)
|
|
||||||
|
|
||||||
let itemRect = CGRect(
|
let itemRect = CGRect(
|
||||||
x: absolutePosition.x - itemSize.width/2,
|
x: absolutePosition.x - itemSize.width/2,
|
||||||
y: absolutePosition.y - itemSize.height/2,
|
y: absolutePosition.y - itemSize.height/2,
|
||||||
@ -780,12 +783,12 @@ private struct PositionGenerator {
|
|||||||
height: itemSize.height
|
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 {
|
||||||
let distance = hypot(absolutePosition.x - centerPoint.x, absolutePosition.y - centerPoint.y)
|
getAbsolutePosition(distance: $0.distance, angle: $0.angle, centerPoint: centerPoint)
|
||||||
|
}, itemSize: itemSize) {
|
||||||
let normalizedDistance = min(distance / maxPossibleDistance, 1.0)
|
let normalizedDistance = min(distance / maxPossibleDistance, 1.0)
|
||||||
let scale = self.scaleRange.max - normalizedDistance * (self.scaleRange.max - self.scaleRange.min)
|
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 {
|
if absolutePosition.x < centerPoint.x {
|
||||||
leftPositions += 1
|
leftPositions += 1
|
||||||
@ -798,8 +801,11 @@ private struct PositionGenerator {
|
|||||||
return positions
|
return positions
|
||||||
}
|
}
|
||||||
|
|
||||||
private func posToAbsolute(_ relativePos: CGPoint, centerPoint: CGPoint) -> CGPoint {
|
func getAbsolutePosition(distance: CGFloat, angle: CGFloat, centerPoint: CGPoint) -> CGPoint {
|
||||||
return CGPoint(x: relativePos.x + centerPoint.x, y: relativePos.y + centerPoint.y)
|
return CGPoint(
|
||||||
|
x: centerPoint.x + distance * cos(angle),
|
||||||
|
y: centerPoint.y + distance * sin(angle)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func isValidPosition(_ rect: CGRect, existingPositions: [CGPoint], itemSize: CGSize) -> Bool {
|
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 {
|
private func windowFunction(t: CGFloat) -> CGFloat {
|
||||||
return bezierPoint(0.6, 0.0, 0.4, 1.0, t)
|
return bezierPoint(0.6, 0.0, 0.4, 1.0, t)
|
||||||
}
|
}
|
||||||
|
@ -2352,6 +2352,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||||||
giftsContext: profileGiftsContext,
|
giftsContext: profileGiftsContext,
|
||||||
hasBackground: hasBackground,
|
hasBackground: hasBackground,
|
||||||
avatarCenter: apparentAvatarFrame.center,
|
avatarCenter: apparentAvatarFrame.center,
|
||||||
|
avatarSize: apparentAvatarFrame.size,
|
||||||
defaultHeight: backgroundDefaultHeight,
|
defaultHeight: backgroundDefaultHeight,
|
||||||
avatarTransitionFraction: max(0.0, min(1.0, titleCollapseFraction + transitionFraction * 2.0)),
|
avatarTransitionFraction: max(0.0, min(1.0, titleCollapseFraction + transitionFraction * 2.0)),
|
||||||
statusBarHeight: statusBarHeight,
|
statusBarHeight: statusBarHeight,
|
||||||
|
@ -165,9 +165,9 @@ private final class SheetContent: CombinedComponent {
|
|||||||
iconName: "Account Freeze/Appeal",
|
iconName: "Account Freeze/Appeal",
|
||||||
iconColor: linkColor,
|
iconColor: linkColor,
|
||||||
action: {
|
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,
|
isEnabled: true,
|
||||||
displaysProgress: false,
|
displaysProgress: false,
|
||||||
action: {
|
action: {
|
||||||
component.submitAppeal()
|
|
||||||
Queue.mainQueue().after(1.0) {
|
|
||||||
component.dismiss()
|
component.dismiss()
|
||||||
|
Queue.mainQueue().after(0.5) {
|
||||||
|
component.submitAppeal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"filename" : "hand_30.pdf",
|
"filename" : "sandtimer_30.pdf",
|
||||||
"idiom" : "universal"
|
"idiom" : "universal"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"filename" : "sandtimer_30.pdf",
|
"filename" : "hand_30.pdf",
|
||||||
"idiom" : "universal"
|
"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
|
public private(set) var isPremium: Bool
|
||||||
|
|
||||||
|
private var isFrozenDisposable: Disposable?
|
||||||
|
public private(set) var isFrozen: Bool
|
||||||
|
|
||||||
public let imageCache: AnyObject?
|
public let imageCache: AnyObject?
|
||||||
|
|
||||||
public init(sharedContext: SharedAccountContextImpl, account: Account, limitsConfiguration: LimitsConfiguration, contentSettings: ContentSettings, appConfiguration: AppConfiguration, availableReplyColors: EngineAvailableColorOptions, availableProfileColors: EngineAvailableColorOptions, temp: Bool = false)
|
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.peerNameColors = PeerNameColors.with(availableReplyColors: availableReplyColors, availableProfileColors: availableProfileColors)
|
||||||
self.audioTranscriptionTrial = AudioTranscription.TrialState.defaultValue
|
self.audioTranscriptionTrial = AudioTranscription.TrialState.defaultValue
|
||||||
self.isPremium = false
|
self.isPremium = false
|
||||||
|
self.isFrozen = false
|
||||||
|
|
||||||
self.downloadedMediaStoreManager = DownloadedMediaStoreManagerImpl(postbox: account.postbox, accountManager: sharedContext.accountManager)
|
self.downloadedMediaStoreManager = DownloadedMediaStoreManagerImpl(postbox: account.postbox, accountManager: sharedContext.accountManager)
|
||||||
|
|
||||||
@ -452,6 +456,18 @@ public final class AccountContextImpl: AccountContext {
|
|||||||
}
|
}
|
||||||
self.audioTranscriptionTrial = audioTranscriptionTrial
|
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 {
|
deinit {
|
||||||
@ -464,6 +480,7 @@ public final class AccountContextImpl: AccountContext {
|
|||||||
self.animatedEmojiStickersDisposable?.dispose()
|
self.animatedEmojiStickersDisposable?.dispose()
|
||||||
self.userLimitsConfigurationDisposable?.dispose()
|
self.userLimitsConfigurationDisposable?.dispose()
|
||||||
self.peerNameColorsConfigurationDisposable?.dispose()
|
self.peerNameColorsConfigurationDisposable?.dispose()
|
||||||
|
self.isFrozenDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func storeSecureIdPassword(password: String) {
|
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 {
|
guard let strongSelf = self, strongSelf.isNodeLoaded else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guard !strongSelf.presentAccountFrozenInfoIfNeeded() else {
|
||||||
|
completion(.immediate, {})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if let messageId = messageId {
|
if let messageId = messageId {
|
||||||
let intrinsicCanSendMessagesHere = canSendMessagesToChat(strongSelf.presentationInterfaceState)
|
let intrinsicCanSendMessagesHere = canSendMessagesToChat(strongSelf.presentationInterfaceState)
|
||||||
var canSendMessagesHere = intrinsicCanSendMessagesHere
|
var canSendMessagesHere = intrinsicCanSendMessagesHere
|
||||||
@ -2114,6 +2120,11 @@ extension ChatControllerImpl {
|
|||||||
})
|
})
|
||||||
}, deleteMessages: { [weak self] messages, contextController, completion in
|
}, deleteMessages: { [weak self] messages, contextController, completion in
|
||||||
if let strongSelf = self, !messages.isEmpty {
|
if let strongSelf = self, !messages.isEmpty {
|
||||||
|
guard !strongSelf.presentAccountFrozenInfoIfNeeded() else {
|
||||||
|
completion(.default)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let messageIds = Set(messages.map { $0.id })
|
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)
|
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
|
|> deliverOnMainQueue).startStrict(next: { actions in
|
||||||
@ -4416,10 +4427,7 @@ extension ChatControllerImpl {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
|
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||||
if let _ = accountFreezeConfiguration.freezeUntilDate {
|
|
||||||
let controller = self.context.sharedContext.makeAccountFreezeInfoScreen(context: self.context)
|
|
||||||
self.push(controller)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,6 +333,9 @@ extension ChatControllerImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
controller?.dismissWithoutContent()
|
controller?.dismissWithoutContent()
|
||||||
|
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||||
|
return
|
||||||
|
}
|
||||||
self.presentTagPremiumPaywall()
|
self.presentTagPremiumPaywall()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,6 +344,11 @@ extension ChatControllerImpl {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||||
|
controller?.dismiss(completion: {})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
guard let message = messages.first else {
|
guard let message = messages.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -3399,8 +3399,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, scheduleCurrentMessage: { [weak self] params in
|
}, scheduleCurrentMessage: { [weak self] params in
|
||||||
if let strongSelf = self {
|
guard let self else {
|
||||||
strongSelf.presentScheduleTimePicker(completion: { [weak self] time in
|
return
|
||||||
|
}
|
||||||
|
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.presentScheduleTimePicker(completion: { [weak self] time in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let _ = strongSelf.presentationInterfaceState.interfaceState.mediaDraftState {
|
if let _ = strongSelf.presentationInterfaceState.interfaceState.mediaDraftState {
|
||||||
strongSelf.sendMediaRecording(scheduleTime: time, messageEffect: (params?.effect).flatMap {
|
strongSelf.sendMediaRecording(scheduleTime: time, messageEffect: (params?.effect).flatMap {
|
||||||
@ -3424,17 +3429,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}, sendScheduledMessagesNow: { [weak self] messageIds in
|
}, sendScheduledMessagesNow: { [weak self] messageIds in
|
||||||
if let strongSelf = self {
|
guard let self else {
|
||||||
if let _ = strongSelf.presentationInterfaceState.slowmodeState {
|
return
|
||||||
if let rect = strongSelf.chatDisplayNode.frameForInputActionButton() {
|
}
|
||||||
strongSelf.interfaceInteraction?.displaySlowmodeTooltip(strongSelf.chatDisplayNode.view, rect)
|
guard !self.presentAccountFrozenInfoIfNeeded() else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let _ = self.presentationInterfaceState.slowmodeState {
|
||||||
|
if let rect = self.chatDisplayNode.frameForInputActionButton() {
|
||||||
|
self.interfaceInteraction?.displaySlowmodeTooltip(self.chatDisplayNode.view, rect)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
let _ = strongSelf.context.engine.messages.sendScheduledMessageNowInteractively(messageId: messageIds.first!).startStandalone()
|
let _ = self.context.engine.messages.sendScheduledMessageNowInteractively(messageId: messageIds.first!).startStandalone()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, editScheduledMessagesTime: { [weak self] messageIds in
|
}, editScheduledMessagesTime: { [weak self] messageIds in
|
||||||
if let strongSelf = self, let messageId = messageIds.first {
|
if let strongSelf = self, let messageId = messageIds.first {
|
||||||
|
@ -21,8 +21,16 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
|
|||||||
return (nil, nil)
|
return (nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if context.isFrozen {
|
||||||
|
var isActuallyFrozen = true
|
||||||
let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||||
if let _ = accountFreezeConfiguration.freezeUntilDate {
|
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) {
|
if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) {
|
||||||
return (currentPanel, nil)
|
return (currentPanel, nil)
|
||||||
} else {
|
} else {
|
||||||
@ -32,6 +40,7 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
|
|||||||
return (panel, nil)
|
return (panel, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let _ = chatPresentationInterfaceState.search {
|
if let _ = chatPresentationInterfaceState.search {
|
||||||
var selectionPanel: ChatMessageSelectionInputPanelNode?
|
var selectionPanel: ChatMessageSelectionInputPanelNode?
|
||||||
|
@ -644,7 +644,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||||||
return self.actionButtons.micButton
|
return self.actionButtons.micButton
|
||||||
}
|
}
|
||||||
|
|
||||||
private let startingBotDisposable = MetaDisposable()
|
|
||||||
private let statusDisposable = MetaDisposable()
|
private let statusDisposable = MetaDisposable()
|
||||||
override var interfaceInteraction: ChatPanelInterfaceInteraction? {
|
override var interfaceInteraction: ChatPanelInterfaceInteraction? {
|
||||||
didSet {
|
didSet {
|
||||||
@ -655,25 +654,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||||||
self?.updateIsProcessingInlineRequest(value)
|
self?.updateIsProcessingInlineRequest(value)
|
||||||
}).strict())
|
}).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()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1130,7 +1110,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.statusDisposable.dispose()
|
self.statusDisposable.dispose()
|
||||||
self.startingBotDisposable.dispose()
|
|
||||||
self.tooltipController?.dismiss()
|
self.tooltipController?.dismiss()
|
||||||
self.currentEmojiSuggestion?.disposable.dispose()
|
self.currentEmojiSuggestion?.disposable.dispose()
|
||||||
}
|
}
|
||||||
|
@ -2451,6 +2451,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
mappedSource = .animatedEmoji
|
mappedSource = .animatedEmoji
|
||||||
case .paidMessages:
|
case .paidMessages:
|
||||||
mappedSource = .paidMessages
|
mappedSource = .paidMessages
|
||||||
|
case let .auth(price):
|
||||||
|
mappedSource = .auth(price)
|
||||||
}
|
}
|
||||||
return mappedSource
|
return mappedSource
|
||||||
}
|
}
|
||||||
@ -2465,13 +2467,13 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
return controller
|
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
|
var modal = true
|
||||||
if case .settings = source {
|
if case .settings = source {
|
||||||
modal = false
|
modal = false
|
||||||
}
|
}
|
||||||
let controller = PremiumIntroScreen(screenContext: .sharedContext(sharedContext, engine, inAppPurchaseManager), source: self.mapIntroSource(source: source), modal: modal)
|
let controller = PremiumIntroScreen(screenContext: .sharedContext(sharedContext, engine, inAppPurchaseManager), source: self.mapIntroSource(source: source), modal: modal)
|
||||||
controller.wasDismissed = dismissed
|
controller.customProceed = proceed
|
||||||
return controller
|
return controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user