Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
overtake 2021-01-22 21:46:22 +03:00
commit 752a21d486
7 changed files with 189 additions and 14 deletions

View File

@ -21,6 +21,7 @@ swift_library(
"//submodules/RadialStatusNode:RadialStatusNode",
"//submodules/AnimatedStickerNode:AnimatedStickerNode",
"//submodules/ChatHistoryImportTasks:ChatHistoryImportTasks",
"//submodules/MimeTypes:MimeTypes",
],
visibility = [
"//visibility:public",

View File

@ -12,6 +12,7 @@ import RadialStatusNode
import AnimatedStickerNode
import AppBundle
import ZIPFoundation
import MimeTypes
public final class ChatImportActivityScreen: ViewController {
private final class Node: ViewControllerTracingNode {
@ -191,7 +192,7 @@ public final class ChatImportActivityScreen: ViewController {
if let (layout, navigationHeight) = self.validLayout {
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .immediate)
self.radialStatus.transitionToState(.progress(color: self.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: max(0.09, self.totalProgress), cancelEnabled: false), animated: animated, synchronous: true, completion: {})
self.radialStatus.transitionToState(.progress(color: self.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: max(0.02, self.totalProgress), cancelEnabled: false), animated: animated, synchronous: true, completion: {})
if isDone {
self.radialCheck.transitionToState(.progress(color: .clear, lineWidth: 6.0, value: self.totalProgress, cancelEnabled: false), animated: false, synchronous: true, completion: {})
self.radialCheck.transitionToState(.check(self.presentationData.theme.list.itemAccentColor), animated: animated, synchronous: true, completion: {})
@ -362,7 +363,15 @@ public final class ChatImportActivityScreen: ViewController {
}
let uploadedMedia = unpackedFile
|> mapToSignal { tempFile -> Signal<(String, Float), ImportError> in
return ChatHistoryImport.uploadMedia(account: context.account, session: session, file: tempFile, fileName: fileName, type: mediaType)
var mimeTypeValue = "application/binary"
let fileExtension = (tempFile.path as NSString).pathExtension
if !fileExtension.isEmpty {
if let value = TGMimeTypeMap.mimeType(forExtension: fileExtension.lowercased()) {
mimeTypeValue = value
}
}
return ChatHistoryImport.uploadMedia(account: context.account, session: session, file: tempFile, fileName: fileName, mimeType: mimeTypeValue, type: mediaType)
|> mapError { _ -> ImportError in
return .generic
}

View File

@ -1351,6 +1351,9 @@ open class NavigationController: UINavigationController, ContainableController,
}
override open func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
if let presentingViewController = self.presentingViewController {
presentingViewController.dismiss(animated: false, completion: nil)
}
if let controller = self.presentedViewController {
if flag {
UIView.animate(withDuration: 0.3, delay: 0.0, options: UIView.AnimationOptions(rawValue: 7 << 16), animations: {

View File

@ -460,7 +460,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[649453030] = { return Api.messages.MessageEditData.parse_messageEditData($0) }
dict[-886477832] = { return Api.LabeledPrice.parse_labeledPrice($0) }
dict[-438840932] = { return Api.messages.ChatFull.parse_chatFull($0) }
dict[-1919636670] = { return Api.messages.HistoryImportParsed.parse_historyImportParsed($0) }
dict[1578088377] = { return Api.messages.HistoryImportParsed.parse_historyImportParsed($0) }
dict[-618540889] = { return Api.InputSecureValue.parse_inputSecureValue($0) }
dict[-170029155] = { return Api.messages.DiscussionMessage.parse_discussionMessage($0) }
dict[1722786150] = { return Api.help.DeepLinkInfo.parse_deepLinkInfoEmpty($0) }

View File

@ -985,10 +985,10 @@ public struct messages {
switch self {
case .historyImportParsed(let flags, let title):
if boxed {
buffer.appendInt32(-1919636670)
buffer.appendInt32(1578088377)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
break
}
}
@ -1004,9 +1004,9 @@ public struct messages {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
if Int(_1!) & Int(1 << 1) != 0 {_2 = parseString(reader) }
if Int(_1!) & Int(1 << 2) != 0 {_2 = parseString(reader) }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 1) == 0) || _2 != nil
let _c2 = (Int(_1!) & Int(1 << 2) == 0) || _2 != nil
if _c1 && _c2 {
return Api.messages.HistoryImportParsed.historyImportParsed(flags: _1!, title: _2)
}

View File

@ -19,6 +19,7 @@ public enum ChatHistoryImport {
public enum ParsedInfo {
case privateChat(title: String?)
case group(title: String?)
case unknown(title: String?)
}
public enum GetInfoError {
@ -39,7 +40,7 @@ public enum ChatHistoryImport {
} else if (flags & (1 << 1)) != 0 {
return .single(.group(title: title))
} else {
return .fail(.parseError)
return .single(.unknown(title: title))
}
}
}
@ -92,7 +93,7 @@ public enum ChatHistoryImport {
case generic
}
public static func uploadMedia(account: Account, session: Session, file: TempBoxFile, fileName: String, type: MediaType) -> Signal<Float, UploadMediaError> {
public static func uploadMedia(account: Account, session: Session, file: TempBoxFile, fileName: String, mimeType: String, type: MediaType) -> Signal<Float, UploadMediaError> {
return multipartUpload(network: account.network, postbox: account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false)
|> mapError { _ -> UploadMediaError in
return .generic
@ -107,18 +108,18 @@ public enum ChatHistoryImport {
case .file, .video, .sticker, .voice:
var attributes: [Api.DocumentAttribute] = []
attributes.append(.documentAttributeFilename(fileName: fileName))
var mimeType = "application/octet-stream"
var resolvedMimeType = mimeType
switch type {
case .video:
mimeType = "video/mp4"
resolvedMimeType = "video/mp4"
case .sticker:
mimeType = "image/webp"
resolvedMimeType = "image/webp"
case .voice:
mimeType = "audio/ogg"
resolvedMimeType = "audio/ogg"
default:
break
}
inputMedia = .inputMediaUploadedDocument(flags: 0, file: inputFile, thumb: nil, mimeType: mimeType, attributes: attributes, stickers: nil, ttlSeconds: nil)
inputMedia = .inputMediaUploadedDocument(flags: 0, file: inputFile, thumb: nil, mimeType: resolvedMimeType, attributes: attributes, stickers: nil, ttlSeconds: nil)
}
case let .progress(value):
return .single(value)

View File

@ -85,6 +85,8 @@ public class ShareRootControllerImpl {
private var observer1: AnyObject?
private var observer2: AnyObject?
private weak var navigationController: NavigationController?
public init(initializationData: ShareRootControllerInitializationData, getExtensionContext: @escaping () -> NSExtensionContext?) {
self.initializationData = initializationData
self.getExtensionContext = getExtensionContext
@ -374,6 +376,9 @@ public class ShareRootControllerImpl {
if let currentShareController = strongSelf.currentShareController {
currentShareController.dismiss()
}
if let navigationController = strongSelf.navigationController {
navigationController.dismiss(animated: false)
}
strongSelf.currentShareController = shareController
strongSelf.mainWindow?.present(shareController, on: .root)
}
@ -491,6 +496,7 @@ public class ShareRootControllerImpl {
let presentationData = internalContext.sharedContext.currentPresentationData.with { $0 }
let navigationController = NavigationController(mode: .single, theme: NavigationControllerTheme(presentationTheme: presentationData.theme))
strongSelf.navigationController = navigationController
navigationController.viewControllers = [TempController(context: context)]
strongSelf.mainWindow?.present(navigationController, on: .root)
@ -677,6 +683,161 @@ public class ShareRootControllerImpl {
})
}
navigationController.viewControllers = [controller]
strongSelf.mainWindow?.present(navigationController, on: .root)
case let .unknown(peerTitle):
//TODO:localize
var attemptSelectionImpl: ((Peer) -> Void)?
var createNewGroupImpl: (() -> Void)?
let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: [.excludeDisabled, .doNotSearchMessages], hasContactSelector: true, hasGlobalSearch: false, title: "Import Chat", attemptSelection: { peer in
attemptSelectionImpl?(peer)
}, createNewGroup: {
createNewGroupImpl?()
}, pretendPresentedInModal: true))
controller.customDismiss = {
self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil)
}
controller.peerSelected = { peer in
attemptSelectionImpl?(peer)
}
controller.navigationPresentation = .default
let beginWithPeer: (PeerId) -> Void = { peerId in
navigationController.view.endEditing(true)
navigationController.pushViewController(ChatImportActivityScreen(context: context, cancel: {
self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil)
}, peerId: peerId, archive: archive, mainEntry: mainFile, otherEntries: otherEntries))
}
attemptSelectionImpl = { [weak controller] peer in
controller?.inProgress = true
let _ = (ChatHistoryImport.checkPeerImport(account: context.account, peerId: peer.id)
|> deliverOnMainQueue).start(error: { error in
controller?.inProgress = false
let presentationData = internalContext.sharedContext.currentPresentationData.with { $0 }
let errorText: String
switch error {
case .generic:
errorText = presentationData.strings.Login_UnknownError
case .userIsNotMutualContact:
errorText = "You can only import messages into private chats with users who added you in their contact list."
}
let controller = standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
})])
strongSelf.mainWindow?.present(controller, on: .root)
}, completed: {
controller?.inProgress = false
let presentationData = internalContext.sharedContext.currentPresentationData.with { $0 }
var errorText: String?
if let channel = peer as? TelegramChannel {
if channel.flags.contains(.isCreator) || channel.adminRights != nil {
} else {
errorText = "You need to be an admin of the group to import messages into it."
}
} else if let group = peer as? TelegramGroup {
switch group.role {
case .creator:
break
default:
errorText = "You need to be an admin of the group to import messages into it."
}
} else if let _ = peer as? TelegramUser {
} else {
errorText = "You can't import history into this group."
}
if let errorText = errorText {
let presentationData = internalContext.sharedContext.currentPresentationData.with { $0 }
let controller = standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
})])
strongSelf.mainWindow?.present(controller, on: .root)
} else {
let presentationData = internalContext.sharedContext.currentPresentationData.with { $0 }
if let user = peer as? TelegramUser {
let text: String
if let title = peerTitle {
text = "Are you sure you want to import messages from **\(title)** into the chat with **\(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))**?"
} else {
text = "Are you sure you want to import messages into the chat with **\(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))**?"
}
let controller = standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Import Messages", text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
}), TextAlertAction(type: .defaultAction, title: "Import", action: {
beginWithPeer(peer.id)
})], parseMarkdown: true)
strongSelf.mainWindow?.present(controller, on: .root)
} else {
let text: String
if let groupTitle = peerTitle {
text = "Are you sure you want to import messages from **\(groupTitle)** into **\(peer.debugDisplayTitle)**?"
} else {
text = "Are you sure you want to import messages into **\(peer.debugDisplayTitle)**?"
}
let controller = standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Import Messages", text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
}), TextAlertAction(type: .defaultAction, title: "Import", action: {
beginWithPeer(peer.id)
})], parseMarkdown: true)
strongSelf.mainWindow?.present(controller, on: .root)
}
}
})
}
createNewGroupImpl = {
let presentationData = internalContext.sharedContext.currentPresentationData.with { $0 }
let resolvedGroupTitle: String
if let groupTitle = peerTitle {
resolvedGroupTitle = groupTitle
} else {
resolvedGroupTitle = "Group"
}
let controller = standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Create Group and Import Messages", text: "Are you sure you want to create group **\(resolvedGroupTitle)** 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: resolvedGroupTitle, description: nil, isForHistoryImport: true)
|> map(Optional.init)
|> `catch` { _ -> Signal<PeerId?, NoError> in
return .single(nil)
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let progressSignal = Signal<Never, NoError> { subscriber in
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
if let strongSelf = self {
strongSelf.mainWindow?.present(controller, on: .root)
}
return ActionDisposable { [weak controller] in
Queue.mainQueue().async() {
controller?.dismiss()
}
}
}
|> runOn(Queue.mainQueue())
|> delay(0.15, queue: Queue.mainQueue())
let progressDisposable = progressSignal.start()
signal = signal
|> afterDisposed {
Queue.mainQueue().async {
progressDisposable.dispose()
}
}
let _ = (signal
|> deliverOnMainQueue).start(next: { peerId in
if let peerId = peerId {
beginWithPeer(peerId)
} else {
//TODO:localize
}
})
}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
})], parseMarkdown: true)
strongSelf.mainWindow?.present(controller, on: .root)
}
navigationController.viewControllers = [controller]
strongSelf.mainWindow?.present(navigationController, on: .root)
}