Peers Nearby improvements and bug fixes

This commit is contained in:
Ilya Laktyushin 2019-06-19 19:04:22 +02:00
parent 7d5815f329
commit 653ed2993e
24 changed files with 3028 additions and 2918 deletions

View file

@ -4387,6 +4387,7 @@ Any member of this group will be able to see messages in the channel.";
"Channel.OwnershipTransfer.ChangeOwner" = "Change Owner";
"Channel.OwnershipTransfer.ErrorPublicChannelsTooMuch" = "Sorry, the target user has too many public groups or channels already. Please ask them to make one of their existing groups or channels private first.";
"Group.OwnershipTransfer.ErrorLocatedGroupsTooMuch" = "Sorry, the target user has too many location-based groups already. Please ask them to delete or transfer one of their existing ones first.";
"Group.OwnershipTransfer.ErrorAdminsTooMuch" = "Sorry, this group has too many admins and the new owner can't be added. Please remove one of the existing admins first.";
"Channel.OwnershipTransfer.ErrorAdminsTooMuch" = "Sorry, this channel has too many admins and the new owner can't be added. Please remove one of the existing admins first.";
@ -4446,3 +4447,9 @@ Any member of this group will be able to see messages in the channel.";
"GroupInfo.Location" = "Location";
"GroupInfo.PublicLink" = "Public Link";
"GroupInfo.PublicLinkAdd" = "Add";
"Group.PublicLink.Title" = "Public Link";
"Group.PublicLink.Placeholder" = "link";
"Group.PublicLink.Info" = "People can share this link with others and find your group using Telegram search.\n\nYou can use use **a-z**, **0-9** and undescores. Minimum length is **5** characters.";
"CreateGroup.ErrorLocatedGroupsTooMuch" = "Sorry, you have too many location-based groups already. Please delete one of your existing ones first.";

View file

@ -25,7 +25,7 @@ final class AlertControllerNode: ASDisplayNode {
let dimColor = UIColor(white: 0.0, alpha: 0.5)
self.centerDimView = UIImageView()
self.centerDimView.image = generateStretchableFilledCircleImage(radius: 16.0, color: nil, backgroundColor: dimColor)
self.centerDimView.backgroundColor = dimColor
self.topDimView = UIView()
self.topDimView.backgroundColor = dimColor
@ -95,11 +95,17 @@ final class AlertControllerNode: ASDisplayNode {
self.bottomDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.leftDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.rightDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, completion: { [weak self] _ in
self?.centerDimView.backgroundColor = nil
self?.centerDimView.image = generateStretchableFilledCircleImage(radius: 16.0, color: nil, backgroundColor: UIColor(white: 0.0, alpha: 0.5))
})
self.containerNode.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, removeOnCompletion: true, additive: false, completion: nil)
}
func animateOut(completion: @escaping () -> Void) {
self.centerDimView.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
self.centerDimView.image = nil
self.centerDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
self.topDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
self.bottomDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)

View file

@ -340,6 +340,8 @@ const CGPoint TGLocationPickerPinOffset = { 0.0f, 33.0f };
- (void)_sendLocation
{
_tableView.userInteractionEnabled = false;
CLLocationCoordinate2D coordinate = _currentUserLocation.coordinate;
if (_mapInFullScreenMode)
coordinate = [self mapCenterCoordinateForPickerPin];

View file

@ -17,6 +17,7 @@ import TelegramApi
public enum CreateChannelError {
case generic
case restricted
case tooMuchLocationBasedGroups
}
private func createChannel(account: Account, title: String, description: String?, isSupergroup:Bool, location: (latitude: Double, longitude: Double, address: String)? = nil) -> Signal<PeerId, CreateChannelError> {
@ -38,7 +39,9 @@ private func createChannel(account: Account, title: String, description: String?
return account.network.request(Api.functions.channels.createChannel(flags: flags, title: title, about: description ?? "", geoPoint: geoPoint, address: address), automaticFloodWait: false)
|> mapError { error -> CreateChannelError in
if error.errorDescription == "USER_RESTRICTED" {
if error.errorDescription == "" {
return .tooMuchLocationBasedGroups
} else if error.errorDescription == "USER_RESTRICTED" {
return .restricted
} else {
return .generic

View file

@ -18,6 +18,7 @@ public enum ChannelOwnershipTransferError {
case invalidPassword
case adminsTooMuch
case userPublicChannelsTooMuch
case userLocatedGroupsTooMuch
case restricted
case userBlocked
}
@ -53,6 +54,8 @@ public func checkOwnershipTranfserAvailability(postbox: Postbox, network: Networ
}
} else if error.errorDescription == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH" {
return .userPublicChannelsTooMuch
} else if error.errorDescription == "CHANNELS_ADMIN_LOCATED_TOO_MUCHs" {
return .userLocatedGroupsTooMuch
} else if error.errorDescription == "ADMINS_TOO_MUCH" {
return .adminsTooMuch
} else if error.errorDescription == "USER_PRIVACY_RESTRICTED" {
@ -69,80 +72,119 @@ public func checkOwnershipTranfserAvailability(postbox: Postbox, network: Networ
}
}
public func updateChannelOwnership(postbox: Postbox, network: Network, accountStateManager: AccountStateManager, channelId: PeerId, memberId: PeerId, password: String) -> Signal<Never, ChannelOwnershipTransferError> {
public func updateChannelOwnership(account: Account, accountStateManager: AccountStateManager, channelId: PeerId, memberId: PeerId, password: String) -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> {
guard !password.isEmpty else {
return .fail(.invalidPassword)
}
return postbox.transaction { transaction -> (channel: Peer?, user: Peer?) in
return (channel: transaction.getPeer(channelId), user: transaction.getPeer(memberId))
return combineLatest(fetchChannelParticipant(account: account, peerId: channelId, participantId: account.peerId), fetchChannelParticipant(account: account, peerId: channelId, participantId: memberId))
|> mapError { error -> ChannelOwnershipTransferError in
return .generic
}
|> introduceError(ChannelOwnershipTransferError.self)
|> mapToSignal { channel, user -> Signal<Never, ChannelOwnershipTransferError> in
guard let channel = channel, let user = user else {
return .fail(.generic)
}
guard let apiChannel = apiInputChannel(channel) else {
return .fail(.generic)
}
guard let apiUser = apiInputUser(user) else {
return .fail(.generic)
}
let checkPassword = twoStepAuthData(network)
|> mapError { error -> ChannelOwnershipTransferError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
return .limitExceeded
} else {
return .generic
}
}
|> mapToSignal { authData -> Signal<Api.InputCheckPasswordSRP, ChannelOwnershipTransferError> in
if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData {
guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else {
return .fail(.generic)
}
return .single(.inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)))
} else {
return .fail(.twoStepAuthMissing)
}
}
return checkPassword
|> mapToSignal { password -> Signal<Never, ChannelOwnershipTransferError> in
return network.request(Api.functions.channels.editCreator(channel: apiChannel, userId: apiUser, password: password))
|> mapError { error -> ChannelOwnershipTransferError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
return .limitExceeded
} else if error.errorDescription == "PASSWORD_HASH_INVALID" {
return .invalidPassword
} else if error.errorDescription == "PASSWORD_MISSING" {
return .twoStepAuthMissing
} else if error.errorDescription.hasPrefix("PASSWORD_TOO_FRESH_") {
let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "PASSWORD_TOO_FRESH_".count)...])
if let value = Int32(timeout) {
return .twoStepAuthTooFresh(value)
|> mapToSignal { currentCreator, currentParticipant -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> in
return account.postbox.transaction { transaction -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> in
if let channel = transaction.getPeer(channelId), let inputChannel = apiInputChannel(channel), let accountUser = transaction.getPeer(account.peerId), let user = transaction.getPeer(memberId), let inputUser = apiInputUser(user) {
let updatedParticipant = ChannelParticipant.creator(id: user.id)
let updatedPreviousCreator = ChannelParticipant.member(id: accountUser.id, invitedAt: Int32(Date().timeIntervalSince1970), adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(flags:[]), promotedBy: accountUser.id, canBeEditedByAccountPeer: false), banInfo: nil)
let checkPassword = twoStepAuthData(account.network)
|> mapError { error -> ChannelOwnershipTransferError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
return .limitExceeded
} else {
return .generic
}
} else if error.errorDescription.hasPrefix("SESSION_TOO_FRESH_") {
let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "SESSION_TOO_FRESH_".count)...])
if let value = Int32(timeout) {
return .authSessionTooFresh(value)
}
} else if error.errorDescription == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH" {
return .userPublicChannelsTooMuch
} else if error.errorDescription == "ADMINS_TOO_MUCH" {
return .adminsTooMuch
} else if error.errorDescription == "USER_PRIVACY_RESTRICTED" {
return .restricted
} else if error.errorDescription == "USER_BLOCKED" {
return .userBlocked
}
return .generic
}
|> mapToSignal { updates -> Signal<Never, ChannelOwnershipTransferError> in
accountStateManager.addUpdates(updates)
return.complete()
|> mapToSignal { authData -> Signal<Api.InputCheckPasswordSRP, ChannelOwnershipTransferError> in
if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData {
guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else {
return .fail(.generic)
}
return .single(.inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)))
} else {
return .fail(.twoStepAuthMissing)
}
}
return checkPassword
|> mapToSignal { password -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> in
return account.network.request(Api.functions.channels.editCreator(channel: inputChannel, userId: inputUser, password: password), automaticFloodWait: false)
|> mapError { error -> ChannelOwnershipTransferError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
return .limitExceeded
} else if error.errorDescription == "PASSWORD_HASH_INVALID" {
return .invalidPassword
} else if error.errorDescription == "PASSWORD_MISSING" {
return .twoStepAuthMissing
} else if error.errorDescription.hasPrefix("PASSWORD_TOO_FRESH_") {
let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "PASSWORD_TOO_FRESH_".count)...])
if let value = Int32(timeout) {
return .twoStepAuthTooFresh(value)
}
} else if error.errorDescription.hasPrefix("SESSION_TOO_FRESH_") {
let timeout = String(error.errorDescription[error.errorDescription.index(error.errorDescription.startIndex, offsetBy: "SESSION_TOO_FRESH_".count)...])
if let value = Int32(timeout) {
return .authSessionTooFresh(value)
}
} else if error.errorDescription == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH" {
return .userPublicChannelsTooMuch
} else if error.errorDescription == "ADMINS_TOO_MUCH" {
return .adminsTooMuch
} else if error.errorDescription == "USER_PRIVACY_RESTRICTED" {
return .restricted
} else if error.errorDescription == "USER_BLOCKED" {
return .userBlocked
}
return .generic
}
|> mapToSignal { updates -> Signal<[(ChannelParticipant?, RenderedChannelParticipant)], ChannelOwnershipTransferError> in
accountStateManager.addUpdates(updates)
return account.postbox.transaction { transaction -> [(ChannelParticipant?, RenderedChannelParticipant)] in
transaction.updatePeerCachedData(peerIds: Set([channelId]), update: { _, cachedData -> CachedPeerData? in
if let cachedData = cachedData as? CachedChannelData, let adminCount = cachedData.participantsSummary.adminCount {
var updatedAdminCount = adminCount
var wasAdmin = false
if let currentParticipant = currentParticipant {
switch currentParticipant {
case .creator:
wasAdmin = true
case let .member(_, _, adminInfo, _):
if let adminInfo = adminInfo, !adminInfo.rights.isEmpty {
wasAdmin = true
}
}
}
if !wasAdmin {
updatedAdminCount = adminCount + 1
}
return cachedData.withUpdatedParticipantsSummary(cachedData.participantsSummary.withUpdatedAdminCount(updatedAdminCount))
} else {
return cachedData
}
})
var peers: [PeerId: Peer] = [:]
var presences: [PeerId: PeerPresence] = [:]
peers[accountUser.id] = accountUser
if let presence = transaction.getPeerPresence(peerId: accountUser.id) {
presences[accountUser.id] = presence
}
peers[user.id] = user
if let presence = transaction.getPeerPresence(peerId: user.id) {
presences[user.id] = presence
}
return [(currentCreator, RenderedChannelParticipant(participant: updatedPreviousCreator, peer: accountUser, peers: peers, presences: presences)), (currentParticipant, RenderedChannelParticipant(participant: updatedParticipant, peer: user, peers: peers, presences: presences))]
}
|> mapError { _ -> ChannelOwnershipTransferError in return .generic }
}
}
} else {
return .fail(.generic)
}
}
|> mapError { _ -> ChannelOwnershipTransferError in return .generic }
|> switchToLatest
}
}

View file

@ -20,7 +20,7 @@ public enum ConvertGroupToSupergroupError {
public func convertGroupToSupergroup(account: Account, peerId: PeerId) -> Signal<PeerId, ConvertGroupToSupergroupError> {
return account.network.request(Api.functions.messages.migrateChat(chatId: peerId.id))
|> mapError { _ -> ConvertGroupToSupergroupError in
|> mapError { error -> ConvertGroupToSupergroupError in
return .generic
}
|> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic))

View file

@ -18,6 +18,7 @@ public enum CreateGroupError {
case generic
case privacy
case restricted
case tooMuchLocationBasedGroups
}
public func createGroup(account: Account, title: String, peerIds: [PeerId]) -> Signal<PeerId?, CreateGroupError> {

View file

@ -47,7 +47,8 @@ public final class PeersNearbyContext {
}
return .single(peersNearby)
|> then(accountStateManager.updatedPeersNearby())
}).start(next: { [weak self] updatedEntries in
}
|> deliverOn(self.queue)).start(next: { [weak self] updatedEntries in
guard let strongSelf = self else {
return
}
@ -76,7 +77,7 @@ public final class PeersNearbyContext {
}
}))
self.timer = SwiftSignalKit.Timer(timeout: 5.0, repeat: true, completion: { [weak self] in
self.timer = SwiftSignalKit.Timer(timeout: 2.0, repeat: true, completion: { [weak self] in
guard let strongSelf = self else {
return
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Artboard Copy@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "Artboard Copy@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -456,7 +456,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
var index = 0
for right in rightsOrder {
if accountUserRightsFlags.contains(right) {
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating))
entries.append(.rightItem(presentationData.theme, index, stringForRight(strings: presentationData.strings, right: right, isGroup: isGroup, defaultBannedRights: channel.defaultBannedRights), right, currentRightsFlags, currentRightsFlags.contains(right), !state.updating && admin.id != accountPeerId))
index += 1
}
}

View file

@ -316,6 +316,10 @@ private final class ChannelMemberSingleCategoryListContext: ChannelMemberCategor
break loop
}
}
if let updated = updated, case .creator = updated.participant{
list.insert(updated, at: 0)
updatedList = true
}
}
case .restricted:
if let updated = updated, let banInfo = updated.participant.banInfo, !banInfo.rights.flags.contains(.banReadMessages) {

View file

@ -436,7 +436,7 @@ private func commitChannelOwnershipTransferController(context: AccountContext, p
let signal: Signal<PeerId?, ChannelOwnershipTransferError>
if let peer = peer as? TelegramChannel {
signal = updateChannelOwnership(postbox: context.account.postbox, network: context.account.network, accountStateManager: context.account.stateManager, channelId: peer.id, memberId: member.id, password: contentNode.password) |> mapToSignal { _ in
signal = context.peerChannelMemberCategoriesContextsManager.transferOwnership(account: context.account, peerId: peer.id, memberId: member.id, password: contentNode.password) |> mapToSignal { _ in
return .complete()
}
|> then(.single(nil))
@ -449,7 +449,7 @@ private func commitChannelOwnershipTransferController(context: AccountContext, p
guard let upgradedPeerId = upgradedPeerId else {
return .fail(.generic)
}
return updateChannelOwnership(postbox: context.account.postbox, network: context.account.network, accountStateManager: context.account.stateManager, channelId: upgradedPeerId, memberId: member.id, password: contentNode.password) |> mapToSignal { _ in
return context.peerChannelMemberCategoriesContextsManager.transferOwnership(account: context.account, peerId: upgradedPeerId, memberId: member.id, password: contentNode.password) |> mapToSignal { _ in
return .complete()
}
|> then(.single(upgradedPeerId))
@ -477,6 +477,8 @@ private func commitChannelOwnershipTransferController(context: AccountContext, p
errorTextAndActions = (isGroup ? presentationData.strings.Group_OwnershipTransfer_ErrorAdminsTooMuch : presentationData.strings.Channel_OwnershipTransfer_ErrorAdminsTooMuch, [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
case .userPublicChannelsTooMuch:
errorTextAndActions = (presentationData.strings.Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch, [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
case .userLocatedGroupsTooMuch:
errorTextAndActions = (presentationData.strings.Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch, [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
case .userBlocked, .restricted:
errorTextAndActions = (isGroup ? presentationData.strings.Group_OwnershipTransfer_ErrorPrivacyRestricted : presentationData.strings.Channel_OwnershipTransfer_ErrorPrivacyRestricted, [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
default:
@ -517,17 +519,10 @@ private func confirmChannelOwnershipTransferController(context: AccountContext,
let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: theme.primaryColor)
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
var dismissImpl: (() -> Void)?
let controller = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Channel_OwnershipTransfer_ChangeOwner, action: {
dismissImpl?()
present(commitChannelOwnershipTransferController(context: context, peer: peer, member: member, present: present, completion: completion), nil)
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {
dismissImpl?()
})], actionLayout: .vertical)
dismissImpl = { [weak controller] in
controller?.dismissAnimated()
}
return controller
}

View file

@ -63,7 +63,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
case publicLinkHeader(PresentationTheme, String)
case publicLinkAvailability(PresentationTheme, String, Bool)
case privateLink(PresentationTheme, String, String?)
case editablePublicLink(PresentationTheme, String)
case editablePublicLink(PresentationTheme, String, String)
case privateLinkInfo(PresentationTheme, String)
case privateLinkCopy(PresentationTheme, String)
case privateLinkRevoke(PresentationTheme, String)
@ -168,8 +168,8 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
} else {
return false
}
case let .editablePublicLink(lhsTheme, lhsCurrentText):
if case let .editablePublicLink(rhsTheme, rhsCurrentText) = rhs, lhsTheme === rhsTheme, lhsCurrentText == rhsCurrentText {
case let .editablePublicLink(lhsTheme, lhsPlaceholder, lhsCurrentText):
if case let .editablePublicLink(rhsTheme, rhsPlaceholder, rhsCurrentText) = rhs, lhsTheme === rhsTheme, lhsPlaceholder == rhsPlaceholder, lhsCurrentText == rhsCurrentText {
return true
} else {
return false
@ -279,8 +279,8 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
arguments.displayPrivateLinkMenu(value)
}
}, tag: ChannelVisibilityEntryTag.privateLink)
case let .editablePublicLink(theme, currentText):
return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: "t.me/", textColor: theme.list.itemPrimaryTextColor), text: currentText, placeholder: "", tag: ChannelVisibilityEntryTag.publicLink, sectionId: self.section, textUpdated: { updatedText in
case let .editablePublicLink(theme, placeholder, currentText):
return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: "t.me/", textColor: theme.list.itemPrimaryTextColor), text: currentText, placeholder: placeholder, tag: ChannelVisibilityEntryTag.publicLink, sectionId: self.section, textUpdated: { updatedText in
arguments.updatePublicLinkText(currentText, updatedText)
}, receivedFocus: {
arguments.scrollToPublicLinkText()
@ -301,7 +301,7 @@ private enum ChannelVisibilityEntry: ItemListNodeEntry {
arguments.sharePrivateLink()
})
case let .publicLinkInfo(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
return ItemListTextItem(theme: theme, text: .markdown(text), sectionId: self.section)
case let .publicLinkStatus(theme, text, status):
var displayActivity = false
let color: UIColor
@ -356,7 +356,6 @@ private struct ChannelVisibilityControllerState: Equatable {
let revealedRevokePeerId: PeerId?
let revokingPeerId: PeerId?
let revokingPrivateLink: Bool
let editingLocation: CurrentChannelLocation?
init() {
self.selectedType = nil
@ -366,10 +365,9 @@ private struct ChannelVisibilityControllerState: Equatable {
self.revealedRevokePeerId = nil
self.revokingPeerId = nil
self.revokingPrivateLink = false
self.editingLocation = nil
}
init(selectedType: CurrentChannelType?, editingPublicLinkText: String?, addressNameValidationStatus: AddressNameValidationStatus?, updatingAddressName: Bool, revealedRevokePeerId: PeerId?, revokingPeerId: PeerId?, revokingPrivateLink: Bool, editingLocation: CurrentChannelLocation?) {
init(selectedType: CurrentChannelType?, editingPublicLinkText: String?, addressNameValidationStatus: AddressNameValidationStatus?, updatingAddressName: Bool, revealedRevokePeerId: PeerId?, revokingPeerId: PeerId?, revokingPrivateLink: Bool) {
self.selectedType = selectedType
self.editingPublicLinkText = editingPublicLinkText
self.addressNameValidationStatus = addressNameValidationStatus
@ -377,7 +375,6 @@ private struct ChannelVisibilityControllerState: Equatable {
self.revealedRevokePeerId = revealedRevokePeerId
self.revokingPeerId = revokingPeerId
self.revokingPrivateLink = revokingPrivateLink
self.editingLocation = editingLocation
}
static func ==(lhs: ChannelVisibilityControllerState, rhs: ChannelVisibilityControllerState) -> Bool {
@ -402,42 +399,35 @@ private struct ChannelVisibilityControllerState: Equatable {
if lhs.revokingPrivateLink != rhs.revokingPrivateLink {
return false
}
if lhs.editingLocation != rhs.editingLocation {
return false
}
return true
}
func withUpdatedSelectedType(_ selectedType: CurrentChannelType?) -> ChannelVisibilityControllerState {
return ChannelVisibilityControllerState(selectedType: selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: self.updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, editingLocation: self.editingLocation)
return ChannelVisibilityControllerState(selectedType: selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: self.updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink)
}
func withUpdatedEditingPublicLinkText(_ editingPublicLinkText: String?) -> ChannelVisibilityControllerState {
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: self.updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, editingLocation: self.editingLocation)
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: self.updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink)
}
func withUpdatedAddressNameValidationStatus(_ addressNameValidationStatus: AddressNameValidationStatus?) -> ChannelVisibilityControllerState {
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: addressNameValidationStatus, updatingAddressName: self.updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, editingLocation: self.editingLocation)
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: addressNameValidationStatus, updatingAddressName: self.updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink)
}
func withUpdatedUpdatingAddressName(_ updatingAddressName: Bool) -> ChannelVisibilityControllerState {
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, editingLocation: self.editingLocation)
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink)
}
func withUpdatedRevealedRevokePeerId(_ revealedRevokePeerId: PeerId?) -> ChannelVisibilityControllerState {
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, editingLocation: self.editingLocation)
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink)
}
func withUpdatedRevokingPeerId(_ revokingPeerId: PeerId?) -> ChannelVisibilityControllerState {
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, editingLocation: self.editingLocation)
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: revokingPeerId, revokingPrivateLink: self.revokingPrivateLink)
}
func withUpdatedRevokingPrivateLink(_ revokingPrivateLink: Bool) -> ChannelVisibilityControllerState {
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: revokingPrivateLink, editingLocation: self.editingLocation)
}
func withUpdatedEditingLocation(_ editingLocation: CurrentChannelLocation?) -> ChannelVisibilityControllerState {
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: self.revokingPrivateLink, editingLocation: editingLocation)
return ChannelVisibilityControllerState(selectedType: self.selectedType, editingPublicLinkText: self.editingPublicLinkText, addressNameValidationStatus: self.addressNameValidationStatus, updatingAddressName: updatingAddressName, revealedRevokePeerId: self.revealedRevokePeerId, revokingPeerId: self.revokingPeerId, revokingPrivateLink: revokingPrivateLink)
}
}
@ -534,7 +524,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_CreatePublicLinkHelp, true))
}
} else {
entries.append(.editablePublicLink(presentationData.theme, currentAddressName))
entries.append(.editablePublicLink(presentationData.theme, presentationData.strings.Group_PublicLink_Placeholder, currentAddressName))
if let status = state.addressNameValidationStatus {
let text: String
switch status {
@ -575,7 +565,11 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.publicLinkStatus(presentationData.theme, text, status))
}
if isGroup {
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePublicLinkHelp))
if let cachedChannelData = view.cachedData as? CachedChannelData, cachedChannelData.peerGeoLocation != nil {
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Group_PublicLink_Info))
} else {
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePublicLinkHelp))
}
} else {
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Channel_Username_CreatePublicLinkHelp))
}
@ -672,7 +666,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.publicLinkAvailability(presentationData.theme, presentationData.strings.Group_Username_CreatePublicLinkHelp, true))
}
} else {
entries.append(.editablePublicLink(presentationData.theme, currentAddressName))
entries.append(.editablePublicLink(presentationData.theme, "", currentAddressName))
if let status = state.addressNameValidationStatus {
let text: String
switch status {
@ -704,6 +698,7 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
entries.append(.publicLinkStatus(presentationData.theme, text, status))
}
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Group_Username_CreatePublicLinkHelp))
}
case .privateChannel:
@ -731,13 +726,15 @@ private func channelVisibilityControllerEntries(presentationData: PresentationDa
return entries
}
private func effectiveChannelType(state: ChannelVisibilityControllerState, peer: TelegramChannel) -> CurrentChannelType {
private func effectiveChannelType(state: ChannelVisibilityControllerState, peer: TelegramChannel, cachedData: CachedPeerData?) -> CurrentChannelType {
let selectedType: CurrentChannelType
if let current = state.selectedType {
selectedType = current
} else {
if let addressName = peer.addressName, !addressName.isEmpty {
selectedType = .publicChannel
} else if let cachedChannelData = cachedData as? CachedChannelData, cachedChannelData.peerGeoLocation != nil {
selectedType = .publicChannel
} else {
selectedType = .privateChannel
}
@ -745,9 +742,9 @@ private func effectiveChannelType(state: ChannelVisibilityControllerState, peer:
return selectedType
}
private func updatedAddressName(state: ChannelVisibilityControllerState, peer: Peer) -> String? {
private func updatedAddressName(state: ChannelVisibilityControllerState, peer: Peer, cachedData: CachedPeerData?) -> String? {
if let peer = peer as? TelegramChannel {
let selectedType = effectiveChannelType(state: state, peer: peer)
let selectedType = effectiveChannelType(state: state, peer: peer, cachedData: cachedData)
let currentAddressName: String
@ -828,9 +825,6 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
let updateAddressNameDisposable = MetaDisposable()
actionsDisposable.add(updateAddressNameDisposable)
let updateLocationDisposable = MetaDisposable()
actionsDisposable.add(updateLocationDisposable)
let revokeAddressNameDisposable = MetaDisposable()
actionsDisposable.add(revokeAddressNameDisposable)
@ -1002,37 +996,11 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
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?
var updatedLocation: CurrentChannelLocation?
updateState { state in
updatedAddressNameValue = updatedAddressName(state: state, peer: peer)
updatedLocation = state.editingLocation
updatedAddressNameValue = updatedAddressName(state: state, peer: peer, cachedData: view.cachedData)
return state
}
let updateLocation: (@escaping (Bool) -> Void) -> Void = { completion in
guard let updatedLocation = updatedLocation else {
completion(true)
return
}
switch updatedLocation {
case let .location(location):
updateLocationDisposable.set((updateChannelGeoLocation(postbox: context.account.postbox, network: context.account.network, channelId: peerId, coordinate: (location.latitude, location.longitude), address: location.address)
|> deliverOnMainQueue).start(error: { error in
completion(false)
}, completed: {
completion(true)
}))
case .removed:
updateLocationDisposable.set((updateChannelGeoLocation(postbox: context.account.postbox, network: context.account.network, channelId: peerId, coordinate: nil, address: nil)
|> deliverOnMainQueue).start(error: { error in
completion(false)
}, completed: {
completion(true)
}))
}
}
if let updatedAddressNameValue = updatedAddressNameValue {
let invokeAction: () -> Void = {
updateState { state in
@ -1051,15 +1019,12 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
updateState { state in
return state.withUpdatedUpdatingAddressName(false)
}
updateLocation({ success in
switch mode {
case .initialSetup:
nextImpl?()
case .generic, .privateLink:
dismissImpl?()
}
})
switch mode {
case .initialSetup:
nextImpl?()
case .generic, .privateLink:
dismissImpl?()
}
}))
}
@ -1072,14 +1037,12 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
}
})
} else {
updateLocation({ success in
switch mode {
case .initialSetup:
nextImpl?()
case .generic, .privateLink:
dismissImpl?()
}
})
switch mode {
case .initialSetup:
nextImpl?()
case .generic, .privateLink:
dismissImpl?()
}
}
})
} else if let peer = peer as? TelegramGroup {
@ -1105,7 +1068,7 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: state.updatingAddressName ? .activity : .bold, enabled: doneEnabled, action: {
var updatedAddressNameValue: String?
updateState { state in
updatedAddressNameValue = updatedAddressName(state: state, peer: peer)
updatedAddressNameValue = updatedAddressName(state: state, peer: peer, cachedData: nil)
return state
}
@ -1224,7 +1187,11 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
if case .privateLink = mode {
title = presentationData.strings.GroupInfo_InviteLink_Title
} else {
title = isGroup ? presentationData.strings.GroupInfo_GroupType : presentationData.strings.Channel_TypeSetup_Title
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
}
}
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(entries: channelVisibilityControllerEntries(presentationData: presentationData, mode: mode, view: view, publicChannelsToRevoke: publicChannelsToRevoke, state: state), style: .blocks, crossfadeState: crossfade, animateChanges: false)

View file

@ -260,7 +260,7 @@ public func createChannelController(context: AccountContext) -> ViewController {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let text: String
switch error {
case .generic:
case .generic, .tooMuchLocationBasedGroups:
text = presentationData.strings.Login_UnknownError
case .restricted:
text = presentationData.strings.Common_ActionNotAllowedError

View file

@ -356,6 +356,8 @@ public func createGroupController(context: AccountContext, peerIds: [PeerId], in
return .generic
case .restricted:
return .restricted
case .tooMuchLocationBasedGroups:
return .tooMuchLocationBasedGroups
}
}
case .locatedGroup:
@ -377,6 +379,8 @@ public func createGroupController(context: AccountContext, peerIds: [PeerId], in
return .generic
case .restricted:
return .restricted
case .tooMuchLocationBasedGroups:
return .tooMuchLocationBasedGroups
}
}
}
@ -436,6 +440,8 @@ public func createGroupController(context: AccountContext, peerIds: [PeerId], in
text = presentationData.strings.Login_UnknownError
case .restricted:
text = presentationData.strings.Common_ActionNotAllowedError
case .tooMuchLocationBasedGroups:
text = presentationData.strings.CreateGroup_ErrorLocatedGroupsTooMuch
}
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}))

View file

@ -1563,7 +1563,7 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
}
} else if let channel = groupPeer as? TelegramChannel {
if channel.hasPermission(.inviteMembers) {
if channel.adminRights != nil {
if channel.flags.contains(.isCreator) || channel.adminRights != nil {
canCreateInviteLink = true
}
}
@ -1772,8 +1772,13 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
inviteByLinkImpl = { [weak contactsController] in
contactsController?.dismiss()
presentControllerImpl?(channelVisibilityController(context: context, peerId: peerView.peerId, mode: .privateLink, upgradedToSupergroup: { updatedPeerId, f in
let mode: ChannelVisibilityControllerMode
if groupPeer.addressName != nil {
mode = .generic
} else {
mode = .privateLink
}
presentControllerImpl?(channelVisibilityController(context: context, peerId: peerView.peerId, mode: mode, upgradedToSupergroup: { updatedPeerId, f in
upgradedToSupergroupImpl?(updatedPeerId, f)
}), ViewControllerPresentationArguments(presentationAnimation: ViewControllerPresentationAnimation.modalSheet))
}

View file

@ -91,6 +91,7 @@ class ItemListAddressItemNode: ListViewItemNode {
private let bottomStripeNode: ASDisplayNode
private let highlightedBackgroundNode: ASDisplayNode
private let imageNode: TransformImageNode
private let iconNode: ASImageNode
private var selectionNode: ItemListSelectableControlNode?
var item: ItemListAddressItem?
@ -125,11 +126,14 @@ class ItemListAddressItemNode: ListViewItemNode {
self.imageNode = TransformImageNode()
self.imageNode.contentAnimations = [.firstUpdate, .subsequentUpdates]
self.iconNode = ASImageNode()
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.labelNode)
self.addSubnode(self.textNode)
self.addSubnode(self.imageNode)
self.addSubnode(self.iconNode)
}
func asyncLayout() -> (_ item: ItemListAddressItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) {
@ -204,6 +208,10 @@ class ItemListAddressItemNode: ListViewItemNode {
strongSelf.imageNode.clearContents()
}
if strongSelf.iconNode.image == nil {
strongSelf.iconNode.image = UIImage(bundleImageName: "Peer Info/LocationIcon")
}
if let _ = updatedTheme {
strongSelf.topStripeNode.backgroundColor = itemSeparatorColor
strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor
@ -237,7 +245,13 @@ class ItemListAddressItemNode: ListViewItemNode {
strongSelf.labelNode.frame = CGRect(origin: CGPoint(x: leftOffset + leftInset, y: 11.0), size: labelLayout.size)
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftOffset + leftInset, y: item.label.isEmpty ? 11.0 : 31.0), size: textLayout.size)
strongSelf.imageNode.frame = CGRect(origin: CGPoint(x: params.width - imageSize.width - rightInset, y: floorToScreenPixels((contentSize.height - imageSize.height) / 2.0)), size: imageSize)
let imageFrame = CGRect(origin: CGPoint(x: params.width - imageSize.width - rightInset, y: floorToScreenPixels((contentSize.height - imageSize.height) / 2.0)), size: imageSize)
strongSelf.imageNode.frame = imageFrame
if let icon = strongSelf.iconNode.image {
strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: imageFrame.minX + floorToScreenPixels((imageFrame.width - icon.size.width) / 2.0), y: imageFrame.minY + floorToScreenPixels((imageFrame.height - icon.size.height) / 2.0) - 7.0), size: icon.size)
}
let leftInset: CGFloat
switch item.style {

View file

@ -244,23 +244,26 @@ final class PeerChannelMemberCategoriesContextsManager {
}
}
func transferOwnership(account: Account, peerId: PeerId, memberId: PeerId, password: String) -> Signal<Never, ChannelOwnershipTransferError> {
return updateChannelOwnership(postbox: account.postbox, network: account.network, accountStateManager: account.stateManager, channelId: peerId, memberId: memberId, password: password)
func transferOwnership(account: Account, peerId: PeerId, memberId: PeerId, password: String) -> Signal<Void, ChannelOwnershipTransferError> {
return updateChannelOwnership(account: account, accountStateManager: account.stateManager, channelId: peerId, memberId: memberId, password: password)
|> map(Optional.init)
|> deliverOnMainQueue
// |> beforeNext { [weak self] result in
// if let strongSelf = self, let (previous, updated) = result {
// strongSelf.impl.with { impl in
// for (contextPeerId, context) in impl.contexts {
// if peerId == contextPeerId {
// context.replayUpdates([(previous, updated, nil)])
// }
// }
// }
// }
// }
// |> mapToSignal { _ -> Signal<Void, ChannelOwnershipTransferError> in
// return .complete()
// }
|> beforeNext { [weak self] results in
if let strongSelf = self, let results = results {
strongSelf.impl.with { impl in
for (contextPeerId, context) in impl.contexts {
if peerId == contextPeerId {
for (previous, updated) in results {
context.replayUpdates([(previous, updated, nil)])
}
}
}
}
}
}
|> mapToSignal { _ -> Signal<Void, ChannelOwnershipTransferError> in
return .complete()
}
}
func join(account: Account, peerId: PeerId) -> Signal<Never, JoinChannelError> {

View file

@ -313,6 +313,8 @@ public func peersNearbyController(context: AccountContext) -> ViewController {
return .single(nil)
}
print("TTTTT: \(CFAbsoluteTimeGetCurrent())")
return Signal { subscriber in
let peersNearbyContext = PeersNearbyContext(network: context.account.network, accountStateManager: context.account.stateManager, coordinate: (latitude: coordinate.latitude, longitude: coordinate.longitude))
@ -373,12 +375,25 @@ public func peersNearbyController(context: AccountContext) -> ViewController {
return value != nil
}
dataPromise.set(.single(nil) |> then(combinedSignal))
let previousData = Atomic<PeersNearbyData?>(value: nil)
let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get())
|> deliverOnMainQueue
|> map { presentationData, data -> (ItemListControllerState, (ItemListNodeState<PeersNearbyEntry>, PeersNearbyEntry.ItemGenerationArguments)) in
let previous = previousData.swap(data)
var crossfade = false
if (data?.users.isEmpty ?? true) != (previous?.users.isEmpty ?? true) {
crossfade = true
}
if (data?.groups.isEmpty ?? true) != (previous?.groups.isEmpty ?? true) {
crossfade = true
}
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.PeopleNearby_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(entries: peersNearbyControllerEntries(data: data, presentationData: presentationData), style: .blocks, emptyStateItem: nil, crossfadeState: false, animateChanges: true, userInteractionEnabled: true)
let listState = ItemListNodeState(entries: peersNearbyControllerEntries(data: data, presentationData: presentationData), style: .blocks, emptyStateItem: nil, crossfadeState: crossfade, animateChanges: !crossfade, userInteractionEnabled: true)
return (controllerState, (listState, arguments))
}

View file

@ -57,6 +57,7 @@ public enum ThemeSettingsEntryTag: ItemListItemTag {
}
private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
case themeListHeader(PresentationTheme, String)
case fontSizeHeader(PresentationTheme, String)
case fontSize(PresentationTheme, PresentationFontSize)
case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder)
@ -73,7 +74,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
var section: ItemListSectionId {
switch self {
case .chatPreview, .themeItem, .accentColor:
case .themeListHeader, .chatPreview, .themeItem, .accentColor:
return ThemeSettingsControllerSection.chatPreview.rawValue
case .fontSizeHeader, .fontSize:
return ThemeSettingsControllerSection.fontSize.rawValue
@ -88,32 +89,34 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
var stableId: Int32 {
switch self {
case .chatPreview:
case .themeListHeader:
return 0
case .themeItem:
case .chatPreview:
return 1
case .accentColor:
case .themeItem:
return 2
case .wallpaper:
case .accentColor:
return 3
case .autoNightTheme:
case .wallpaper:
return 4
case .fontSizeHeader:
case .autoNightTheme:
return 5
case .fontSize:
case .fontSizeHeader:
return 6
case .iconHeader:
case .fontSize:
return 7
case .iconItem:
case .iconHeader:
return 8
case .otherHeader:
case .iconItem:
return 9
case .largeEmoji:
case .otherHeader:
return 10
case .animations:
case .largeEmoji:
return 11
case .animationsInfo:
case .animations:
return 12
case .animationsInfo:
return 13
}
}
@ -143,6 +146,12 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
} else {
return false
}
case let .themeListHeader(lhsTheme, lhsText):
if case let .themeListHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .themeItem(lhsTheme, lhsStrings, lhsThemes, lhsCurrentTheme, lhsThemeAccentColor):
if case let .themeItem(rhsTheme, rhsStrings, rhsThemes, rhsCurrentTheme, rhsThemeAccentColor) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsThemes == rhsThemes, lhsCurrentTheme == rhsCurrentTheme, lhsThemeAccentColor == rhsThemeAccentColor {
return true
@ -226,6 +235,8 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
return ItemListDisclosureItem(theme: theme, icon: nil, title: text, label: value, labelStyle: .text, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
arguments.openAutoNightTheme()
})
case let .themeListHeader(theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .themeItem(theme, strings, themes, currentTheme, themeAccentColor):
return ThemeSettingsThemeItem(theme: theme, strings: strings, sectionId: self.section, themes: themes.map { ($0, $0 == .day ? themeAccentColor : nil) }, currentTheme: currentTheme, updated: { theme in
arguments.selectTheme(theme.rawValue)
@ -255,6 +266,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
private func themeSettingsControllerEntries(presentationData: PresentationData, theme: PresentationTheme, themeAccentColor: Int32?, autoNightSettings: AutomaticThemeSwitchSetting, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, largeEmoji: Bool, disableAnimations: Bool, availableAppIcons: [PresentationAppIcon], currentAppIconName: String?) -> [ThemeSettingsControllerEntry] {
var entries: [ThemeSettingsControllerEntry] = []
entries.append(.themeListHeader(presentationData.theme, strings.Appearance_ColorTheme.uppercased()))
entries.append(.chatPreview(presentationData.theme, theme, wallpaper, fontSize, presentationData.strings, dateTimeFormat, presentationData.nameDisplayOrder))
if case let .builtin(theme) = theme.name {
entries.append(.themeItem(presentationData.theme, presentationData.strings, [.dayClassic, .day, .nightAccent, .nightGrayscale], theme.reference, themeAccentColor != nil ? UIColor(rgb: UInt32(bitPattern: themeAccentColor!)) : nil))