mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Peers Nearby improvements and bug fixes
This commit is contained in:
parent
7d5815f329
commit
653ed2993e
24 changed files with 3028 additions and 2918 deletions
|
|
@ -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.";
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
BIN
submodules/TelegramUI/Images.xcassets/Peer Info/LocationIcon.imageset/Artboard Copy@2x.png
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Peer Info/LocationIcon.imageset/Artboard Copy@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
BIN
submodules/TelegramUI/Images.xcassets/Peer Info/LocationIcon.imageset/Artboard Copy@3x.png
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Peer Info/LocationIcon.imageset/Artboard Copy@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
22
submodules/TelegramUI/Images.xcassets/Peer Info/LocationIcon.imageset/Contents.json
vendored
Normal file
22
submodules/TelegramUI/Images.xcassets/Peer Info/LocationIcon.imageset/Contents.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue