mirror of
https://github.com/tutao/tutanota.git
synced 2025-12-07 13:49:47 +00:00
fix selecting apple MBOX format when importing emails
Co-authored-by: amm <amm@tutao.de> Co-authored-by: map <mpfau@users.noreply.github.com>
This commit is contained in:
parent
4c4309139c
commit
b6fe5d3e97
15 changed files with 65 additions and 1 deletions
|
|
@ -126,6 +126,10 @@ class AndroidFileFacade(
|
||||||
error("not implemented for this platform")
|
error("not implemented for this platform")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun openMacImportFileChooser(): List<String> {
|
||||||
|
error("not implemented for this platform")
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override suspend fun writeTempDataFile(file: DataFile): String = withContext(Dispatchers.IO) {
|
override suspend fun writeTempDataFile(file: DataFile): String = withContext(Dispatchers.IO) {
|
||||||
val fileHandle = File(tempDir.decrypt, file.name)
|
val fileHandle = File(tempDir.decrypt, file.name)
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,10 @@ class AndroidFileFacade(
|
||||||
error("not implemented for this platform")
|
error("not implemented for this platform")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun openMacImportFileChooser(): List<String> {
|
||||||
|
error("not implemented for this platform")
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override suspend fun writeTempDataFile(file: DataFile): String = withContext(Dispatchers.IO) {
|
override suspend fun writeTempDataFile(file: DataFile): String = withContext(Dispatchers.IO) {
|
||||||
val fileHandle = File(tempDir.decrypt, file.name)
|
val fileHandle = File(tempDir.decrypt, file.name)
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,11 @@ interface FileFacade {
|
||||||
*/
|
*/
|
||||||
suspend fun openFolderChooser(
|
suspend fun openFolderChooser(
|
||||||
): String?
|
): String?
|
||||||
|
/**
|
||||||
|
* Opens OS file picker for selecting either a file or folder for Email Import. Works only on macOS
|
||||||
|
*/
|
||||||
|
suspend fun openMacImportFileChooser(
|
||||||
|
): List<String>
|
||||||
suspend fun deleteFile(
|
suspend fun deleteFile(
|
||||||
file: String,
|
file: String,
|
||||||
): Unit
|
): Unit
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,11 @@ class FileFacadeReceiveDispatcher(
|
||||||
)
|
)
|
||||||
return json.encodeToString(result)
|
return json.encodeToString(result)
|
||||||
}
|
}
|
||||||
|
"openMacImportFileChooser" -> {
|
||||||
|
val result: List<String> = this.facade.openMacImportFileChooser(
|
||||||
|
)
|
||||||
|
return json.encodeToString(result)
|
||||||
|
}
|
||||||
"deleteFile" -> {
|
"deleteFile" -> {
|
||||||
val file: String = json.decodeFromString(arg[0])
|
val file: String = json.decodeFromString(arg[0])
|
||||||
val result: Unit = this.facade.deleteFile(
|
val result: Unit = this.facade.deleteFile(
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,11 @@ public protocol FileFacade {
|
||||||
*/
|
*/
|
||||||
func openFolderChooser(
|
func openFolderChooser(
|
||||||
) async throws -> String?
|
) async throws -> String?
|
||||||
|
/**
|
||||||
|
* Opens OS file picker for selecting either a file or folder for Email Import. Works only on macOS
|
||||||
|
*/
|
||||||
|
func openMacImportFileChooser(
|
||||||
|
) async throws -> [String]
|
||||||
func deleteFile(
|
func deleteFile(
|
||||||
_ file: String
|
_ file: String
|
||||||
) async throws -> Void
|
) async throws -> Void
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,10 @@ public class FileFacadeReceiveDispatcher {
|
||||||
let result = try await self.facade.openFolderChooser(
|
let result = try await self.facade.openFolderChooser(
|
||||||
)
|
)
|
||||||
return toJson(result)
|
return toJson(result)
|
||||||
|
case "openMacImportFileChooser":
|
||||||
|
let result = try await self.facade.openMacImportFileChooser(
|
||||||
|
)
|
||||||
|
return toJson(result)
|
||||||
case "deleteFile":
|
case "deleteFile":
|
||||||
let file = try! JSONDecoder().decode(String.self, from: arg[0].data(using: .utf8)!)
|
let file = try! JSONDecoder().decode(String.self, from: arg[0].data(using: .utf8)!)
|
||||||
try await self.facade.deleteFile(
|
try await self.facade.deleteFile(
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import TutanotaSharedFramework
|
||||||
import UniformTypeIdentifiers
|
import UniformTypeIdentifiers
|
||||||
|
|
||||||
class IosFileFacade: FileFacade {
|
class IosFileFacade: FileFacade {
|
||||||
|
func openMacImportFileChooser() async throws -> [String] { fatalError("not implemented for this platform") }
|
||||||
|
|
||||||
let chooser: TUTFileChooser
|
let chooser: TUTFileChooser
|
||||||
let viewer: FileViewer
|
let viewer: FileViewer
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import TutanotaSharedFramework
|
||||||
import UniformTypeIdentifiers
|
import UniformTypeIdentifiers
|
||||||
|
|
||||||
class IosFileFacade: FileFacade {
|
class IosFileFacade: FileFacade {
|
||||||
|
func openMacImportFileChooser() async throws -> [String] { fatalError("not implemented for this platform") }
|
||||||
|
|
||||||
let chooser: TUTFileChooser
|
let chooser: TUTFileChooser
|
||||||
let viewer: FileViewer
|
let viewer: FileViewer
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,11 @@
|
||||||
"arg": [],
|
"arg": [],
|
||||||
"ret": "string?"
|
"ret": "string?"
|
||||||
},
|
},
|
||||||
|
"openMacImportFileChooser": {
|
||||||
|
"doc": "Opens OS file picker for selecting either a file or folder for Email Import. Works only on macOS",
|
||||||
|
"arg": [],
|
||||||
|
"ret": "List<string>"
|
||||||
|
},
|
||||||
"deleteFile": {
|
"deleteFile": {
|
||||||
"arg": [
|
"arg": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -204,6 +204,17 @@ export class DesktopFileFacade implements FileFacade {
|
||||||
.then(({ filePaths }) => filePaths[0] ?? null)
|
.then(({ filePaths }) => filePaths[0] ?? null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens OS file picker for selecting either a file or a folder. The options "openDirectory", "openFile" simultaneously are only supported on macOS
|
||||||
|
* This is needed because Apple Mail uses a custom MBOX when format when exporting, which is a directory and not a file.
|
||||||
|
*/
|
||||||
|
async openMacImportFileChooser(): Promise<Array<string>> {
|
||||||
|
const opts: OpenDialogOptions = { properties: ["openDirectory", "openFile", "multiSelections"] }
|
||||||
|
opts.filters = [{ name: "Filter", extensions: ["eml", "mbox"].slice() }]
|
||||||
|
const { filePaths } = await this.electron.dialog.showOpenDialog(this.win._browserWindow, opts)
|
||||||
|
return filePaths
|
||||||
|
}
|
||||||
|
|
||||||
async putFileIntoDownloadsFolder(localFileUri: string, fileNameToUse: string): Promise<string> {
|
async putFileIntoDownloadsFolder(localFileUri: string, fileNameToUse: string): Promise<string> {
|
||||||
const savePath = await this.pickSavePath(fileNameToUse)
|
const savePath = await this.pickSavePath(fileNameToUse)
|
||||||
await this.fs.promises.mkdir(path.dirname(savePath), {
|
await this.fs.promises.mkdir(path.dirname(savePath), {
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,11 @@ export class NativeFileApp {
|
||||||
return this.fileFacade.openFolderChooser()
|
return this.fileFacade.openFolderChooser()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async openMacImportFileChooser(): Promise<Array<FileReference>> {
|
||||||
|
const files = await this.fileFacade.openMacImportFileChooser()
|
||||||
|
return promiseMap(files, this.uriToFileRef.bind(this))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the file.
|
* Deletes the file.
|
||||||
* @param file The uri of the file to delete.
|
* @param file The uri of the file to delete.
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,11 @@ export interface FileFacade {
|
||||||
*/
|
*/
|
||||||
openFolderChooser(): Promise<string | null>
|
openFolderChooser(): Promise<string | null>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens OS file picker for selecting either a file or folder for Email Import. Works only on macOS
|
||||||
|
*/
|
||||||
|
openMacImportFileChooser(): Promise<ReadonlyArray<string>>
|
||||||
|
|
||||||
deleteFile(file: string): Promise<void>
|
deleteFile(file: string): Promise<void>
|
||||||
|
|
||||||
getName(file: string): Promise<string>
|
getName(file: string): Promise<string>
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,9 @@ export class FileFacadeReceiveDispatcher {
|
||||||
case "openFolderChooser": {
|
case "openFolderChooser": {
|
||||||
return this.facade.openFolderChooser()
|
return this.facade.openFolderChooser()
|
||||||
}
|
}
|
||||||
|
case "openMacImportFileChooser": {
|
||||||
|
return this.facade.openMacImportFileChooser()
|
||||||
|
}
|
||||||
case "deleteFile": {
|
case "deleteFile": {
|
||||||
const file: string = arg[0]
|
const file: string = arg[0]
|
||||||
return this.facade.deleteFile(file)
|
return this.facade.deleteFile(file)
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@ export class FileFacadeSendDispatcher implements FileFacade {
|
||||||
async openFolderChooser(...args: Parameters<FileFacade["openFolderChooser"]>) {
|
async openFolderChooser(...args: Parameters<FileFacade["openFolderChooser"]>) {
|
||||||
return this.transport.invokeNative("ipc", ["FileFacade", "openFolderChooser", ...args])
|
return this.transport.invokeNative("ipc", ["FileFacade", "openFolderChooser", ...args])
|
||||||
}
|
}
|
||||||
|
async openMacImportFileChooser(...args: Parameters<FileFacade["openMacImportFileChooser"]>) {
|
||||||
|
return this.transport.invokeNative("ipc", ["FileFacade", "openMacImportFileChooser", ...args])
|
||||||
|
}
|
||||||
async deleteFile(...args: Parameters<FileFacade["deleteFile"]>) {
|
async deleteFile(...args: Parameters<FileFacade["deleteFile"]>) {
|
||||||
return this.transport.invokeNative("ipc", ["FileFacade", "deleteFile", ...args])
|
return this.transport.invokeNative("ipc", ["FileFacade", "deleteFile", ...args])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import { ColumnWidth, Table, TableLineAttrs } from "../../common/gui/base/Table.
|
||||||
import { mailLocator } from "../mailLocator.js"
|
import { mailLocator } from "../mailLocator.js"
|
||||||
import { formatDate } from "../../common/misc/Formatter.js"
|
import { formatDate } from "../../common/misc/Formatter.js"
|
||||||
import { LoginButton, LoginButtonType } from "../../common/gui/base/buttons/LoginButton"
|
import { LoginButton, LoginButtonType } from "../../common/gui/base/buttons/LoginButton"
|
||||||
|
import { client } from "../../common/misc/ClientDetector"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings viewer for mail import rendered only in the Desktop client.
|
* Settings viewer for mail import rendered only in the Desktop client.
|
||||||
|
|
@ -59,7 +60,9 @@ export class DesktopMailImportSettingsViewer implements UpdatableSettingsViewer
|
||||||
}
|
}
|
||||||
|
|
||||||
const allowedExtensions = ["eml", "mbox"]
|
const allowedExtensions = ["eml", "mbox"]
|
||||||
const filePaths = await mailLocator.fileApp.openFileChooser(dom.getBoundingClientRect(), allowedExtensions, true)
|
const filePaths = client.isMacOS
|
||||||
|
? await mailLocator.fileApp.openMacImportFileChooser()
|
||||||
|
: await mailLocator.fileApp.openFileChooser(dom.getBoundingClientRect(), allowedExtensions, true)
|
||||||
await this.mailImporter().onStartBtnClick(filePaths.map((fp) => fp.location))
|
await this.mailImporter().onStartBtnClick(filePaths.map((fp) => fp.location))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue