mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Chat Import
This commit is contained in:
parent
da2faa5967
commit
fe491b6831
@ -1130,6 +1130,7 @@
|
||||
"ShareFileTip.CloseTip" = "Close Tip";
|
||||
|
||||
"DialogList.SearchSectionDialogs" = "Chats and Contacts";
|
||||
"DialogList.SearchSectionChats" = "Chats";
|
||||
"DialogList.SearchSectionGlobal" = "Global Search";
|
||||
"DialogList.SearchSectionMessages" = "Messages";
|
||||
|
||||
@ -5900,3 +5901,5 @@ Sorry for the inconvenience.";
|
||||
"DialogList.MultipleTypingPair" = "%@ and %@ are typing";
|
||||
|
||||
"Common.Save" = "Save";
|
||||
|
||||
"ChatList.HeaderImportIntoAnExistingGroup" = "OR IMPORT INTO AN EXISTING GROUP";
|
||||
|
@ -34,18 +34,22 @@ public final class PeerSelectionControllerParams {
|
||||
public let filter: ChatListNodePeersFilter
|
||||
public let hasChatListSelector: Bool
|
||||
public let hasContactSelector: Bool
|
||||
public let hasGlobalSearch: Bool
|
||||
public let title: String?
|
||||
public let attemptSelection: ((Peer) -> Void)?
|
||||
public let createNewGroup: (() -> Void)?
|
||||
public let pretendPresentedInModal: Bool
|
||||
|
||||
public init(context: AccountContext, filter: ChatListNodePeersFilter = [.onlyWriteable], hasChatListSelector: Bool = true, hasContactSelector: Bool = true, title: String? = nil, attemptSelection: ((Peer) -> Void)? = nil, createNewGroup: (() -> Void)? = nil) {
|
||||
public init(context: AccountContext, filter: ChatListNodePeersFilter = [.onlyWriteable], hasChatListSelector: Bool = true, hasContactSelector: Bool = true, hasGlobalSearch: Bool = true, title: String? = nil, attemptSelection: ((Peer) -> Void)? = nil, createNewGroup: (() -> Void)? = nil, pretendPresentedInModal: Bool = false) {
|
||||
self.context = context
|
||||
self.filter = filter
|
||||
self.hasChatListSelector = hasChatListSelector
|
||||
self.hasContactSelector = hasContactSelector
|
||||
self.hasGlobalSearch = hasGlobalSearch
|
||||
self.title = title
|
||||
self.attemptSelection = attemptSelection
|
||||
self.createNewGroup = createNewGroup
|
||||
self.pretendPresentedInModal = pretendPresentedInModal
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,13 +120,13 @@ public final class ChatImportActivityScreen: ViewController {
|
||||
//TODO:localize
|
||||
|
||||
let iconSize = CGSize(width: 170.0, height: 170.0)
|
||||
let radialStatusSize = CGSize(width: 180.0, height: 180.0)
|
||||
let radialStatusSize = CGSize(width: 186.0, height: 186.0)
|
||||
let maxIconStatusSpacing: CGFloat = 62.0
|
||||
let maxProgressTextSpacing: CGFloat = 32.0
|
||||
let progressStatusSpacing: CGFloat = 16.0
|
||||
let statusButtonSpacing: CGFloat = 16.0
|
||||
let maxProgressTextSpacing: CGFloat = 33.0
|
||||
let progressStatusSpacing: CGFloat = 14.0
|
||||
let statusButtonSpacing: CGFloat = 19.0
|
||||
|
||||
self.radialStatusText.attributedText = NSAttributedString(string: "\(Int(self.totalProgress * 100.0))%", font: Font.with(size: 42.0, design: .round, traits: []), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||
self.radialStatusText.attributedText = NSAttributedString(string: "\(Int(self.totalProgress * 100.0))%", font: Font.with(size: 42.0, design: .round, weight: .semibold), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||
let radialStatusTextSize = self.radialStatusText.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
|
||||
|
||||
self.progressText.attributedText = NSAttributedString(string: "\(dataSizeString(Int(self.totalProgress * CGFloat(self.totalBytes)))) of \(dataSizeString(Int(1.0 * CGFloat(self.totalBytes))))", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||
@ -207,6 +207,13 @@ public final class ChatImportActivityScreen: ViewController {
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
|
||||
override public var _presentedInModal: Bool {
|
||||
get {
|
||||
return true
|
||||
} set(value) {
|
||||
}
|
||||
}
|
||||
|
||||
public init(context: AccountContext, cancel: @escaping () -> Void, peerId: PeerId, archive: Archive, mainEntry: TempBoxFile, otherEntries: [(Entry, String, ChatHistoryImport.MediaType)]) {
|
||||
self.context = context
|
||||
self.cancel = cancel
|
||||
|
@ -25,6 +25,7 @@ public enum ChatListSearchItemHeaderType {
|
||||
case groupMembers
|
||||
case activeVoiceChats
|
||||
case recentCalls
|
||||
case orImportIntoAnExistingGroup
|
||||
|
||||
fileprivate func title(strings: PresentationStrings) -> String {
|
||||
switch self {
|
||||
@ -68,6 +69,8 @@ public enum ChatListSearchItemHeaderType {
|
||||
return strings.CallList_ActiveVoiceChatsHeader
|
||||
case .recentCalls:
|
||||
return strings.CallList_RecentCallsHeader
|
||||
case .orImportIntoAnExistingGroup:
|
||||
return strings.ChatList_HeaderImportIntoAnExistingGroup
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,6 +116,8 @@ public enum ChatListSearchItemHeaderType {
|
||||
return .activeVoiceChats
|
||||
case .recentCalls:
|
||||
return .recentCalls
|
||||
case .orImportIntoAnExistingGroup:
|
||||
return .orImportIntoAnExistingGroup
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -142,6 +147,7 @@ private enum ChatListSearchItemHeaderId: Int32 {
|
||||
case groupMembers
|
||||
case activeVoiceChats
|
||||
case recentCalls
|
||||
case orImportIntoAnExistingGroup
|
||||
}
|
||||
|
||||
public final class ChatListSearchItemHeader: ListViewItemHeader {
|
||||
|
@ -429,7 +429,13 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
case .collapse:
|
||||
actionTitle = strings.ChatList_Search_ShowLess
|
||||
}
|
||||
header = ChatListSearchItemHeader(type: .localPeers, theme: theme, strings: strings, actionTitle: actionTitle, action: actionTitle == nil ? nil : {
|
||||
let headerType: ChatListSearchItemHeaderType
|
||||
if filter.contains(.onlyGroups) {
|
||||
headerType = .chats
|
||||
} else {
|
||||
headerType = .localPeers
|
||||
}
|
||||
header = ChatListSearchItemHeader(type: headerType, theme: theme, strings: strings, actionTitle: actionTitle, action: actionTitle == nil ? nil : {
|
||||
toggleExpandLocalResults()
|
||||
})
|
||||
}
|
||||
|
@ -250,7 +250,14 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
||||
switch mode {
|
||||
case let .peers(_, _, additionalCategories, _):
|
||||
if !additionalCategories.isEmpty {
|
||||
header = ChatListSearchItemHeader(type: .chats, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||
let headerType: ChatListSearchItemHeaderType
|
||||
if case .action = additionalCategories[0].appearance {
|
||||
// TODO: hack, generalize
|
||||
headerType = .orImportIntoAnExistingGroup
|
||||
} else {
|
||||
headerType = .chats
|
||||
}
|
||||
header = ChatListSearchItemHeader(type: headerType, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||
}
|
||||
default:
|
||||
break
|
||||
@ -320,7 +327,14 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
||||
switch mode {
|
||||
case let .peers(_, _, additionalCategories, _):
|
||||
if !additionalCategories.isEmpty {
|
||||
header = ChatListSearchItemHeader(type: .chats, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||
let headerType: ChatListSearchItemHeaderType
|
||||
if case .action = additionalCategories[0].appearance {
|
||||
// TODO: hack, generalize
|
||||
headerType = .orImportIntoAnExistingGroup
|
||||
} else {
|
||||
headerType = .chats
|
||||
}
|
||||
header = ChatListSearchItemHeader(type: headerType, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||
}
|
||||
default:
|
||||
break
|
||||
|
@ -33,7 +33,7 @@ public struct Font {
|
||||
case bold
|
||||
}
|
||||
|
||||
public static func with(size: CGFloat, design: Design = .regular, traits: Traits = []) -> UIFont {
|
||||
public static func with(size: CGFloat, design: Design = .regular, weight: Weight = .regular, traits: Traits = []) -> UIFont {
|
||||
if #available(iOS 13.0, *) {
|
||||
let descriptor = UIFont.systemFont(ofSize: size).fontDescriptor
|
||||
var symbolicTraits = descriptor.symbolicTraits
|
||||
@ -63,6 +63,15 @@ public struct Font {
|
||||
default:
|
||||
updatedDescriptor = updatedDescriptor?.withDesign(.default)
|
||||
}
|
||||
switch weight {
|
||||
case .semibold:
|
||||
let fontTraits = [UIFontDescriptor.TraitKey.weight: UIFont.Weight.semibold]
|
||||
updatedDescriptor = updatedDescriptor?.addingAttributes([
|
||||
UIFontDescriptor.AttributeName.traits: fontTraits
|
||||
])
|
||||
default:
|
||||
break
|
||||
}
|
||||
if let updatedDescriptor = updatedDescriptor {
|
||||
return UIFont(descriptor: updatedDescriptor, size: size)
|
||||
} else {
|
||||
|
@ -139,7 +139,7 @@ public enum TabBarItemContextActionType {
|
||||
}
|
||||
|
||||
open var navigationPresentation: ViewControllerNavigationPresentation = .default
|
||||
var _presentedInModal: Bool = false
|
||||
open var _presentedInModal: Bool = false
|
||||
|
||||
public var presentedOverCoveringView: Bool = false
|
||||
|
||||
|
@ -12,7 +12,7 @@ public enum CreateChannelError {
|
||||
case serverProvided(String)
|
||||
}
|
||||
|
||||
private func createChannel(account: Account, title: String, description: String?, isSupergroup:Bool, location: (latitude: Double, longitude: Double, address: String)? = nil) -> Signal<PeerId, CreateChannelError> {
|
||||
private func createChannel(account: Account, title: String, description: String?, isSupergroup:Bool, location: (latitude: Double, longitude: Double, address: String)? = nil, isForHistoryImport: Bool = false) -> Signal<PeerId, CreateChannelError> {
|
||||
return account.postbox.transaction { transaction -> Signal<PeerId, CreateChannelError> in
|
||||
var flags: Int32 = 0
|
||||
if isSupergroup {
|
||||
@ -20,6 +20,9 @@ private func createChannel(account: Account, title: String, description: String?
|
||||
} else {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
if isForHistoryImport {
|
||||
flags |= (1 << 3)
|
||||
}
|
||||
|
||||
var geoPoint: Api.InputGeoPoint?
|
||||
var address: String?
|
||||
@ -69,8 +72,8 @@ public func createChannel(account: Account, title: String, description: String?)
|
||||
return createChannel(account: account, title: title, description: description, isSupergroup: false)
|
||||
}
|
||||
|
||||
public func createSupergroup(account: Account, title: String, description: String?, location: (latitude: Double, longitude: Double, address: String)? = nil) -> Signal<PeerId, CreateChannelError> {
|
||||
return createChannel(account: account, title: title, description: description, isSupergroup: true, location: location)
|
||||
public func createSupergroup(account: Account, title: String, description: String?, location: (latitude: Double, longitude: Double, address: String)? = nil, isForHistoryImport: Bool = false) -> Signal<PeerId, CreateChannelError> {
|
||||
return createChannel(account: account, title: title, description: description, isSupergroup: true, location: location, isForHistoryImport: isForHistoryImport)
|
||||
}
|
||||
|
||||
public enum DeleteChannelError {
|
||||
@ -81,7 +84,7 @@ public func deleteChannel(account: Account, peerId: PeerId) -> Signal<Void, Dele
|
||||
return account.postbox.transaction { transaction -> Api.InputChannel? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputChannel)
|
||||
}
|
||||
|> mapError { _ -> DeleteChannelError in return .generic }
|
||||
|> mapError { _ -> DeleteChannelError in }
|
||||
|> mapToSignal { inputChannel -> Signal<Void, DeleteChannelError> in
|
||||
if let inputChannel = inputChannel {
|
||||
return account.network.request(Api.functions.channels.deleteChannel(channel: inputChannel))
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -56,6 +56,22 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
||||
|
||||
private let hasChatListSelector: Bool
|
||||
private let hasContactSelector: Bool
|
||||
private let hasGlobalSearch: Bool
|
||||
private let pretendPresentedInModal: Bool
|
||||
|
||||
override public var _presentedInModal: Bool {
|
||||
get {
|
||||
if self.pretendPresentedInModal {
|
||||
return true
|
||||
} else {
|
||||
return super._presentedInModal
|
||||
}
|
||||
} set(value) {
|
||||
if !self.pretendPresentedInModal {
|
||||
super._presentedInModal = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var searchContentNode: NavigationBarSearchContentNode?
|
||||
|
||||
@ -64,9 +80,11 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
||||
self.filter = params.filter
|
||||
self.hasChatListSelector = params.hasChatListSelector
|
||||
self.hasContactSelector = params.hasContactSelector
|
||||
self.hasGlobalSearch = params.hasGlobalSearch
|
||||
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.attemptSelection = params.attemptSelection
|
||||
self.createNewGroup = params.createNewGroup
|
||||
self.pretendPresentedInModal = params.pretendPresentedInModal
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
|
||||
@ -126,7 +144,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = PeerSelectionControllerNode(context: self.context, filter: self.filter, hasChatListSelector: self.hasChatListSelector, hasContactSelector: self.hasContactSelector, createNewGroup: self.createNewGroup, present: { [weak self] c, a in
|
||||
self.displayNode = PeerSelectionControllerNode(context: self.context, filter: self.filter, hasChatListSelector: self.hasChatListSelector, hasContactSelector: self.hasContactSelector, hasGlobalSearch: self.hasGlobalSearch, createNewGroup: self.createNewGroup, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
}, dismiss: { [weak self] in
|
||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
|
@ -19,6 +19,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
private let present: (ViewController, Any?) -> Void
|
||||
private let dismiss: () -> Void
|
||||
private let filter: ChatListNodePeersFilter
|
||||
private let hasGlobalSearch: Bool
|
||||
|
||||
var inProgress: Bool = false {
|
||||
didSet {
|
||||
@ -59,11 +60,12 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
return self.readyValue.get()
|
||||
}
|
||||
|
||||
init(context: AccountContext, filter: ChatListNodePeersFilter, hasChatListSelector: Bool, hasContactSelector: Bool, createNewGroup: (() -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismiss: @escaping () -> Void) {
|
||||
init(context: AccountContext, filter: ChatListNodePeersFilter, hasChatListSelector: Bool, hasContactSelector: Bool, hasGlobalSearch: Bool, createNewGroup: (() -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismiss: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.present = present
|
||||
self.dismiss = dismiss
|
||||
self.filter = filter
|
||||
self.hasGlobalSearch = hasGlobalSearch
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
@ -264,7 +266,11 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
}, placeholder: placeholderNode)
|
||||
|
||||
} else if let contactListNode = self.contactListNode, contactListNode.supernode != nil {
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ContactsSearchContainerNode(context: self.context, onlyWriteable: true, categories: [.cloudContacts, .global], addContact: nil, openPeer: { [weak self] peer in
|
||||
var categories: ContactsSearchCategories = [.cloudContacts]
|
||||
if self.hasGlobalSearch {
|
||||
categories.insert(.global)
|
||||
}
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ContactsSearchContainerNode(context: self.context, onlyWriteable: true, categories: categories, addContact: nil, openPeer: { [weak self] peer in
|
||||
if let strongSelf = self {
|
||||
switch peer {
|
||||
case let .peer(peer, _, _):
|
||||
|
@ -489,11 +489,11 @@ public class ShareRootControllerImpl {
|
||||
//TODO:localize
|
||||
var attemptSelectionImpl: ((Peer) -> Void)?
|
||||
var createNewGroupImpl: (() -> Void)?
|
||||
let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: [.onlyGroups, .onlyManageable, .excludeDisabled], hasContactSelector: false, title: "Import Chat", attemptSelection: { peer in
|
||||
let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: [.onlyGroups, .onlyManageable, .excludeDisabled, .doNotSearchMessages], hasContactSelector: false, hasGlobalSearch: false, title: "Import Chat", attemptSelection: { peer in
|
||||
attemptSelectionImpl?(peer)
|
||||
}, createNewGroup: {
|
||||
createNewGroupImpl?()
|
||||
}))
|
||||
}, pretendPresentedInModal: true))
|
||||
|
||||
controller.customDismiss = {
|
||||
self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil)
|
||||
@ -547,7 +547,7 @@ public class ShareRootControllerImpl {
|
||||
createNewGroupImpl = {
|
||||
let presentationData = internalContext.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Create Group and Import Messages", text: "Are you sure you want to create group **\(groupTitle)** and import messages from another messaging app?", actions: [TextAlertAction(type: .defaultAction, title: "Create and Import", action: {
|
||||
var signal: Signal<PeerId?, NoError> = createSupergroup(account: context.account, title: groupTitle, description: nil)
|
||||
var signal: Signal<PeerId?, NoError> = createSupergroup(account: context.account, title: groupTitle, description: nil, isForHistoryImport: true)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<PeerId?, NoError> in
|
||||
return .single(nil)
|
||||
@ -596,9 +596,9 @@ public class ShareRootControllerImpl {
|
||||
|
||||
//TODO:localize
|
||||
var attemptSelectionImpl: ((Peer) -> Void)?
|
||||
let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: [.onlyPrivateChats, .excludeDisabled], hasChatListSelector: false, hasContactSelector: true, title: "Import Chat", attemptSelection: { peer in
|
||||
let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: [.onlyPrivateChats, .excludeDisabled, .doNotSearchMessages], hasChatListSelector: false, hasContactSelector: true, hasGlobalSearch: false, title: "Import Chat", attemptSelection: { peer in
|
||||
attemptSelectionImpl?(peer)
|
||||
}))
|
||||
}, pretendPresentedInModal: true))
|
||||
|
||||
controller.customDismiss = {
|
||||
self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil)
|
||||
|
Loading…
x
Reference in New Issue
Block a user