Various improvements

This commit is contained in:
Ilya Laktyushin 2022-05-08 19:34:50 +04:00
parent b997987108
commit 5ded9f78a6
18 changed files with 654 additions and 512 deletions

View File

@ -7549,18 +7549,18 @@ Sorry for the inconvenience.";
"Chat.MultipleTypingMore" = "%@ and %@ others";
"DialogList.ExtendedPinLimitError" = "Sorry, you can pin more than **%1$@** chats to the top. Unpin some of the currently pinned ones or subscribe to **Telegram Premium** to double the limit to **%2$@** chats.";
"DialogList.ExtendedPinLimitIncrease" = "Increase Limit";
"Group.Username.RemoveExistingUsernamesTitle" = "Too Many Public Links";
"Group.Username.RemoveExistingUsernamesOrExtendInfo" = "You have reserved too many public links. Try revoking a link from an older group or channel, or upgrade to **Telegram Premium** to double the limit to **%@** public links.";
"Group.Username.IncreaseLimit" = "Increase Limit";
"OldChannels.TooManyCommunitiesTitle" = "Too Many Communities";
"OldChannels.TooManyCommunitiesText" = "You are a member of **%@** groups and channels. Please leave some before joining a new one or upgrade to **Telegram Premium** to double the limit to **%@** groups and channels.";
"OldChannels.IncreaseLimit" = "Increase Limit";
"OldChannels.LeaveCommunities_1" = "Leave %@ Community";
"OldChannels.LeaveCommunities_any" = "Leave %@ Communities";
"Stickers.FaveLimitReachedInfo" = "Sorry, you can't add more than **%@** stickers to favorites. Replace an older saved sticker or subscribe to **Telegram Premium** to double the limit to **%@** favorites stickers.";
"Stickers.FaveLimitReplaceOlder" = "Replace Older Sticker";
"Stickers.FaveLimitIncrease" = "Increase Limit";
"Premium.LimitReached" = "Limit Reached";
"Premium.IncreaseLimit" = "Increase Limit";
"Premium.MaxFoldersCountText" = "You have reached the limit of **%@** folders. You can double the limit to **%@** folders by subscribing to **Telegram Premium**.";
"Premium.MaxChatsInFolderCountText" = "Sorry, you can't add more than **%@** chats to a folder. You can increase this limit to **%@** by upgrading to **Telegram Premium**.";
"Premium.MaxFileSizeText" = "Double this limit to %@ per file by subscribing to **Telegram Premium**.";

View File

@ -331,7 +331,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
return nil
}, action: nil as ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?)))
subItems.append(.action(ContextMenuActionItem(text: strings.DialogList_ExtendedPinLimitIncrease, icon: { _ in
subItems.append(.action(ContextMenuActionItem(text: strings.Premium_IncreaseLimit, icon: { _ in
return nil
}, action: { _, f in
f(.default)

View File

@ -2,21 +2,35 @@ import Foundation
import UIKit
public final class RoundedRectangle: Component {
public let color: UIColor
public let cornerRadius: CGFloat
public enum GradientDirection: Equatable {
case horizontal
case vertical
}
public init(color: UIColor, cornerRadius: CGFloat) {
self.color = color
public let colors: [UIColor]
public let cornerRadius: CGFloat
public let gradientDirection: GradientDirection
public convenience init(color: UIColor, cornerRadius: CGFloat) {
self.init(colors: [color], cornerRadius: cornerRadius)
}
public init(colors: [UIColor], cornerRadius: CGFloat, gradientDirection: GradientDirection = .horizontal) {
self.colors = colors
self.cornerRadius = cornerRadius
self.gradientDirection = gradientDirection
}
public static func ==(lhs: RoundedRectangle, rhs: RoundedRectangle) -> Bool {
if !lhs.color.isEqual(rhs.color) {
if lhs.colors != rhs.colors {
return false
}
if lhs.cornerRadius != rhs.cornerRadius {
return false
}
if lhs.gradientDirection != rhs.gradientDirection {
return false
}
return true
}
@ -25,14 +39,37 @@ public final class RoundedRectangle: Component {
func update(component: RoundedRectangle, availableSize: CGSize, transition: Transition) -> CGSize {
if self.component != component {
let imageSize = CGSize(width: component.cornerRadius * 2.0, height: component.cornerRadius * 2.0)
UIGraphicsBeginImageContextWithOptions(imageSize, false, 0.0)
if let context = UIGraphicsGetCurrentContext() {
context.setFillColor(component.color.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: imageSize))
if component.colors.count == 1, let color = component.colors.first {
let imageSize = CGSize(width: component.cornerRadius * 2.0, height: component.cornerRadius * 2.0)
UIGraphicsBeginImageContextWithOptions(imageSize, false, 0.0)
if let context = UIGraphicsGetCurrentContext() {
context.setFillColor(color.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: imageSize))
}
self.image = UIGraphicsGetImageFromCurrentImageContext()?.stretchableImage(withLeftCapWidth: Int(component.cornerRadius), topCapHeight: Int(component.cornerRadius))
UIGraphicsEndImageContext()
} else if component.colors.count > 1{
let imageSize = availableSize
UIGraphicsBeginImageContextWithOptions(imageSize, false, 0.0)
if let context = UIGraphicsGetCurrentContext() {
context.addPath(UIBezierPath(roundedRect: CGRect(origin: CGPoint(), size: imageSize), cornerRadius: component.cornerRadius).cgPath)
context.clip()
let colors = component.colors
let gradientColors = colors.map { $0.cgColor } as CFArray
let colorSpace = CGColorSpaceCreateDeviceRGB()
var locations: [CGFloat] = []
let delta = 1.0 / CGFloat(colors.count - 1)
for i in 0 ..< colors.count {
locations.append(delta * CGFloat(i))
}
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: component.gradientDirection == .horizontal ? CGPoint(x: imageSize.width, y: 0.0) : CGPoint(x: 0.0, y: imageSize.height), options: CGGradientDrawingOptions())
}
self.image = UIGraphicsGetImageFromCurrentImageContext()?.stretchableImage(withLeftCapWidth: Int(component.cornerRadius), topCapHeight: Int(component.cornerRadius))
UIGraphicsEndImageContext()
}
self.image = UIGraphicsGetImageFromCurrentImageContext()?.stretchableImage(withLeftCapWidth: Int(component.cornerRadius), topCapHeight: Int(component.cornerRadius))
UIGraphicsEndImageContext()
}
return availableSize

View File

@ -66,6 +66,7 @@ open class ViewControllerComponentContainer: ViewController {
public let isVisible: Bool
public let theme: PresentationTheme
public let strings: PresentationStrings
public let dateTimeFormat: PresentationDateTimeFormat
public let controller: () -> ViewController?
public init(
@ -75,6 +76,7 @@ open class ViewControllerComponentContainer: ViewController {
isVisible: Bool,
theme: PresentationTheme,
strings: PresentationStrings,
dateTimeFormat: PresentationDateTimeFormat,
controller: @escaping () -> ViewController?
) {
self.statusBarHeight = statusBarHeight
@ -83,6 +85,7 @@ open class ViewControllerComponentContainer: ViewController {
self.isVisible = isVisible
self.theme = theme
self.strings = strings
self.dateTimeFormat = dateTimeFormat
self.controller = controller
}
@ -109,6 +112,9 @@ open class ViewControllerComponentContainer: ViewController {
if lhs.strings !== rhs.strings {
return false
}
if lhs.dateTimeFormat != rhs.dateTimeFormat {
return false
}
return true
}
@ -149,6 +155,7 @@ open class ViewControllerComponentContainer: ViewController {
isVisible: self.currentIsVisible,
theme: self.theme ?? self.presentationData.theme,
strings: self.presentationData.strings,
dateTimeFormat: self.presentationData.dateTimeFormat,
controller: { [weak self] in
return self?.controller
}

View File

@ -696,7 +696,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
if let _ = (view.cachedData as? CachedChannelData)?.peerGeoLocation {
} else {
switch mode {
case .privateLink:
case .privateLink, .revokeNames:
break
case .initialSetup, .generic:
entries.append(.typeHeader(presentationData.theme, isGroup ? presentationData.strings.Group_Setup_TypeHeader.uppercased() : presentationData.strings.Channel_Edit_LinkItem.uppercased()))
@ -808,7 +808,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePublicLinkHelp))
}
switch mode {
case .initialSetup:
case .initialSetup, .revokeNames:
break
case .generic, .privateLink:
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
@ -825,7 +825,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePrivateLinkHelp))
}
switch mode {
case .initialSetup:
case .initialSetup, .revokeNames:
break
case .generic, .privateLink:
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
@ -856,13 +856,34 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.forwardingInfo(presentationData.theme, forwardingEnabled ? (isGroup ? presentationData.strings.Group_Setup_ForwardingGroupInfo : presentationData.strings.Group_Setup_ForwardingChannelInfo) : (isGroup ? presentationData.strings.Group_Setup_ForwardingGroupInfoDisabled : presentationData.strings.Group_Setup_ForwardingChannelInfoDisabled)))
} else if let peer = view.peers[view.peerId] as? TelegramGroup {
switch mode {
case .revokeNames:
if let publicChannelsToRevoke = publicChannelsToRevoke {
entries.append(.linksLimitInfo(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesTitle, presentationData.strings.Group_Username_RemoveExistingUsernamesOrExtendInfo("\(1000)").string, 500))
entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_RemoveExistingUsernamesInfo, false))
var index: Int32 = 0
for peer in publicChannelsToRevoke.sorted(by: { lhs, rhs in
var lhsDate: Int32 = 0
var rhsDate: Int32 = 0
if let lhs = lhs as? TelegramChannel {
lhsDate = lhs.creationDate
}
if let rhs = rhs as? TelegramChannel {
rhsDate = rhs.creationDate
}
return lhsDate > rhsDate
}) {
entries.append(.existingLinkPeerItem(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, peer, ItemListPeerItemEditing(editable: true, editing: true, revealed: state.revealedRevokePeerId == peer.id), state.revokingPeerId == nil))
index += 1
}
}
case .privateLink:
let invite = (view.cachedData as? CachedGroupData)?.exportedInvitation
entries.append(.privateLinkHeader(presentationData.theme, presentationData.strings.InviteLink_InviteLink.uppercased()))
entries.append(.privateLink(presentationData.theme, invite, importers?.importers.prefix(3).compactMap { $0.peer.peer.flatMap(EnginePeer.init) } ?? [], importers?.count ?? 0, mode != .initialSetup))
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.GroupInfo_InviteLink_Help))
switch mode {
case .initialSetup:
case .initialSetup, .revokeNames:
break
case .generic, .privateLink:
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
@ -963,7 +984,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.privateLink(presentationData.theme, invite, importers?.importers.prefix(3).compactMap { $0.peer.peer.flatMap(EnginePeer.init) } ?? [], importers?.count ?? 0, mode != .initialSetup))
entries.append(.privateLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePrivateLinkHelp))
switch mode {
case .initialSetup:
case .initialSetup, .revokeNames:
break
case .generic, .privateLink:
entries.append(.privateLinkManage(presentationData.theme, presentationData.strings.InviteLink_Manage))
@ -1057,6 +1078,7 @@ public enum ChannelVisibilityControllerMode {
case initialSetup
case generic
case privateLink
case revokeNames
}
public func channelVisibilityController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: PeerId, mode: ChannelVisibilityControllerMode, upgradedToSupergroup: @escaping (PeerId, @escaping () -> Void) -> Void, onDismissRemoveController: ViewController? = nil) -> ViewController {
@ -1358,189 +1380,193 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
var footerItem: ItemListControllerFooterItem?
var rightNavigationButton: ItemListNavigationButton?
if let peer = peer as? TelegramChannel {
var doneEnabled = true
if let selectedType = state.selectedType {
switch selectedType {
case .privateChannel:
break
case .publicChannel:
var hasLocation = false
if let cachedChannelData = view.cachedData as? CachedChannelData, cachedChannelData.peerGeoLocation != nil {
hasLocation = true
}
if case .revokeNames = mode {
if let addressNameValidationStatus = state.addressNameValidationStatus {
switch addressNameValidationStatus {
case .availability(.available):
break
default:
doneEnabled = false
} else {
if let peer = peer as? TelegramChannel {
var doneEnabled = true
if let selectedType = state.selectedType {
switch selectedType {
case .privateChannel:
break
case .publicChannel:
var hasLocation = false
if let cachedChannelData = view.cachedData as? CachedChannelData, cachedChannelData.peerGeoLocation != nil {
hasLocation = true
}
} else {
doneEnabled = !(peer.addressName?.isEmpty ?? true) || hasLocation
}
}
}
rightNavigationButton = ItemListNavigationButton(content: .text(mode == .initialSetup ? presentationData.strings.Common_Next : presentationData.strings.Common_Done), style: state.updatingAddressName ? .activity : .bold, enabled: doneEnabled, action: {
var updatedAddressNameValue: String?
updateState { state in
updatedAddressNameValue = updatedAddressName(mode: mode, state: state, peer: peer, cachedData: view.cachedData)
return state
}
if let updatedCopyProtection = state.forwardingEnabled {
toggleCopyProtectionDisposable.set(context.engine.peers.toggleMessageCopyProtection(peerId: peerId, enabled: !updatedCopyProtection).start())
}
if let updatedJoinToSend = state.joinToSend {
toggleJoinToSendDisposable.set(context.engine.peers.toggleChannelJoinToSend(peerId: peerId, enabled: updatedJoinToSend == .members).start())
}
if let updatedApproveMembers = state.approveMembers {
toggleRequestToJoinDisposable.set(context.engine.peers.toggleChannelJoinRequest(peerId: peerId, enabled: updatedApproveMembers).start())
}
if let updatedAddressNameValue = updatedAddressNameValue {
let invokeAction: () -> Void = {
updateState { state in
return state.withUpdatedUpdatingAddressName(true)
}
_ = ApplicationSpecificNotice.markAsSeenSetPublicChannelLink(accountManager: context.sharedContext.accountManager).start()
updateAddressNameDisposable.set((context.engine.peers.updateAddressName(domain: .peer(peerId), name: updatedAddressNameValue.isEmpty ? nil : updatedAddressNameValue) |> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic))
|> deliverOnMainQueue).start(error: { _ in
updateState { state in
return state.withUpdatedUpdatingAddressName(false)
if let addressNameValidationStatus = state.addressNameValidationStatus {
switch addressNameValidationStatus {
case .availability(.available):
break
default:
doneEnabled = false
}
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}, completed: {
updateState { state in
return state.withUpdatedUpdatingAddressName(false)
} else {
doneEnabled = !(peer.addressName?.isEmpty ?? true) || hasLocation
}
}
}
rightNavigationButton = ItemListNavigationButton(content: .text(mode == .initialSetup ? presentationData.strings.Common_Next : presentationData.strings.Common_Done), style: state.updatingAddressName ? .activity : .bold, enabled: doneEnabled, action: {
var updatedAddressNameValue: String?
updateState { state in
updatedAddressNameValue = updatedAddressName(mode: mode, state: state, peer: peer, cachedData: view.cachedData)
return state
}
if let updatedCopyProtection = state.forwardingEnabled {
toggleCopyProtectionDisposable.set(context.engine.peers.toggleMessageCopyProtection(peerId: peerId, enabled: !updatedCopyProtection).start())
}
if let updatedJoinToSend = state.joinToSend {
toggleJoinToSendDisposable.set(context.engine.peers.toggleChannelJoinToSend(peerId: peerId, enabled: updatedJoinToSend == .members).start())
}
if let updatedApproveMembers = state.approveMembers {
toggleRequestToJoinDisposable.set(context.engine.peers.toggleChannelJoinRequest(peerId: peerId, enabled: updatedApproveMembers).start())
}
if let updatedAddressNameValue = updatedAddressNameValue {
let invokeAction: () -> Void = {
updateState { state in
return state.withUpdatedUpdatingAddressName(true)
}
_ = ApplicationSpecificNotice.markAsSeenSetPublicChannelLink(accountManager: context.sharedContext.accountManager).start()
updateAddressNameDisposable.set((context.engine.peers.updateAddressName(domain: .peer(peerId), name: updatedAddressNameValue.isEmpty ? nil : updatedAddressNameValue) |> timeout(10, queue: Queue.mainQueue(), alternate: .fail(.generic))
|> deliverOnMainQueue).start(error: { _ in
updateState { state in
return state.withUpdatedUpdatingAddressName(false)
}
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}, completed: {
updateState { state in
return state.withUpdatedUpdatingAddressName(false)
}
switch mode {
case .initialSetup:
nextImpl?()
case .generic, .privateLink, .revokeNames:
dismissImpl?()
}
}))
}
_ = (ApplicationSpecificNotice.getSetPublicChannelLink(accountManager: context.sharedContext.accountManager) |> deliverOnMainQueue).start(next: { showAlert in
if showAlert {
let text: String
if case .broadcast = peer.info {
text = presentationData.strings.Channel_Edit_PrivatePublicLinkAlert
} else {
text = presentationData.strings.Group_Edit_PrivatePublicLinkAlert
}
switch mode {
case .initialSetup:
nextImpl?()
case .generic, .privateLink:
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: invokeAction)]), nil)
} else {
invokeAction()
}
})
} else {
switch mode {
case .initialSetup:
nextImpl?()
case .generic, .privateLink, .revokeNames:
dismissImpl?()
}
}
})
} else if let peer = peer as? TelegramGroup {
var doneEnabled = true
if let selectedType = state.selectedType {
switch selectedType {
case .privateChannel:
break
case .publicChannel:
if let addressNameValidationStatus = state.addressNameValidationStatus {
switch addressNameValidationStatus {
case .availability(.available):
break
default:
doneEnabled = false
}
} else {
doneEnabled = !(peer.addressName?.isEmpty ?? true)
}
}
}
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: state.updatingAddressName ? .activity : .bold, enabled: doneEnabled, action: {
var updatedAddressNameValue: String?
updateState { state in
updatedAddressNameValue = updatedAddressName(mode: mode, state: state, peer: peer, cachedData: nil)
return state
}
if let updatedCopyProtection = state.forwardingEnabled {
toggleCopyProtectionDisposable.set(context.engine.peers.toggleMessageCopyProtection(peerId: peerId, enabled: !updatedCopyProtection).start())
}
if let updatedAddressNameValue = updatedAddressNameValue {
let invokeAction: () -> Void = {
updateState { state in
return state.withUpdatedUpdatingAddressName(true)
}
_ = ApplicationSpecificNotice.markAsSeenSetPublicChannelLink(accountManager: context.sharedContext.accountManager).start()
let signal = context.engine.peers.convertGroupToSupergroup(peerId: peerId)
|> mapToSignal { upgradedPeerId -> Signal<PeerId?, ConvertGroupToSupergroupError> in
return context.engine.peers.updateAddressName(domain: .peer(upgradedPeerId), name: updatedAddressNameValue.isEmpty ? nil : updatedAddressNameValue)
|> `catch` { _ -> Signal<Void, NoError> in
return .complete()
}
|> mapToSignal { _ -> Signal<PeerId?, NoError> in
return .complete()
}
|> then(.single(upgradedPeerId))
|> castError(ConvertGroupToSupergroupError.self)
}
|> deliverOnMainQueue
updateAddressNameDisposable.set((signal
|> deliverOnMainQueue).start(next: { updatedPeerId in
if let updatedPeerId = updatedPeerId {
upgradedToSupergroup(updatedPeerId, {
dismissImpl?()
})
} else {
dismissImpl?()
}
}, error: { error in
updateState { state in
return state.withUpdatedUpdatingAddressName(false)
}
switch error {
case .tooManyChannels:
pushControllerImpl?(oldChannelsController(context: context, updatedPresentationData: updatedPresentationData, intent: .upgrade))
default:
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}
}))
}
}
_ = (ApplicationSpecificNotice.getSetPublicChannelLink(accountManager: context.sharedContext.accountManager) |> deliverOnMainQueue).start(next: { showAlert in
if showAlert {
let text: String
if case .broadcast = peer.info {
text = presentationData.strings.Channel_Edit_PrivatePublicLinkAlert
_ = (ApplicationSpecificNotice.getSetPublicChannelLink(accountManager: context.sharedContext.accountManager) |> deliverOnMainQueue).start(next: { showAlert in
if showAlert {
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Group_Edit_PrivatePublicLinkAlert, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: invokeAction)]), nil)
} else {
text = presentationData.strings.Group_Edit_PrivatePublicLinkAlert
invokeAction()
}
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: invokeAction)]), nil)
} else {
invokeAction()
}
})
} else {
switch mode {
case .initialSetup:
nextImpl?()
case .generic, .privateLink:
dismissImpl?()
}
}
})
} else if let peer = peer as? TelegramGroup {
var doneEnabled = true
if let selectedType = state.selectedType {
switch selectedType {
case .privateChannel:
break
case .publicChannel:
if let addressNameValidationStatus = state.addressNameValidationStatus {
switch addressNameValidationStatus {
case .availability(.available):
break
default:
doneEnabled = false
}
} else {
doneEnabled = !(peer.addressName?.isEmpty ?? true)
}
}
}
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: state.updatingAddressName ? .activity : .bold, enabled: doneEnabled, action: {
var updatedAddressNameValue: String?
updateState { state in
updatedAddressNameValue = updatedAddressName(mode: mode, state: state, peer: peer, cachedData: nil)
return state
}
if let updatedCopyProtection = state.forwardingEnabled {
toggleCopyProtectionDisposable.set(context.engine.peers.toggleMessageCopyProtection(peerId: peerId, enabled: !updatedCopyProtection).start())
}
if let updatedAddressNameValue = updatedAddressNameValue {
let invokeAction: () -> Void = {
updateState { state in
return state.withUpdatedUpdatingAddressName(true)
}
_ = ApplicationSpecificNotice.markAsSeenSetPublicChannelLink(accountManager: context.sharedContext.accountManager).start()
let signal = context.engine.peers.convertGroupToSupergroup(peerId: peerId)
|> mapToSignal { upgradedPeerId -> Signal<PeerId?, ConvertGroupToSupergroupError> in
return context.engine.peers.updateAddressName(domain: .peer(upgradedPeerId), name: updatedAddressNameValue.isEmpty ? nil : updatedAddressNameValue)
|> `catch` { _ -> Signal<Void, NoError> in
return .complete()
}
|> mapToSignal { _ -> Signal<PeerId?, NoError> in
return .complete()
}
|> then(.single(upgradedPeerId))
|> castError(ConvertGroupToSupergroupError.self)
}
|> deliverOnMainQueue
updateAddressNameDisposable.set((signal
|> deliverOnMainQueue).start(next: { updatedPeerId in
if let updatedPeerId = updatedPeerId {
upgradedToSupergroup(updatedPeerId, {
dismissImpl?()
})
} else {
})
} else {
switch mode {
case .initialSetup:
nextImpl?()
case .generic, .privateLink, .revokeNames:
dismissImpl?()
}
}, error: { error in
updateState { state in
return state.withUpdatedUpdatingAddressName(false)
}
switch error {
case .tooManyChannels:
pushControllerImpl?(oldChannelsController(context: context, updatedPresentationData: updatedPresentationData, intent: .upgrade))
default:
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}
}))
}
_ = (ApplicationSpecificNotice.getSetPublicChannelLink(accountManager: context.sharedContext.accountManager) |> deliverOnMainQueue).start(next: { showAlert in
if showAlert {
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Group_Edit_PrivatePublicLinkAlert, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: invokeAction)]), nil)
} else {
invokeAction()
}
})
} else {
switch mode {
case .initialSetup:
nextImpl?()
case .generic, .privateLink:
dismissImpl?()
}
}
})
})
}
}
if state.revokingPeerId != nil {
@ -1560,7 +1586,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
switch mode {
case .initialSetup:
leftNavigationButton = nil
case .generic, .privateLink:
case .generic, .privateLink, .revokeNames:
leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
dismissImpl?()
})
@ -1602,7 +1628,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
}
if hasNamesToRevoke && selectedType == .publicChannel {
footerItem = IncreaseLimitFooterItem(theme: presentationData.theme, title: presentationData.strings.Group_Username_IncreaseLimit, colorful: true, action: {})
footerItem = IncreaseLimitFooterItem(theme: presentationData.theme, title: presentationData.strings.Premium_IncreaseLimit, colorful: true, action: {})
}
if let hadNamesToRevoke = hadNamesToRevoke {
@ -1611,14 +1637,17 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
}
let title: String
if case .privateLink = mode {
title = presentationData.strings.GroupInfo_InviteLink_Title
} else {
if let cachedChannelData = view.cachedData as? CachedChannelData, cachedChannelData.peerGeoLocation != nil {
title = presentationData.strings.Group_PublicLink_Title
} else {
title = isGroup ? presentationData.strings.GroupInfo_GroupType : presentationData.strings.Channel_TypeSetup_Title
}
switch mode {
case .generic, .initialSetup:
if let cachedChannelData = view.cachedData as? CachedChannelData, cachedChannelData.peerGeoLocation != nil {
title = presentationData.strings.Group_PublicLink_Title
} else {
title = isGroup ? presentationData.strings.GroupInfo_GroupType : presentationData.strings.Channel_TypeSetup_Title
}
case .privateLink:
title = presentationData.strings.GroupInfo_InviteLink_Title
case .revokeNames:
title = presentationData.strings.Premium_LimitReached
}
let entries = channelVisibilityControllerEntries(presentationData: presentationData, mode: mode, view: view, publicChannelsToRevoke: publicChannelsToRevoke, importers: importers, state: state)

View File

@ -309,7 +309,7 @@ public func oldChannelsController(context: AccountContext, updatedPresentationDa
buttonText = presentationData.strings.OldChannels_LeaveCommunities(Int32(state.selectedPeers.count))
colorful = false
} else {
buttonText = presentationData.strings.OldChannels_IncreaseLimit
buttonText = presentationData.strings.Premium_IncreaseLimit
colorful = true
}
let footerItem = IncreaseLimitFooterItem(theme: presentationData.theme, title: buttonText, colorful: colorful, action: {

View File

@ -41,19 +41,44 @@ private final class LimitScreenComponent: CombinedComponent {
final class State: ComponentState {
private let context: AccountContext
init(context: AccountContext) {
private var disposable: Disposable?
var limits: EngineConfiguration.UserLimits
var premiumLimits: EngineConfiguration.UserLimits
init(context: AccountContext, subject: LimitScreen.Subject) {
self.context = context
self.limits = EngineConfiguration.UserLimits.defaultValue
self.premiumLimits = EngineConfiguration.UserLimits.defaultValue
super.init()
self.disposable = (context.engine.data.get(
TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: false),
TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: true)
) |> deliverOnMainQueue).start(next: { [weak self] result in
if let strongSelf = self {
let (limits, premiumLimits) = result
strongSelf.limits = limits
strongSelf.premiumLimits = premiumLimits
strongSelf.updated(transition: .immediate)
}
})
}
deinit {
self.disposable?.dispose()
}
}
func makeState() -> State {
return State(context: self.context)
return State(context: self.context, subject: self.subject)
}
static var body: Body {
let icon = Child(BundleIconComponent.self)
let badgeBackground = Child(RoundedRectangle.self)
let badgeIcon = Child(BundleIconComponent.self)
let badgeText = Child(MultilineTextComponent.self)
let title = Child(MultilineTextComponent.self)
let text = Child(MultilineTextComponent.self)
@ -66,22 +91,84 @@ private final class LimitScreenComponent: CombinedComponent {
let theme = environment.theme
let strings = environment.strings
let state = context.state
let subject = component.subject
let topInset: CGFloat = 34.0 + 38.0
let sideInset: CGFloat = 16.0 + environment.safeInsets.left
let textSideInset: CGFloat = 24.0 + environment.safeInsets.left
let icon = icon.update(
let iconName: String
let badgeString: String
let string: String
switch subject {
case .folders:
let limit = state.limits.maxFoldersCount
let premiumLimit = state.premiumLimits.maxFoldersCount
iconName = "Premium/Folder"
badgeString = "\(limit)"
string = strings.Premium_MaxFoldersCountText("\(limit)", "\(premiumLimit)").string
case .chatsInFolder:
let limit = state.limits.maxFolderChatsCount
let premiumLimit = state.premiumLimits.maxFolderChatsCount
iconName = "Premium/Chat"
badgeString = "\(limit)"
string = strings.Premium_MaxChatsInFolderCountText("\(limit)", "\(premiumLimit)").string
case .pins:
let limit = state.limits.maxPinnedChatCount
let premiumLimit = state.premiumLimits.maxPinnedChatCount
iconName = "Premium/Pin"
badgeString = "\(limit)"
string = strings.DialogList_ExtendedPinLimitError("\(limit)", "\(premiumLimit)").string
case .files:
let limit = 2048 * 1024 * 1024 //state.limits.maxPinnedChatCount
let premiumLimit = 4096 * 1024 * 1024 //state.premiumLimits.maxPinnedChatCount
iconName = "Premium/File"
badgeString = dataSizeString(limit, formatting: DataSizeStringFormatting(strings: environment.strings, decimalSeparator: environment.dateTimeFormat.decimalSeparator))
string = strings.Premium_MaxFileSizeText(dataSizeString(premiumLimit, formatting: DataSizeStringFormatting(strings: environment.strings, decimalSeparator: environment.dateTimeFormat.decimalSeparator))).string
}
let badgeIcon = badgeIcon.update(
component: BundleIconComponent(
name: "Premium/Tmp",
tintColor: nil
name: iconName,
tintColor: .white
),
availableSize: CGSize(width: context.availableSize.width, height: CGFloat.greatestFiniteMagnitude),
availableSize: context.availableSize,
transition: .immediate
)
let badgeText = badgeText.update(
component: MultilineTextComponent(
text: NSAttributedString(
string: badgeString,
font: Font.with(size: 24.0, design: .round, weight: .semibold, traits: []),
textColor: .white,
paragraphAlignment: .center
),
horizontalAlignment: .center,
maximumNumberOfLines: 1
),
availableSize: context.availableSize,
transition: .immediate
)
let badgeBackground = badgeBackground.update(
component: RoundedRectangle(
colors: [UIColor(rgb: 0xa34fcf), UIColor(rgb: 0xc8498a), UIColor(rgb: 0xff7a23)],
cornerRadius: 23.5
),
availableSize: CGSize(width: badgeText.size.width + 67.0, height: 47.0),
transition: .immediate
)
let title = title.update(
component: MultilineTextComponent(
text: NSAttributedString(string: "Limit Reached", font: Font.semibold(17.0), textColor: theme.actionSheet.primaryTextColor, paragraphAlignment: .center),
text: NSAttributedString(
string: strings.Premium_LimitReached,
font: Font.semibold(17.0),
textColor: theme.actionSheet.primaryTextColor,
paragraphAlignment: .center
),
horizontalAlignment: .center,
maximumNumberOfLines: 1
),
@ -89,19 +176,10 @@ private final class LimitScreenComponent: CombinedComponent {
transition: .immediate
)
let textFont = Font.regular(15.0)
let boldTextFont = Font.semibold(15.0)
let textFont = Font.regular(16.0)
let boldTextFont = Font.semibold(16.0)
let textColor = theme.actionSheet.secondaryTextColor
let string: String
switch component.subject {
case .chatsInFolder:
string = ""
case .folders:
string = ""
case .pins:
string = strings.DialogList_ExtendedPinLimitError("\(5)", "\(10)").string
}
let textColor = theme.actionSheet.primaryTextColor
let attributedText = parseMarkdownIntoAttributedString(string, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: textColor), bold: MarkdownAttributeSet(font: boldTextFont, textColor: textColor), link: MarkdownAttributeSet(font: textFont, textColor: textColor), linkAttribute: { _ in
return nil
}))
@ -111,7 +189,7 @@ private final class LimitScreenComponent: CombinedComponent {
text: attributedText,
horizontalAlignment: .center,
maximumNumberOfLines: 0,
lineSpacing: 0.1
lineSpacing: 0.2
),
availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),
transition: .immediate
@ -119,7 +197,7 @@ private final class LimitScreenComponent: CombinedComponent {
let button = button.update(
component: SolidRoundedButtonComponent(
title: "Increase Limit",
title: strings.Premium_IncreaseLimit,
theme: SolidRoundedButtonComponent.Theme(
backgroundColor: .black,
backgroundColors: [UIColor(rgb: 0x407af0), UIColor(rgb: 0x9551e8), UIColor(rgb: 0xbf499a), UIColor(rgb: 0xf17b30)],
@ -154,8 +232,19 @@ private final class LimitScreenComponent: CombinedComponent {
let width = context.availableSize.width
context.add(icon
.position(CGPoint(x: width / 2.0, y: 57.0))
let badgeFrame = CGRect(origin: CGPoint(x: floor((context.availableSize.width - badgeBackground.size.width) / 2.0), y: 33.0), size: badgeBackground.size)
context.add(badgeBackground
.position(CGPoint(x: badgeFrame.midX, y: badgeFrame.midY))
)
let badgeIconFrame = CGRect(origin: CGPoint(x: badgeFrame.minX + 18.0, y: badgeFrame.minY + floor((badgeFrame.height - badgeIcon.size.height) / 2.0)), size: badgeIcon.size)
context.add(badgeIcon
.position(CGPoint(x: badgeIconFrame.midX, y: badgeIconFrame.midY))
)
let badgeTextFrame = CGRect(origin: CGPoint(x: badgeFrame.maxX - badgeText.size.width - 15.0, y: badgeFrame.minY + floor((badgeFrame.height - badgeText.size.height) / 2.0)), size: badgeText.size)
context.add(badgeText
.position(CGPoint(x: badgeTextFrame.midX, y: badgeTextFrame.midY))
)
context.add(title
@ -174,7 +263,7 @@ private final class LimitScreenComponent: CombinedComponent {
.position(CGPoint(x: width / 2.0, y: topInset + 76.0 + text.size.height + 20.0 + button.size.height + 40.0))
)
let contentSize = CGSize(width: context.availableSize.width, height: topInset + title.size.height + text.size.height)
let contentSize = CGSize(width: context.availableSize.width, height: topInset + 76.0 + text.size.height + 20.0 + button.size.height + 40.0 + 33.0 + environment.safeInsets.bottom)
return contentSize
}
@ -182,7 +271,7 @@ private final class LimitScreenComponent: CombinedComponent {
}
public class LimitScreen: ViewController {
final class Node: ViewControllerTracingNode, UIScrollViewDelegate, UIGestureRecognizerDelegate {
final class Node: ViewControllerTracingNode, UIGestureRecognizerDelegate {
private var presentationData: PresentationData
private weak var controller: LimitScreen?
@ -192,12 +281,9 @@ public class LimitScreen: ViewController {
let dim: ASDisplayNode
let wrappingView: UIView
let containerView: UIView
let scrollView: UIScrollView
let hostView: ComponentHostView<ViewControllerComponentContainer.Environment>
private(set) var isExpanded = false
private var panGestureRecognizer: UIPanGestureRecognizer?
private var panGestureArguments: (topInset: CGFloat, offset: CGFloat, scrollView: UIScrollView?, listNode: ListView?)?
private var currentIsVisible: Bool = false
private var currentLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
@ -218,14 +304,10 @@ public class LimitScreen: ViewController {
self.wrappingView = UIView()
self.containerView = UIView()
self.scrollView = UIScrollView()
self.hostView = ComponentHostView()
super.init()
self.scrollView.delegate = self
self.scrollView.showsVerticalScrollIndicator = false
self.containerView.clipsToBounds = true
self.containerView.backgroundColor = self.presentationData.theme.actionSheet.opaqueItemBackgroundColor
@ -233,8 +315,7 @@ public class LimitScreen: ViewController {
self.view.addSubview(self.wrappingView)
self.wrappingView.addSubview(self.containerView)
self.containerView.addSubview(self.scrollView)
self.scrollView.addSubview(self.hostView)
self.containerView.addSubview(self.hostView)
}
override func didLoad() {
@ -248,8 +329,6 @@ public class LimitScreen: ViewController {
self.wrappingView.addGestureRecognizer(panRecognizer)
self.dim.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimTapGesture(_:))))
self.controller?.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
}
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
@ -262,16 +341,16 @@ public class LimitScreen: ViewController {
if let (layout, _) = self.currentLayout {
if case .regular = layout.metrics.widthClass {
return false
} else {
let location = gestureRecognizer.location(in: self.containerView)
if !self.hostView.frame.contains(location) {
return false
}
}
}
return true
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let contentOffset = self.scrollView.contentOffset.y
self.controller?.navigationBar?.updateBackgroundAlpha(min(30.0, contentOffset) / 30.0, transition: .immediate)
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is UIPanGestureRecognizer {
return true
@ -303,10 +382,6 @@ public class LimitScreen: ViewController {
})
let alphaTransition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut)
alphaTransition.updateAlpha(node: self.dim, alpha: 0.0)
if !self.temporaryDismiss {
self.controller?.updateModalStyleOverlayTransitionFactor(0.0, transition: positionTransition)
}
}
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: Transition) {
@ -318,29 +393,11 @@ public class LimitScreen: ViewController {
self.dim.frame = CGRect(origin: CGPoint(x: 0.0, y: -layout.size.height), size: CGSize(width: layout.size.width, height: layout.size.height * 3.0))
var effectiveExpanded = self.isExpanded
if case .regular = layout.metrics.widthClass {
effectiveExpanded = true
}
let isLandscape = layout.orientation == .landscape
let edgeTopInset = isLandscape ? 0.0 : self.defaultTopInset
let topInset: CGFloat
if let (panInitialTopInset, panOffset, _, _) = self.panGestureArguments {
if effectiveExpanded {
topInset = min(edgeTopInset, panInitialTopInset + max(0.0, panOffset))
} else {
topInset = max(0.0, panInitialTopInset + min(0.0, panOffset))
}
} else {
topInset = effectiveExpanded ? 0.0 : edgeTopInset
}
transition.setFrame(view: self.wrappingView, frame: CGRect(origin: CGPoint(x: 0.0, y: topInset), size: layout.size), completion: nil)
let modalProgress = isLandscape ? 0.0 : (1.0 - topInset / self.defaultTopInset)
self.controller?.updateModalStyleOverlayTransitionFactor(modalProgress, transition: transition.containedViewLayoutTransition)
transition.setFrame(view: self.wrappingView, frame: CGRect(origin: CGPoint(), size: layout.size), completion: nil)
let clipFrame: CGRect
var clipFrame: CGRect
if layout.metrics.widthClass == .compact {
self.dim.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.25)
if isLandscape {
@ -387,9 +444,6 @@ public class LimitScreen: ViewController {
clipFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - containerSize.width) / 2.0), y: floor((layout.size.height - containerSize.height) / 2.0)), size: containerSize)
}
transition.setFrame(view: self.containerView, frame: clipFrame)
transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(), size: clipFrame.size), completion: nil)
let environment = ViewControllerComponentContainer.Environment(
statusBarHeight: 0.0,
navigationHeight: navigationHeight,
@ -397,23 +451,28 @@ public class LimitScreen: ViewController {
isVisible: self.currentIsVisible,
theme: self.theme ?? self.presentationData.theme,
strings: self.presentationData.strings,
dateTimeFormat: self.presentationData.dateTimeFormat,
controller: { [weak self] in
return self?.controller
}
)
var contentSize = self.hostView.update(
let contentSize = self.hostView.update(
transition: transition,
component: self.component,
environment: {
environment
},
forceUpdate: true,
containerSize: CGSize(width: clipFrame.size.width, height: 10000.0)
containerSize: CGSize(width: clipFrame.size.width, height: clipFrame.size.height)
)
contentSize.height = max(layout.size.height - navigationHeight, contentSize.height)
transition.setFrame(view: self.hostView, frame: CGRect(origin: CGPoint(), size: contentSize), completion: nil)
self.scrollView.contentSize = contentSize
if !isLandscape {
clipFrame.origin.y = layout.size.height - contentSize.height
transition.setFrame(view: self.containerView, frame: clipFrame)
} else {
}
}
private var didPlayAppearAnimation = false
@ -434,193 +493,28 @@ public class LimitScreen: ViewController {
}
}
private var defaultTopInset: CGFloat {
return 390.0
// guard let (layout, _) = self.currentLayout else{
// return 210.0
// }
// if case .compact = layout.metrics.widthClass {
// var factor: CGFloat = 0.2488
// if layout.size.width <= 320.0 {
// factor = 0.15
// }
// return floor(max(layout.size.width, layout.size.height) * factor)
// } else {
// return 210.0
// }
}
private func findScrollView(view: UIView?) -> (UIScrollView, ListView?)? {
if let view = view {
if let view = view as? UIScrollView {
return (view, nil)
}
if let node = view.asyncdisplaykit_node as? ListView {
return (node.scroller, node)
}
return findScrollView(view: view.superview)
} else {
return nil
}
}
@objc func panGesture(_ recognizer: UIPanGestureRecognizer) {
guard let (layout, navigationHeight) = self.currentLayout else {
return
}
let isLandscape = layout.orientation == .landscape
let edgeTopInset = isLandscape ? 0.0 : defaultTopInset
switch recognizer.state {
case .began:
let point = recognizer.location(in: self.view)
let currentHitView = self.hitTest(point, with: nil)
var scrollViewAndListNode = self.findScrollView(view: currentHitView)
if scrollViewAndListNode?.0.frame.height == self.frame.width {
scrollViewAndListNode = nil
}
let scrollView = scrollViewAndListNode?.0
let listNode = scrollViewAndListNode?.1
let topInset: CGFloat
if self.isExpanded {
topInset = 0.0
} else {
topInset = edgeTopInset
}
self.panGestureArguments = (topInset, 0.0, scrollView, listNode)
break
case .changed:
guard let (topInset, panOffset, scrollView, listNode) = self.panGestureArguments else {
return
}
let visibleContentOffset = listNode?.visibleContentOffset()
let contentOffset = scrollView?.contentOffset.y ?? 0.0
var translation = recognizer.translation(in: self.view).y
var currentOffset = topInset + translation
let epsilon = 1.0
if case let .known(value) = visibleContentOffset, value <= epsilon {
if let scrollView = scrollView {
scrollView.bounces = false
scrollView.setContentOffset(CGPoint(x: 0.0, y: 0.0), animated: false)
}
} else if let scrollView = scrollView, contentOffset <= -scrollView.contentInset.top + epsilon {
scrollView.bounces = false
scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false)
} else if let scrollView = scrollView {
translation = panOffset
currentOffset = topInset + translation
if self.isExpanded {
recognizer.setTranslation(CGPoint(), in: self.view)
} else if currentOffset > 0.0 {
scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false)
}
}
self.panGestureArguments = (topInset, translation, scrollView, listNode)
if !self.isExpanded {
if currentOffset > 0.0, let scrollView = scrollView {
scrollView.panGestureRecognizer.setTranslation(CGPoint(), in: scrollView)
}
}
let translation = recognizer.translation(in: self.view).y
var bounds = self.bounds
if self.isExpanded {
bounds.origin.y = -max(0.0, translation - edgeTopInset)
} else {
bounds.origin.y = -translation
}
bounds.origin.y = -translation
bounds.origin.y = min(0.0, bounds.origin.y)
self.bounds = bounds
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate)
case .ended:
guard let (currentTopInset, panOffset, scrollView, listNode) = self.panGestureArguments else {
return
}
self.panGestureArguments = nil
let visibleContentOffset = listNode?.visibleContentOffset()
let contentOffset = scrollView?.contentOffset.y ?? 0.0
let translation = recognizer.translation(in: self.view).y
var velocity = recognizer.velocity(in: self.view)
if self.isExpanded {
if case let .known(value) = visibleContentOffset, value > 0.1 {
velocity = CGPoint()
} else if case .unknown = visibleContentOffset {
velocity = CGPoint()
} else if contentOffset > 0.1 {
velocity = CGPoint()
}
}
let velocity = recognizer.velocity(in: self.view)
var bounds = self.bounds
if self.isExpanded {
bounds.origin.y = -max(0.0, translation - edgeTopInset)
} else {
bounds.origin.y = -translation
}
bounds.origin.y = -translation
bounds.origin.y = min(0.0, bounds.origin.y)
scrollView?.bounces = true
let offset = currentTopInset + panOffset
let topInset: CGFloat = edgeTopInset
var dismissing = false
if bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) || (self.isExpanded && bounds.minY.isZero && velocity.y > 1800.0) {
if bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) {
self.controller?.dismiss(animated: true, completion: nil)
dismissing = true
} else if self.isExpanded {
if velocity.y > 300.0 || offset > topInset / 2.0 {
self.isExpanded = false
if let listNode = listNode {
listNode.scroller.setContentOffset(CGPoint(), animated: false)
} else if let scrollView = scrollView {
scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false)
}
let distance = topInset - offset
let initialVelocity: CGFloat = distance.isZero ? 0.0 : abs(velocity.y / distance)
let transition = ContainedViewLayoutTransition.animated(duration: 0.45, curve: .customSpring(damping: 124.0, initialVelocity: initialVelocity))
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: Transition(transition))
} else {
self.isExpanded = true
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: Transition(.animated(duration: 0.3, curve: .easeInOut)))
}
} else if (velocity.y < -300.0 || offset < topInset / 2.0) {
if velocity.y > -2200.0 && velocity.y < -300.0, let listNode = listNode {
DispatchQueue.main.async {
listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
}
}
let initialVelocity: CGFloat = offset.isZero ? 0.0 : abs(velocity.y / offset)
let transition = ContainedViewLayoutTransition.animated(duration: 0.45, curve: .customSpring(damping: 124.0, initialVelocity: initialVelocity))
self.isExpanded = true
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: Transition(transition))
} else {
if let listNode = listNode {
listNode.scroller.setContentOffset(CGPoint(), animated: false)
} else if let scrollView = scrollView {
scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: false)
}
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: Transition(.animated(duration: 0.3, curve: .easeInOut)))
}
if !dismissing {
var bounds = self.bounds
let previousBounds = bounds
bounds.origin.y = 0.0
@ -628,25 +522,15 @@ public class LimitScreen: ViewController {
self.layer.animateBounds(from: previousBounds, to: self.bounds, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
}
case .cancelled:
self.panGestureArguments = nil
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: Transition(.animated(duration: 0.3, curve: .easeInOut)))
var bounds = self.bounds
let previousBounds = bounds
bounds.origin.y = 0.0
self.bounds = bounds
self.layer.animateBounds(from: previousBounds, to: self.bounds, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
default:
break
}
}
func update(isExpanded: Bool, transition: ContainedViewLayoutTransition) {
guard isExpanded != self.isExpanded else {
return
}
self.isExpanded = isExpanded
guard let (layout, navigationHeight) = self.currentLayout else {
return
}
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: Transition(transition))
}
}
var node: Node {
@ -667,6 +551,7 @@ public class LimitScreen: ViewController {
case folders
case chatsInFolder
case pins
case files
}
public convenience init(context: AccountContext, subject: Subject) {
@ -678,7 +563,7 @@ public class LimitScreen: ViewController {
self.component = AnyComponent(component)
self.theme = nil
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: context.sharedContext.currentPresentationData.with { $0 }))
super.init(navigationBarPresentationData: nil)
}
required public init(coder aDecoder: NSCoder) {
@ -719,36 +604,11 @@ public class LimitScreen: ViewController {
self.node.updateIsVisible(isVisible: false)
}
override public func updateNavigationBarLayout(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
var navigationLayout = self.navigationLayout(layout: layout)
var navigationFrame = navigationLayout.navigationFrame
var layout = layout
if case .regular = layout.metrics.widthClass {
let verticalInset: CGFloat = 44.0
let maxSide = max(layout.size.width, layout.size.height)
let minSide = min(layout.size.width, layout.size.height)
let containerSize = CGSize(width: min(layout.size.width - 20.0, floor(maxSide / 2.0)), height: min(layout.size.height, minSide) - verticalInset * 2.0)
let clipFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - containerSize.width) / 2.0), y: floor((layout.size.height - containerSize.height) / 2.0)), size: containerSize)
navigationFrame.size.width = clipFrame.width
layout.size = clipFrame.size
}
navigationFrame.size.height = 56.0
navigationLayout.navigationFrame = navigationFrame
navigationLayout.defaultContentHeight = 56.0
layout.statusBarHeight = nil
self.applyNavigationBarLayout(layout, navigationLayout: navigationLayout, additionalBackgroundHeight: 0.0, transition: transition)
}
override open func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
self.currentLayout = layout
super.containerLayoutUpdated(layout, transition: transition)
let navigationHeight: CGFloat = 56.0
self.node.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: Transition(transition))
}
}

View File

@ -0,0 +1 @@
import Foundation

View File

@ -434,6 +434,7 @@ public final class SolidRoundedButtonView: UIView {
private var fontSize: CGFloat
private let buttonBackgroundNode: UIImageView
private var buttonBackgroundAnimationView: UIImageView?
private let buttonGlossView: SolidRoundedButtonGlossView?
private let buttonNode: HighlightTrackingButton
private let titleNode: ImmediateTextView
@ -506,6 +507,11 @@ public final class SolidRoundedButtonView: UIView {
locations.append(delta * CGFloat(i))
}
self.buttonBackgroundNode.image = generateGradientImage(size: CGSize(width: 200.0, height: height), colors: theme.backgroundColors, locations: locations, direction: .horizontal)
let buttonBackgroundAnimationView = UIImageView()
buttonBackgroundAnimationView.image = generateGradientImage(size: CGSize(width: 200.0, height: height), colors: theme.backgroundColors, locations: locations, direction: .horizontal)
self.buttonBackgroundNode.addSubview(buttonBackgroundAnimationView)
self.buttonBackgroundAnimationView = buttonBackgroundAnimationView
} else {
self.buttonBackgroundNode.backgroundColor = theme.backgroundColor
}
@ -575,6 +581,42 @@ public final class SolidRoundedButtonView: UIView {
fatalError("init(coder:) has not been implemented")
}
private func setupGradientAnimations() {
guard let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView else {
return
}
if let _ = buttonBackgroundAnimationView.layer.animation(forKey: "movement") {
} else {
let offset = (buttonBackgroundAnimationView.frame.width - self.frame.width) / 2.0
let previousValue = buttonBackgroundAnimationView.center.x
var newValue: CGFloat = offset
if offset - previousValue < buttonBackgroundAnimationView.frame.width * 0.25 {
newValue -= CGFloat.random(in: buttonBackgroundAnimationView.frame.width * 0.3 ..< buttonBackgroundAnimationView.frame.width * 0.4)
} else {
// newValue -= CGFloat.random(in: 0.0 ..< buttonBackgroundAnimationView.frame.width * 0.1)
}
buttonBackgroundAnimationView.center = CGPoint(x: newValue, y: buttonBackgroundAnimationView.bounds.size.height / 2.0)
CATransaction.begin()
let animation = CABasicAnimation(keyPath: "position.x")
animation.duration = Double.random(in: 1.8 ..< 2.3)
animation.fromValue = previousValue
animation.toValue = newValue
animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
CATransaction.setCompletionBlock { [weak self] in
// if let isCurrentlyInHierarchy = self?.isCurrentlyInHierarchy, isCurrentlyInHierarchy {
self?.setupGradientAnimations()
// }
}
buttonBackgroundAnimationView.layer.add(animation, forKey: "movement")
CATransaction.commit()
}
}
public func transitionToProgress() {
guard self.progressNode == nil else {
return
@ -659,6 +701,12 @@ public final class SolidRoundedButtonView: UIView {
let buttonSize = CGSize(width: width, height: self.buttonHeight)
let buttonFrame = CGRect(origin: CGPoint(), size: buttonSize)
transition.updateFrame(view: self.buttonBackgroundNode, frame: buttonFrame)
if let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView {
transition.updateFrame(view: buttonBackgroundAnimationView, frame: CGRect(origin: CGPoint(), size: CGSize(width: buttonSize.width * 2.4, height: buttonSize.height)))
self.setupGradientAnimations()
}
if let buttonGlossView = self.buttonGlossView {
transition.updateFrame(view: buttonGlossView, frame: buttonFrame)
}

View File

@ -0,0 +1,80 @@
import Postbox
import SwiftSignalKit
public struct UserLimitsConfiguration: Equatable {
public let maxPinnedChatCount: Int32
public let maxChannelsCount: Int32
public let maxPublicLinksCount: Int32
public let maxSavedGifCount: Int32
public let maxFavedStickerCount: Int32
public let maxFoldersCount: Int32
public let maxFolderChatsCount: Int32
public let maxTextLengthCount: Int32
public static var defaultValue: UserLimitsConfiguration {
return UserLimitsConfiguration(
maxPinnedChatCount: 5,
maxChannelsCount: 500,
maxPublicLinksCount: 10,
maxSavedGifCount: 200,
maxFavedStickerCount: 5,
maxFoldersCount: 10,
maxFolderChatsCount: 100,
maxTextLengthCount: 4096
)
}
public init(
maxPinnedChatCount: Int32,
maxChannelsCount: Int32,
maxPublicLinksCount: Int32,
maxSavedGifCount: Int32,
maxFavedStickerCount: Int32,
maxFoldersCount: Int32,
maxFolderChatsCount: Int32,
maxTextLengthCount: Int32
) {
self.maxPinnedChatCount = maxPinnedChatCount
self.maxChannelsCount = maxChannelsCount
self.maxPublicLinksCount = maxPublicLinksCount
self.maxSavedGifCount = maxSavedGifCount
self.maxFavedStickerCount = maxFavedStickerCount
self.maxFoldersCount = maxFoldersCount
self.maxFolderChatsCount = maxFolderChatsCount
self.maxTextLengthCount = maxTextLengthCount
}
}
extension UserLimitsConfiguration {
init(appConfiguration: AppConfiguration, isPremium: Bool) {
let keySuffix = isPremium ? "_premium" : "_default"
let defaultValue = UserLimitsConfiguration.defaultValue
func getValue(_ key: String, orElse defaultValue: Int32) -> Int32 {
if let value = appConfiguration.data?[key + keySuffix] as? Double {
return Int32(value)
} else {
return defaultValue
}
}
self.maxPinnedChatCount = getValue("dialogs_pinned_limit", orElse: defaultValue.maxPinnedChatCount)
self.maxChannelsCount = getValue("channels_limit", orElse: defaultValue.maxPinnedChatCount)
self.maxPublicLinksCount = getValue("channels_public_limit", orElse: defaultValue.maxPinnedChatCount)
self.maxSavedGifCount = getValue("saved_gifs_limit", orElse: defaultValue.maxPinnedChatCount)
self.maxFavedStickerCount = getValue("stickers_faved_limit", orElse: defaultValue.maxPinnedChatCount)
self.maxFoldersCount = getValue("dialog_filters_limit", orElse: defaultValue.maxPinnedChatCount)
self.maxFolderChatsCount = getValue("dialog_filters_chats_limit", orElse: defaultValue.maxPinnedChatCount)
self.maxTextLengthCount = getValue("message_text_length_limit", orElse: defaultValue.maxPinnedChatCount)
}
}
public func getUserLimits(postbox: Postbox) -> Signal<Never, NoError> {
return postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|> mapToSignal { preferencesView -> Signal<Never, NoError> in
let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue
let configuration = UserLimitsConfiguration(appConfiguration: appConfiguration, isPremium: false)
print(configuration)
return .never()
}
}

View File

@ -46,6 +46,41 @@ public enum EngineConfiguration {
self.maxMessageRevokeIntervalInPrivateChats = maxMessageRevokeIntervalInPrivateChats
}
}
public struct UserLimits: Equatable {
public let maxPinnedChatCount: Int32
public let maxChannelsCount: Int32
public let maxPublicLinksCount: Int32
public let maxSavedGifCount: Int32
public let maxFavedStickerCount: Int32
public let maxFoldersCount: Int32
public let maxFolderChatsCount: Int32
public let maxTextLengthCount: Int32
public static var defaultValue: UserLimits {
return UserLimits(UserLimitsConfiguration.defaultValue)
}
public init(
maxPinnedChatCount: Int32,
maxChannelsCount: Int32,
maxPublicLinksCount: Int32,
maxSavedGifCount: Int32,
maxFavedStickerCount: Int32,
maxFoldersCount: Int32,
maxFolderChatsCount: Int32,
maxTextLengthCount: Int32
) {
self.maxPinnedChatCount = maxPinnedChatCount
self.maxChannelsCount = maxChannelsCount
self.maxPublicLinksCount = maxPublicLinksCount
self.maxSavedGifCount = maxSavedGifCount
self.maxFavedStickerCount = maxFavedStickerCount
self.maxFoldersCount = maxFoldersCount
self.maxFolderChatsCount = maxFolderChatsCount
self.maxTextLengthCount = maxTextLengthCount
}
}
}
extension EngineConfiguration.Limits {
@ -67,6 +102,21 @@ extension EngineConfiguration.Limits {
}
}
extension EngineConfiguration.UserLimits {
init(_ userLimitsConfiguration: UserLimitsConfiguration) {
self.init(
maxPinnedChatCount: userLimitsConfiguration.maxPinnedChatCount,
maxChannelsCount: userLimitsConfiguration.maxChannelsCount,
maxPublicLinksCount: userLimitsConfiguration.maxPublicLinksCount,
maxSavedGifCount: userLimitsConfiguration.maxSavedGifCount,
maxFavedStickerCount: userLimitsConfiguration.maxFavedStickerCount,
maxFoldersCount: userLimitsConfiguration.maxFoldersCount,
maxFolderChatsCount: userLimitsConfiguration.maxFolderChatsCount,
maxTextLengthCount: userLimitsConfiguration.maxTextLengthCount
)
}
}
public extension TelegramEngine.EngineData.Item {
enum Configuration {
public struct Limits: TelegramEngineDataItem, PostboxViewDataItem {
@ -89,5 +139,28 @@ public extension TelegramEngine.EngineData.Item {
return EngineConfiguration.Limits(limitsConfiguration)
}
}
public struct UserLimits: TelegramEngineDataItem, PostboxViewDataItem {
public typealias Result = EngineConfiguration.UserLimits
fileprivate let isPremium: Bool
public init(isPremium: Bool) {
self.isPremium = isPremium
}
var key: PostboxViewKey {
return .preferences(keys: Set([PreferencesKeys.appConfiguration]))
}
func extract(view: PostboxView) -> Result {
guard let view = view as? PreferencesView else {
preconditionFailure()
}
guard let appConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) else {
return EngineConfiguration.UserLimits(UserLimitsConfiguration.defaultValue)
}
return EngineConfiguration.UserLimits(UserLimitsConfiguration(appConfiguration: appConfiguration, isPremium: self.isPremium))
}
}
}
}

View File

@ -491,7 +491,7 @@ public extension TelegramEngine {
}
public func toggleItemPinned(location: TogglePeerChatPinnedLocation, itemId: PinnedItemId) -> Signal<TogglePeerChatPinnedResult, NoError> {
return _internal_toggleItemPinned(postbox: self.account.postbox, location: location, itemId: itemId)
return _internal_toggleItemPinned(postbox: self.account.postbox, accountPeerId: self.account.peerId, location: location, itemId: itemId)
}
public func getPinnedItemIds(location: TogglePeerChatPinnedLocation) -> Signal<[PinnedItemId], NoError> {

View File

@ -13,8 +13,10 @@ public enum TogglePeerChatPinnedResult {
case limitExceeded(Int)
}
func _internal_toggleItemPinned(postbox: Postbox, location: TogglePeerChatPinnedLocation, itemId: PinnedItemId) -> Signal<TogglePeerChatPinnedResult, NoError> {
func _internal_toggleItemPinned(postbox: Postbox, accountPeerId: PeerId, location: TogglePeerChatPinnedLocation, itemId: PinnedItemId) -> Signal<TogglePeerChatPinnedResult, NoError> {
return postbox.transaction { transaction -> TogglePeerChatPinnedResult in
let isPremium = transaction.getPeer(accountPeerId)?.isPremium ?? false
switch location {
case let .group(groupId):
var itemIds = transaction.getPinnedItemIds(groupId: groupId)
@ -37,10 +39,13 @@ func _internal_toggleItemPinned(postbox: Postbox, location: TogglePeerChatPinned
additionalCount = 1
}
let appConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? .defaultValue
let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue
let userLimitsConfiguration = UserLimitsConfiguration(appConfiguration: appConfiguration, isPremium: isPremium)
let limitCount: Int
if case .root = groupId {
limitCount = Int(limitsConfiguration.maxPinnedChatCount)
limitCount = Int(userLimitsConfiguration.maxPinnedChatCount)
} else {
limitCount = Int(limitsConfiguration.maxArchivedPinnedChatCount)
}

View File

@ -2252,7 +2252,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
private var initializedCredibilityIcon = false
private var currentPanelStatusData: PeerInfoStatusData?
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat {
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat {
self.state = state
self.peer = peer
self.avatarListNode.listContainerNode.peer = peer
@ -2567,17 +2567,13 @@ final class PeerInfoHeaderNode: ASDisplayNode {
if self.isAvatarExpanded {
let minTitleSize = CGSize(width: titleSize.width * 0.7, height: titleSize.height * 0.7)
let minTitleFrame: CGRect
minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - 58.0 - UIScreenPixel + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: minTitleSize)
let minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - 58.0 - UIScreenPixel + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: minTitleSize)
titleFrame = CGRect(origin: CGPoint(x: minTitleFrame.midX - titleSize.width / 2.0, y: minTitleFrame.midY - titleSize.height / 2.0), size: titleSize)
subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: minTitleFrame.maxY + 2.0), size: subtitleSize)
usernameFrame = CGRect(origin: CGPoint(x: width - usernameSize.width - 16.0, y: minTitleFrame.midY - usernameSize.height / 2.0), size: usernameSize)
} else {
titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 7.0 + (subtitleSize.height.isZero ? 11.0 : 0.0)), size: titleSize)
titleFrame = titleFrame.offsetBy(dx: 0.0, dy: 11.0)
titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 7.0 + (subtitleSize.height.isZero ? 11.0 : 0.0) + 11.0), size: titleSize)
let totalSubtitleWidth = subtitleSize.width + usernameSpacing + usernameSize.width
if usernameSize.width == 0.0 {
@ -2593,7 +2589,10 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let titleLockOffset: CGFloat = 7.0 + singleTitleLockOffset
let titleMaxLockOffset: CGFloat = 7.0
let titleCollapseOffset = titleFrame.midY - statusBarHeight - titleLockOffset
var titleCollapseOffset = titleFrame.midY - statusBarHeight - titleLockOffset
if case .regular = metrics.widthClass {
titleCollapseOffset -= 7.0
}
let titleOffset = -min(titleCollapseOffset, contentOffset)
let titleCollapseFraction = max(0.0, min(1.0, contentOffset / titleCollapseOffset))

View File

@ -6997,7 +6997,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
let headerInset = sectionInset
var headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, transition: transition, additive: additive)
var headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive)
if !self.isSettings && !self.state.isEditing {
headerHeight += 71.0
}
@ -7357,7 +7357,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
let headerInset = sectionInset
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, transition: transition, additive: additive)
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive)
}
let paneAreaExpansionDistance: CGFloat = 32.0
@ -8312,7 +8312,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig
}
let headerInset = sectionInset
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, notificationSettings: self.screenNode.data?.notificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, transition: transition, additive: false)
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, notificationSettings: self.screenNode.data?.notificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, metrics: layout.metrics, transition: transition, additive: false)
}
let titleScale = (fraction * previousTitleNode.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.bounds.height

View File

@ -129,6 +129,8 @@ public final class TelegramRootController: NavigationController {
self.accountSettingsController = accountSettingsController
self.rootTabController = tabBarController
self.pushViewController(tabBarController, animated: false)
let _ = getUserLimits(postbox: self.context.account.postbox).start()
}
public func updateRootControllers(showCallsTab: Bool) {

View File

@ -723,6 +723,7 @@ public class TranslateScreen: ViewController {
isVisible: self.currentIsVisible,
theme: self.theme ?? self.presentationData.theme,
strings: self.presentationData.strings,
dateTimeFormat: self.presentationData.dateTimeFormat,
controller: { [weak self] in
return self?.controller
}