Various fixes

This commit is contained in:
Ilya Laktyushin 2023-01-19 17:00:41 +04:00
parent ab9d4748ec
commit 587d700978
5 changed files with 232 additions and 20 deletions

View File

@ -8660,7 +8660,7 @@ Sorry for the inconvenience.";
"RequestPeer.Requirement.Group.Rights.Delete" = "delete messages";
"RequestPeer.Requirement.Group.Rights.Edit" = "edit messages";
"RequestPeer.Requirement.Group.Rights.Ban" = "ban users";
"RequestPeer.Requirement.Group.Rights.Invite" = "invite users via link";
"RequestPeer.Requirement.Group.Rights.Invite" = "add members";
"RequestPeer.Requirement.Group.Rights.Pin" = "pin messages";
"RequestPeer.Requirement.Group.Rights.Topics" = "manage topics";
"RequestPeer.Requirement.Group.Rights.VideoChats" = "manage video chats";

View File

@ -461,7 +461,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
}
}
public func item(context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, location: ChatListControllerLocation, key: ChatListSearchPaneKey, tagMask: EngineMessage.Tags?, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (EnginePeer) -> Void, searchQuery: String?, searchOptions: ChatListSearchOptions?, messageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void)?, openClearRecentlyDownloaded: @escaping () -> Void, toggleAllPaused: @escaping () -> Void) -> ListViewItem {
public func item(context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, requestPeerType: ReplyMarkupButtonRequestPeerType?, location: ChatListControllerLocation, key: ChatListSearchPaneKey, tagMask: EngineMessage.Tags?, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (EnginePeer) -> Void, searchQuery: String?, searchOptions: ChatListSearchOptions?, messageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void)?, openClearRecentlyDownloaded: @escaping () -> Void, toggleAllPaused: @escaping () -> Void) -> ListViewItem {
switch self {
case let .topic(peer, threadInfo, _, theme, strings, expandType):
let actionTitle: String?
@ -621,7 +621,11 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
if filter.contains(.onlyGroups) {
headerType = .chats
} else {
headerType = .localPeers
if let _ = requestPeerType {
headerType = .chats
} else {
headerType = .localPeers
}
}
header = ChatListSearchItemHeader(type: headerType, theme: theme, strings: strings, actionTitle: actionTitle, action: actionTitle == nil ? nil : {
toggleExpandLocalResults()
@ -826,12 +830,12 @@ private func chatListSearchContainerPreparedRecentTransition(from fromEntries: [
return ChatListSearchContainerRecentTransition(deletions: deletions, insertions: insertions, updates: updates)
}
public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatListSearchEntry], to toEntries: [ChatListSearchEntry], displayingResults: Bool, isEmpty: Bool, isLoading: Bool, animated: Bool, context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, location: ChatListControllerLocation, key: ChatListSearchPaneKey, tagMask: EngineMessage.Tags?, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (EnginePeer) -> Void, searchQuery: String?, searchOptions: ChatListSearchOptions?, messageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void)?, openClearRecentlyDownloaded: @escaping () -> Void, toggleAllPaused: @escaping () -> Void) -> ChatListSearchContainerTransition {
public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatListSearchEntry], to toEntries: [ChatListSearchEntry], displayingResults: Bool, isEmpty: Bool, isLoading: Bool, animated: Bool, context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, requestPeerType: ReplyMarkupButtonRequestPeerType?, location: ChatListControllerLocation, key: ChatListSearchPaneKey, tagMask: EngineMessage.Tags?, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (EnginePeer) -> Void, searchQuery: String?, searchOptions: ChatListSearchOptions?, messageContextAction: ((EngineMessage, ASDisplayNode?, CGRect?, UIGestureRecognizer?, ChatListSearchPaneKey, (id: String, size: Int64, isFirstInList: Bool)?) -> Void)?, openClearRecentlyDownloaded: @escaping () -> Void, toggleAllPaused: @escaping () -> Void) -> ChatListSearchContainerTransition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, location: location, key: key, tagMask: tagMask, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, searchPeer: searchPeer, searchQuery: searchQuery, searchOptions: searchOptions, messageContextAction: messageContextAction, openClearRecentlyDownloaded: openClearRecentlyDownloaded, toggleAllPaused: toggleAllPaused), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, location: location, key: key, tagMask: tagMask, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, searchPeer: searchPeer, searchQuery: searchQuery, searchOptions: searchOptions, messageContextAction: messageContextAction, openClearRecentlyDownloaded: openClearRecentlyDownloaded, toggleAllPaused: toggleAllPaused), directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, requestPeerType: requestPeerType, location: location, key: key, tagMask: tagMask, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, searchPeer: searchPeer, searchQuery: searchQuery, searchOptions: searchOptions, messageContextAction: messageContextAction, openClearRecentlyDownloaded: openClearRecentlyDownloaded, toggleAllPaused: toggleAllPaused), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, requestPeerType: requestPeerType, location: location, key: key, tagMask: tagMask, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, searchPeer: searchPeer, searchQuery: searchQuery, searchOptions: searchOptions, messageContextAction: messageContextAction, openClearRecentlyDownloaded: openClearRecentlyDownloaded, toggleAllPaused: toggleAllPaused), directionHint: nil) }
return ChatListSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, displayingResults: displayingResults, isEmpty: isEmpty, isLoading: isLoading, query: searchQuery, animated: animated)
}
@ -2269,7 +2273,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
let animated = selectionChanged || expandGlobalSearchChanged
let firstTime = previousEntries == nil
var transition = chatListSearchContainerPreparedTransition(from: previousEntries ?? [], to: newEntries, displayingResults: entriesAndFlags != nil, isEmpty: !isSearching && (entriesAndFlags?.isEmpty ?? false), isLoading: isSearching, animated: animated, context: context, presentationData: strongSelf.presentationData, enableHeaders: true, filter: peersFilter, location: location, key: strongSelf.key, tagMask: tagMask, interaction: chatListInteraction, listInteraction: listInteraction, peerContextAction: { message, node, rect, gesture, location in
var transition = chatListSearchContainerPreparedTransition(from: previousEntries ?? [], to: newEntries, displayingResults: entriesAndFlags != nil, isEmpty: !isSearching && (entriesAndFlags?.isEmpty ?? false), isLoading: isSearching, animated: animated, context: context, presentationData: strongSelf.presentationData, enableHeaders: true, filter: peersFilter, requestPeerType: requestPeerType, location: location, key: strongSelf.key, tagMask: tagMask, interaction: chatListInteraction, listInteraction: listInteraction, peerContextAction: { message, node, rect, gesture, location in
interaction.peerContextAction?(message, node, rect, gesture, location)
}, toggleExpandLocalResults: {
guard let strongSelf = self else {

View File

@ -113,7 +113,7 @@ public final class HashtagSearchController: TelegramBaseController {
})
let firstTime = previousEntries == nil
let transition = chatListSearchContainerPreparedTransition(from: previousEntries ?? [], to: entries, displayingResults: true, isEmpty: entries.isEmpty, isLoading: false, animated: false, context: strongSelf.context, presentationData: strongSelf.presentationData, enableHeaders: false, filter: [], location: .chatList(groupId: .root), key: .chats, tagMask: nil, interaction: interaction, listInteraction: listInteraction, peerContextAction: nil, toggleExpandLocalResults: {
let transition = chatListSearchContainerPreparedTransition(from: previousEntries ?? [], to: entries, displayingResults: true, isEmpty: entries.isEmpty, isLoading: false, animated: false, context: strongSelf.context, presentationData: strongSelf.presentationData, enableHeaders: false, filter: [], requestPeerType: nil, location: .chatList(groupId: .root), key: .chats, tagMask: nil, interaction: interaction, listInteraction: listInteraction, peerContextAction: nil, toggleExpandLocalResults: {
}, toggleExpandGlobalResults: {
}, searchPeer: { _ in
}, searchQuery: "", searchOptions: nil, messageContextAction: nil, openClearRecentlyDownloaded: {}, toggleAllPaused: {})

View File

@ -17,6 +17,7 @@ import WebSearchUI
import PeerInfoUI
import MapResourceToAvatarSizes
import LegacyMediaPickerUI
import TextFormat
private struct CreateChannelArguments {
let context: AccountContext
@ -26,11 +27,14 @@ private struct CreateChannelArguments {
let done: () -> Void
let changeProfilePhoto: () -> Void
let focusOnDescription: () -> Void
let updatePublicLinkText: (String) -> Void
let openAuction: (String) -> Void
}
private enum CreateChannelSection: Int32 {
case info
case description
case username
}
private enum CreateChannelEntryTag: ItemListItemTag {
@ -62,16 +66,23 @@ private enum CreateChannelEntryTag: ItemListItemTag {
private enum CreateChannelEntry: ItemListNodeEntry {
case channelInfo(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer?, ItemListAvatarAndNameInfoItemState, ItemListAvatarAndNameInfoItemUpdatingAvatar?)
case setProfilePhoto(PresentationTheme, String)
case descriptionSetup(PresentationTheme, String, String)
case descriptionInfo(PresentationTheme, String)
case usernameHeader(PresentationTheme, String)
case username(PresentationTheme, String, String)
case usernameStatus(PresentationTheme, String, AddressNameValidationStatus, String, String)
case usernameInfo(PresentationTheme, String)
var section: ItemListSectionId {
switch self {
case .channelInfo, .setProfilePhoto:
return CreateChannelSection.info.rawValue
case .descriptionSetup, .descriptionInfo:
return CreateChannelSection.description.rawValue
case .usernameHeader, .username, .usernameStatus, .usernameInfo:
return CreateChannelSection.username.rawValue
}
}
@ -85,6 +96,14 @@ private enum CreateChannelEntry: ItemListNodeEntry {
return 2
case .descriptionInfo:
return 3
case .usernameHeader:
return 4
case .username:
return 5
case .usernameStatus:
return 6
case .usernameInfo:
return 7
}
}
@ -136,6 +155,30 @@ private enum CreateChannelEntry: ItemListNodeEntry {
} else {
return false
}
case let .usernameHeader(lhsTheme, lhsText):
if case let .usernameHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .username(lhsTheme, lhsText, lhsValue):
if case let .username(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .usernameStatus(lhsTheme, lhsAddressName, lhsStatus, lhsText, lhsUsername):
if case let .usernameStatus(rhsTheme, rhsAddressName, rhsStatus, rhsText, rhsUsername) = rhs, lhsTheme === rhsTheme, lhsAddressName == rhsAddressName, lhsStatus == rhsStatus, lhsText == rhsText, lhsUsername == rhsUsername {
return true
} else {
return false
}
case let .usernameInfo(lhsTheme, lhsText):
if case let .usernameInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
}
}
@ -164,6 +207,37 @@ private enum CreateChannelEntry: ItemListNodeEntry {
}, tag: CreateChannelEntryTag.description)
case let .descriptionInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
case let .usernameHeader(_, title):
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
case let .username(theme, placeholder, text):
return ItemListSingleLineInputItem(presentationData: presentationData, title: NSAttributedString(string: "t.me/", textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: placeholder, type: .username, clearType: .always, tag: nil, sectionId: self.section, textUpdated: { updatedText in
arguments.updatePublicLinkText(updatedText)
}, action: {
})
case let .usernameStatus(_, _, status, text, username):
var displayActivity = false
let textColor: ItemListActivityTextItem.TextColor
switch status {
case .invalidFormat:
textColor = .destructive
case let .availability(availability):
switch availability {
case .available:
textColor = .constructive
case .purchaseAvailable:
textColor = .generic
case .invalid, .taken:
textColor = .destructive
}
case .checking:
textColor = .generic
displayActivity = true
}
return ItemListActivityTextItem(displayActivity: displayActivity, presentationData: presentationData, text: text, color: textColor, linkAction: { _ in
arguments.openAuction(username)
}, sectionId: self.section)
case let .usernameInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section)
}
}
}
@ -173,6 +247,8 @@ private struct CreateChannelState: Equatable {
var editingName: ItemListAvatarAndNameInfoItemName
var editingDescriptionText: String
var avatar: ItemListAvatarAndNameInfoItemUpdatingAvatar?
var editingPublicLinkText: String?
var addressNameValidationStatus: AddressNameValidationStatus?
static func ==(lhs: CreateChannelState, rhs: CreateChannelState) -> Bool {
if lhs.creating != rhs.creating {
@ -187,11 +263,17 @@ private struct CreateChannelState: Equatable {
if lhs.avatar != rhs.avatar {
return false
}
if lhs.editingPublicLinkText != rhs.editingPublicLinkText {
return false
}
if lhs.addressNameValidationStatus != rhs.addressNameValidationStatus {
return false
}
return true
}
}
private func CreateChannelEntries(presentationData: PresentationData, state: CreateChannelState) -> [CreateChannelEntry] {
private func CreateChannelEntries(presentationData: PresentationData, state: CreateChannelState, requestPeer: ReplyMarkupButtonRequestPeerType.Channel?) -> [CreateChannelEntry] {
var entries: [CreateChannelEntry] = []
let groupInfoState = ItemListAvatarAndNameInfoItemState(editingName: state.editingName, updatingName: nil)
@ -203,6 +285,55 @@ private func CreateChannelEntries(presentationData: PresentationData, state: Cre
entries.append(.descriptionSetup(presentationData.theme, presentationData.strings.Channel_Edit_AboutItem, state.editingDescriptionText))
entries.append(.descriptionInfo(presentationData.theme, presentationData.strings.Channel_About_Help))
if let requestPeer {
if let hasUsername = requestPeer.hasUsername, hasUsername {
let currentUsername = state.editingPublicLinkText ?? ""
entries.append(.usernameHeader(presentationData.theme, presentationData.strings.CreateGroup_PublicLinkTitle.uppercased()))
entries.append(.username(presentationData.theme, presentationData.strings.Group_PublicLink_Placeholder, currentUsername))
if let status = state.addressNameValidationStatus {
let statusText: String
switch status {
case let .invalidFormat(error):
switch error {
case .startsWithDigit:
statusText = presentationData.strings.Username_InvalidStartsWithNumber
case .startsWithUnderscore:
statusText = presentationData.strings.Username_InvalidStartsWithUnderscore
case .endsWithUnderscore:
statusText = presentationData.strings.Username_InvalidEndsWithUnderscore
case .invalidCharacters:
statusText = presentationData.strings.Username_InvalidCharacters
case .tooShort:
statusText = presentationData.strings.Username_InvalidTooShort
}
case let .availability(availability):
switch availability {
case .available:
statusText = presentationData.strings.Username_UsernameIsAvailable(currentUsername).string
case .invalid:
statusText = presentationData.strings.Username_InvalidCharacters
case .taken:
statusText = presentationData.strings.Username_InvalidTaken
case .purchaseAvailable:
var markdownString = presentationData.strings.Username_UsernamePurchaseAvailable
let entities = generateTextEntities(markdownString, enabledTypes: [.mention])
if let entity = entities.first {
markdownString.insert(contentsOf: "]()", at: markdownString.index(markdownString.startIndex, offsetBy: entity.range.upperBound))
markdownString.insert(contentsOf: "[", at: markdownString.index(markdownString.startIndex, offsetBy: entity.range.lowerBound))
}
statusText = markdownString
}
case .checking:
statusText = presentationData.strings.Username_CheckingUsername
}
entries.append(.usernameStatus(presentationData.theme, currentUsername, status, statusText, currentUsername))
}
entries.append(.usernameInfo(presentationData.theme, presentationData.strings.CreateGroup_PublicLinkInfo))
}
}
return entries
}
@ -222,6 +353,7 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
var replaceControllerImpl: ((ViewController) -> Void)?
var pushControllerImpl: ((ViewController) -> Void)?
var presentControllerImpl: ((ViewController, Any?) -> Void)?
var dismissImpl: (() -> Void)?
var endEditingImpl: (() -> Void)?
var focusOnDescriptionImpl: (() -> Void)?
@ -232,6 +364,14 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
let uploadedAvatar = Promise<UploadedPeerPhotoData>()
var uploadedVideoAvatar: (Promise<UploadedPeerPhotoData?>, Double?)? = nil
let checkAddressNameDisposable = MetaDisposable()
actionsDisposable.add(checkAddressNameDisposable)
var requestPeer: ReplyMarkupButtonRequestPeerType.Channel?
if case let .requestPeer(peerType) = mode {
requestPeer = peerType
}
let arguments = CreateChannelArguments(context: context, updateEditingName: { editingName in
updateState { current in
var current = current
@ -250,8 +390,8 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
return current
}
}, done: {
let (creating, title, description) = stateValue.with { state -> (Bool, String, String) in
return (state.creating, state.editingName.composedTitle, state.editingDescriptionText)
let (creating, title, description, publicLink) = stateValue.with { state -> (Bool, String, String, String?) in
return (state.creating, state.editingName.composedTitle, state.editingDescriptionText, state.editingPublicLinkText)
}
if !creating && !title.isEmpty {
@ -263,7 +403,23 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
}
endEditingImpl?()
actionsDisposable.add((context.engine.peers.createChannel(title: title, description: description.isEmpty ? nil : description)
var createSignal: Signal<PeerId, CreateChannelError> = context.engine.peers.createChannel(title: title, description: description.isEmpty ? nil : description)
if case .requestPeer = mode {
if let publicLink, !publicLink.isEmpty {
createSignal = createSignal
|> mapToSignal { peerId in
return context.engine.peers.updateAddressName(domain: .peer(peerId), name: publicLink)
|> mapError { _ in
return .generic
}
|> map { _ in
return peerId
}
}
}
}
actionsDisposable.add((createSignal
|> deliverOnMainQueue
|> afterDisposed {
Queue.mainQueue().async {
@ -283,8 +439,14 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
}).start()
}
let controller = channelVisibilityController(context: context, peerId: peerId, mode: .initialSetup, upgradedToSupergroup: { _, f in f() })
replaceControllerImpl?(controller)
if case .requestPeer = mode {
completion?(peerId, {
dismissImpl?()
})
} else {
let controller = channelVisibilityController(context: context, peerId: peerId, mode: .initialSetup, upgradedToSupergroup: { _, f in f() })
replaceControllerImpl?(controller)
}
}, error: { error in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let text: String?
@ -504,21 +666,57 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
})
}, focusOnDescription: {
focusOnDescriptionImpl?()
}, updatePublicLinkText: { text in
if text.isEmpty {
checkAddressNameDisposable.set(nil)
updateState { state in
var updated = state
updated.editingPublicLinkText = text
updated.addressNameValidationStatus = nil
return updated
}
} else {
updateState { state in
var updated = state
updated.editingPublicLinkText = text
return updated
}
checkAddressNameDisposable.set((context.engine.peers.validateAddressNameInteractive(domain: .peer(PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(0))), name: text)
|> deliverOnMainQueue).start(next: { result in
updateState { state in
var updated = state
updated.addressNameValidationStatus = result
return updated
}
}))
}
}, openAuction: { username in
endEditingImpl?()
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: "https://fragment.com/username/\(username)", forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {})
})
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get())
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
let rightNavigationButton: ItemListNavigationButton
if state.creating {
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
} else {
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Next), style: .bold, enabled: !state.editingName.composedTitle.isEmpty, action: {
var isEnabled = true
if state.editingName.composedTitle.isEmpty {
isEnabled = false
}
if case let .requestPeer(peerType) = mode, let hasUsername = peerType.hasUsername, hasUsername, (state.editingPublicLinkText ?? "").isEmpty {
isEnabled = false
}
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Next), style: .bold, enabled: isEnabled, action: {
arguments.done()
})
}
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.ChannelIntro_CreateChannel), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: CreateChannelEntries(presentationData: presentationData, state: state), style: .blocks, focusItemTag: CreateChannelEntryTag.info)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: CreateChannelEntries(presentationData: presentationData, state: state, requestPeer: requestPeer), style: .blocks, focusItemTag: CreateChannelEntryTag.info)
return (controllerState, (listState, arguments))
} |> afterDisposed {
@ -535,6 +733,9 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
presentControllerImpl = { [weak controller] c, a in
controller?.present(c, in: .window(.root), with: a)
}
dismissImpl = { [weak controller] in
controller?.dismiss()
}
controller.willDisappear = { _ in
endEditingImpl?()
}

View File

@ -415,7 +415,7 @@ private func createGroupEntries(presentationData: PresentationData, state: Creat
if let hasUsername = requestPeer.hasUsername, hasUsername {
let currentUsername = state.editingPublicLinkText ?? ""
entries.append(.usernameHeader(presentationData.theme, presentationData.strings.CreateGroup_PublicLinkTitle.uppercased()))
entries.append(.username(presentationData.theme, "link", currentUsername))
entries.append(.username(presentationData.theme, presentationData.strings.Group_PublicLink_Placeholder, currentUsername))
if let status = state.addressNameValidationStatus {
let statusText: String
@ -1180,7 +1180,14 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
if state.creating {
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
} else {
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Compose_Create), style: .bold, enabled: !state.editingName.composedTitle.isEmpty, action: {
var isEnabled = true
if state.editingName.composedTitle.isEmpty {
isEnabled = false
}
if case let .requestPeer(peerType) = mode, let hasUsername = peerType.hasUsername, hasUsername, (state.editingPublicLinkText ?? "").isEmpty {
isEnabled = false
}
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Compose_Create), style: .bold, enabled: isEnabled, action: {
arguments.done()
})
}