mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Various fixes
This commit is contained in:
parent
ab9d4748ec
commit
587d700978
@ -8660,7 +8660,7 @@ Sorry for the inconvenience.";
|
|||||||
"RequestPeer.Requirement.Group.Rights.Delete" = "delete messages";
|
"RequestPeer.Requirement.Group.Rights.Delete" = "delete messages";
|
||||||
"RequestPeer.Requirement.Group.Rights.Edit" = "edit messages";
|
"RequestPeer.Requirement.Group.Rights.Edit" = "edit messages";
|
||||||
"RequestPeer.Requirement.Group.Rights.Ban" = "ban users";
|
"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.Pin" = "pin messages";
|
||||||
"RequestPeer.Requirement.Group.Rights.Topics" = "manage topics";
|
"RequestPeer.Requirement.Group.Rights.Topics" = "manage topics";
|
||||||
"RequestPeer.Requirement.Group.Rights.VideoChats" = "manage video chats";
|
"RequestPeer.Requirement.Group.Rights.VideoChats" = "manage video chats";
|
||||||
|
@ -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 {
|
switch self {
|
||||||
case let .topic(peer, threadInfo, _, theme, strings, expandType):
|
case let .topic(peer, threadInfo, _, theme, strings, expandType):
|
||||||
let actionTitle: String?
|
let actionTitle: String?
|
||||||
@ -621,7 +621,11 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
if filter.contains(.onlyGroups) {
|
if filter.contains(.onlyGroups) {
|
||||||
headerType = .chats
|
headerType = .chats
|
||||||
} else {
|
} 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 : {
|
header = ChatListSearchItemHeader(type: headerType, theme: theme, strings: strings, actionTitle: actionTitle, action: actionTitle == nil ? nil : {
|
||||||
toggleExpandLocalResults()
|
toggleExpandLocalResults()
|
||||||
@ -826,12 +830,12 @@ private func chatListSearchContainerPreparedRecentTransition(from fromEntries: [
|
|||||||
return ChatListSearchContainerRecentTransition(deletions: deletions, insertions: insertions, updates: updates)
|
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 (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||||
|
|
||||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
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 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, 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)
|
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 animated = selectionChanged || expandGlobalSearchChanged
|
||||||
let firstTime = previousEntries == nil
|
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)
|
interaction.peerContextAction?(message, node, rect, gesture, location)
|
||||||
}, toggleExpandLocalResults: {
|
}, toggleExpandLocalResults: {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
|
@ -113,7 +113,7 @@ public final class HashtagSearchController: TelegramBaseController {
|
|||||||
})
|
})
|
||||||
|
|
||||||
let firstTime = previousEntries == nil
|
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: {
|
}, toggleExpandGlobalResults: {
|
||||||
}, searchPeer: { _ in
|
}, searchPeer: { _ in
|
||||||
}, searchQuery: "", searchOptions: nil, messageContextAction: nil, openClearRecentlyDownloaded: {}, toggleAllPaused: {})
|
}, searchQuery: "", searchOptions: nil, messageContextAction: nil, openClearRecentlyDownloaded: {}, toggleAllPaused: {})
|
||||||
|
@ -17,6 +17,7 @@ import WebSearchUI
|
|||||||
import PeerInfoUI
|
import PeerInfoUI
|
||||||
import MapResourceToAvatarSizes
|
import MapResourceToAvatarSizes
|
||||||
import LegacyMediaPickerUI
|
import LegacyMediaPickerUI
|
||||||
|
import TextFormat
|
||||||
|
|
||||||
private struct CreateChannelArguments {
|
private struct CreateChannelArguments {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
@ -26,11 +27,14 @@ private struct CreateChannelArguments {
|
|||||||
let done: () -> Void
|
let done: () -> Void
|
||||||
let changeProfilePhoto: () -> Void
|
let changeProfilePhoto: () -> Void
|
||||||
let focusOnDescription: () -> Void
|
let focusOnDescription: () -> Void
|
||||||
|
let updatePublicLinkText: (String) -> Void
|
||||||
|
let openAuction: (String) -> Void
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum CreateChannelSection: Int32 {
|
private enum CreateChannelSection: Int32 {
|
||||||
case info
|
case info
|
||||||
case description
|
case description
|
||||||
|
case username
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum CreateChannelEntryTag: ItemListItemTag {
|
private enum CreateChannelEntryTag: ItemListItemTag {
|
||||||
@ -62,16 +66,23 @@ private enum CreateChannelEntryTag: ItemListItemTag {
|
|||||||
private enum CreateChannelEntry: ItemListNodeEntry {
|
private enum CreateChannelEntry: ItemListNodeEntry {
|
||||||
case channelInfo(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer?, ItemListAvatarAndNameInfoItemState, ItemListAvatarAndNameInfoItemUpdatingAvatar?)
|
case channelInfo(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, Peer?, ItemListAvatarAndNameInfoItemState, ItemListAvatarAndNameInfoItemUpdatingAvatar?)
|
||||||
case setProfilePhoto(PresentationTheme, String)
|
case setProfilePhoto(PresentationTheme, String)
|
||||||
|
|
||||||
case descriptionSetup(PresentationTheme, String, String)
|
case descriptionSetup(PresentationTheme, String, String)
|
||||||
case descriptionInfo(PresentationTheme, 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 {
|
var section: ItemListSectionId {
|
||||||
switch self {
|
switch self {
|
||||||
case .channelInfo, .setProfilePhoto:
|
case .channelInfo, .setProfilePhoto:
|
||||||
return CreateChannelSection.info.rawValue
|
return CreateChannelSection.info.rawValue
|
||||||
case .descriptionSetup, .descriptionInfo:
|
case .descriptionSetup, .descriptionInfo:
|
||||||
return CreateChannelSection.description.rawValue
|
return CreateChannelSection.description.rawValue
|
||||||
|
case .usernameHeader, .username, .usernameStatus, .usernameInfo:
|
||||||
|
return CreateChannelSection.username.rawValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +96,14 @@ private enum CreateChannelEntry: ItemListNodeEntry {
|
|||||||
return 2
|
return 2
|
||||||
case .descriptionInfo:
|
case .descriptionInfo:
|
||||||
return 3
|
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 {
|
} else {
|
||||||
return false
|
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)
|
}, tag: CreateChannelEntryTag.description)
|
||||||
case let .descriptionInfo(_, text):
|
case let .descriptionInfo(_, text):
|
||||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
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 editingName: ItemListAvatarAndNameInfoItemName
|
||||||
var editingDescriptionText: String
|
var editingDescriptionText: String
|
||||||
var avatar: ItemListAvatarAndNameInfoItemUpdatingAvatar?
|
var avatar: ItemListAvatarAndNameInfoItemUpdatingAvatar?
|
||||||
|
var editingPublicLinkText: String?
|
||||||
|
var addressNameValidationStatus: AddressNameValidationStatus?
|
||||||
|
|
||||||
static func ==(lhs: CreateChannelState, rhs: CreateChannelState) -> Bool {
|
static func ==(lhs: CreateChannelState, rhs: CreateChannelState) -> Bool {
|
||||||
if lhs.creating != rhs.creating {
|
if lhs.creating != rhs.creating {
|
||||||
@ -187,11 +263,17 @@ private struct CreateChannelState: Equatable {
|
|||||||
if lhs.avatar != rhs.avatar {
|
if lhs.avatar != rhs.avatar {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.editingPublicLinkText != rhs.editingPublicLinkText {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.addressNameValidationStatus != rhs.addressNameValidationStatus {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func CreateChannelEntries(presentationData: PresentationData, state: CreateChannelState) -> [CreateChannelEntry] {
|
private func CreateChannelEntries(presentationData: PresentationData, state: CreateChannelState, requestPeer: ReplyMarkupButtonRequestPeerType.Channel?) -> [CreateChannelEntry] {
|
||||||
var entries: [CreateChannelEntry] = []
|
var entries: [CreateChannelEntry] = []
|
||||||
|
|
||||||
let groupInfoState = ItemListAvatarAndNameInfoItemState(editingName: state.editingName, updatingName: nil)
|
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(.descriptionSetup(presentationData.theme, presentationData.strings.Channel_Edit_AboutItem, state.editingDescriptionText))
|
||||||
entries.append(.descriptionInfo(presentationData.theme, presentationData.strings.Channel_About_Help))
|
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
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,6 +353,7 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
|
|||||||
var replaceControllerImpl: ((ViewController) -> Void)?
|
var replaceControllerImpl: ((ViewController) -> Void)?
|
||||||
var pushControllerImpl: ((ViewController) -> Void)?
|
var pushControllerImpl: ((ViewController) -> Void)?
|
||||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||||
|
var dismissImpl: (() -> Void)?
|
||||||
var endEditingImpl: (() -> Void)?
|
var endEditingImpl: (() -> Void)?
|
||||||
var focusOnDescriptionImpl: (() -> Void)?
|
var focusOnDescriptionImpl: (() -> Void)?
|
||||||
|
|
||||||
@ -232,6 +364,14 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
|
|||||||
let uploadedAvatar = Promise<UploadedPeerPhotoData>()
|
let uploadedAvatar = Promise<UploadedPeerPhotoData>()
|
||||||
var uploadedVideoAvatar: (Promise<UploadedPeerPhotoData?>, Double?)? = nil
|
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
|
let arguments = CreateChannelArguments(context: context, updateEditingName: { editingName in
|
||||||
updateState { current in
|
updateState { current in
|
||||||
var current = current
|
var current = current
|
||||||
@ -250,8 +390,8 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
|
|||||||
return current
|
return current
|
||||||
}
|
}
|
||||||
}, done: {
|
}, done: {
|
||||||
let (creating, title, description) = stateValue.with { state -> (Bool, String, String) in
|
let (creating, title, description, publicLink) = stateValue.with { state -> (Bool, String, String, String?) in
|
||||||
return (state.creating, state.editingName.composedTitle, state.editingDescriptionText)
|
return (state.creating, state.editingName.composedTitle, state.editingDescriptionText, state.editingPublicLinkText)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !creating && !title.isEmpty {
|
if !creating && !title.isEmpty {
|
||||||
@ -263,7 +403,23 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
|
|||||||
}
|
}
|
||||||
|
|
||||||
endEditingImpl?()
|
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
|
|> deliverOnMainQueue
|
||||||
|> afterDisposed {
|
|> afterDisposed {
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
@ -283,8 +439,14 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
|
|||||||
}).start()
|
}).start()
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = channelVisibilityController(context: context, peerId: peerId, mode: .initialSetup, upgradedToSupergroup: { _, f in f() })
|
if case .requestPeer = mode {
|
||||||
replaceControllerImpl?(controller)
|
completion?(peerId, {
|
||||||
|
dismissImpl?()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let controller = channelVisibilityController(context: context, peerId: peerId, mode: .initialSetup, upgradedToSupergroup: { _, f in f() })
|
||||||
|
replaceControllerImpl?(controller)
|
||||||
|
}
|
||||||
}, error: { error in
|
}, error: { error in
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let text: String?
|
let text: String?
|
||||||
@ -504,21 +666,57 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
|
|||||||
})
|
})
|
||||||
}, focusOnDescription: {
|
}, focusOnDescription: {
|
||||||
focusOnDescriptionImpl?()
|
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())
|
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get())
|
||||||
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||||
let rightNavigationButton: ItemListNavigationButton
|
let rightNavigationButton: ItemListNavigationButton
|
||||||
if state.creating {
|
if state.creating {
|
||||||
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
|
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
|
||||||
} else {
|
} 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()
|
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 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))
|
return (controllerState, (listState, arguments))
|
||||||
} |> afterDisposed {
|
} |> afterDisposed {
|
||||||
@ -535,6 +733,9 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
|
|||||||
presentControllerImpl = { [weak controller] c, a in
|
presentControllerImpl = { [weak controller] c, a in
|
||||||
controller?.present(c, in: .window(.root), with: a)
|
controller?.present(c, in: .window(.root), with: a)
|
||||||
}
|
}
|
||||||
|
dismissImpl = { [weak controller] in
|
||||||
|
controller?.dismiss()
|
||||||
|
}
|
||||||
controller.willDisappear = { _ in
|
controller.willDisappear = { _ in
|
||||||
endEditingImpl?()
|
endEditingImpl?()
|
||||||
}
|
}
|
||||||
|
@ -415,7 +415,7 @@ private func createGroupEntries(presentationData: PresentationData, state: Creat
|
|||||||
if let hasUsername = requestPeer.hasUsername, hasUsername {
|
if let hasUsername = requestPeer.hasUsername, hasUsername {
|
||||||
let currentUsername = state.editingPublicLinkText ?? ""
|
let currentUsername = state.editingPublicLinkText ?? ""
|
||||||
entries.append(.usernameHeader(presentationData.theme, presentationData.strings.CreateGroup_PublicLinkTitle.uppercased()))
|
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 {
|
if let status = state.addressNameValidationStatus {
|
||||||
let statusText: String
|
let statusText: String
|
||||||
@ -1180,7 +1180,14 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
|
|||||||
if state.creating {
|
if state.creating {
|
||||||
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
|
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
|
||||||
} else {
|
} 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()
|
arguments.done()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user