diff --git a/i18n/en.json b/i18n/en.json index e2a38e15..dc53f598 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -43,6 +43,8 @@ "main.CriticalErrorHandler.uncaughtException.button.showDetails": "Show Details", "main.CriticalErrorHandler.uncaughtException.dialog.message": "The {appName} app quit unexpectedly. Click \"{showDetails}\" to learn more or \"{reopen}\" to open the application again.\n\nInternal error: {err}", "main.CriticalErrorHandler.unresponsive.dialog.message": "The window is no longer responsive.\nDo you want to wait until the window becomes responsive again?", + "main.downloadsManager.resetDownloadsFolder": "Please reset the folder where files will download", + "main.downloadsManager.specifyDownloadsFolder": "Specify the folder where files will download", "main.menus.app.edit": "&Edit", "main.menus.app.edit.copy": "Copy", "main.menus.app.edit.cut": "Cut", diff --git a/src/main/app/initialize.ts b/src/main/app/initialize.ts index bda850ae..7d6d5a94 100644 --- a/src/main/app/initialize.ts +++ b/src/main/app/initialize.ts @@ -13,7 +13,6 @@ import { QUIT, SHOW_NEW_SERVER_MODAL, NOTIFY_MENTION, - GET_DOWNLOAD_LOCATION, SWITCH_TAB, CLOSE_TAB, OPEN_TAB, @@ -92,7 +91,6 @@ import { handleMentionNotification, handleOpenAppMenu, handleQuit, - handleSelectDownload, handlePingDomain, } from './intercom'; import { @@ -290,7 +288,6 @@ function initializeInterCommunicationEventListeners() { ipcMain.on(SHOW_EDIT_SERVER_MODAL, handleEditServerModal); ipcMain.on(SHOW_REMOVE_SERVER_MODAL, handleRemoveServerModal); ipcMain.handle(GET_AVAILABLE_SPELL_CHECKER_LANGUAGES, () => session.defaultSession.availableSpellCheckerLanguages); - ipcMain.handle(GET_DOWNLOAD_LOCATION, handleSelectDownload); ipcMain.on(START_UPDATE_DOWNLOAD, handleStartDownload); ipcMain.on(START_UPGRADE, handleStartUpgrade); ipcMain.handle(PING_DOMAIN, handlePingDomain); diff --git a/src/main/app/intercom.ts b/src/main/app/intercom.ts index 7f4cab6a..9bfcfc69 100644 --- a/src/main/app/intercom.ts +++ b/src/main/app/intercom.ts @@ -1,18 +1,17 @@ // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {app, dialog, IpcMainEvent, IpcMainInvokeEvent, Menu} from 'electron'; +import {app, IpcMainEvent, IpcMainInvokeEvent, Menu} from 'electron'; import {MattermostTeam} from 'types/config'; import {MentionData} from 'types/notification'; -import Config from 'common/config'; import {Logger} from 'common/log'; +import ServerManager from 'common/servers/serverManager'; import {ping} from 'common/utils/requests'; import {displayMention} from 'main/notifications'; import {getLocalPreload, getLocalURLString} from 'main/utils'; -import ServerManager from 'common/servers/serverManager'; import ModalManager from 'main/views/modalManager'; import MainWindow from 'main/windows/mainWindow'; @@ -130,17 +129,6 @@ export function handleOpenAppMenu() { }); } -export async function handleSelectDownload(event: IpcMainInvokeEvent, startFrom: string) { - log.debug('handleSelectDownload', startFrom); - - const message = 'Specify the folder where files will download'; - const result = await dialog.showOpenDialog({defaultPath: startFrom || Config.downloadLocation, - message, - properties: - ['openDirectory', 'createDirectory', 'dontAddToRecent', 'promptToCreate']}); - return result.filePaths[0]; -} - export function handlePingDomain(event: IpcMainInvokeEvent, url: string): Promise { return Promise.allSettled([ ping(new URL(`https://${url}`)), diff --git a/src/main/downloadsManager.ts b/src/main/downloadsManager.ts index f7cfd7eb..43924fee 100644 --- a/src/main/downloadsManager.ts +++ b/src/main/downloadsManager.ts @@ -3,7 +3,7 @@ import path from 'path'; import fs from 'fs'; -import {DownloadItem, Event, WebContents, FileFilter, ipcMain, dialog, shell, Menu, app} from 'electron'; +import {DownloadItem, Event, WebContents, FileFilter, ipcMain, dialog, shell, Menu, app, IpcMainInvokeEvent} from 'electron'; import {ProgressInfo, UpdateInfo} from 'electron-updater'; import {DownloadedItem, DownloadItemDoneEventState, DownloadedItems, DownloadItemState, DownloadItemUpdatedEventState} from 'types/downloads'; @@ -12,6 +12,7 @@ import { CLOSE_DOWNLOADS_DROPDOWN, CLOSE_DOWNLOADS_DROPDOWN_MENU, DOWNLOADS_DROPDOWN_FOCUSED, + GET_DOWNLOAD_LOCATION, HIDE_DOWNLOADS_DROPDOWN_BUTTON_BADGE, NO_UPDATE_AVAILABLE, OPEN_DOWNLOADS_DROPDOWN, @@ -89,12 +90,14 @@ export class DownloadsManager extends JsonFileManager { return this.hasDownloads(); }); + ipcMain.removeHandler(GET_DOWNLOAD_LOCATION); ipcMain.removeListener(DOWNLOADS_DROPDOWN_FOCUSED, this.clearAutoCloseTimeout); ipcMain.removeListener(UPDATE_AVAILABLE, this.onUpdateAvailable); ipcMain.removeListener(UPDATE_DOWNLOADED, this.onUpdateDownloaded); ipcMain.removeListener(UPDATE_PROGRESS, this.onUpdateProgress); ipcMain.removeListener(NO_UPDATE_AVAILABLE, this.noUpdateAvailable); + ipcMain.handle(GET_DOWNLOAD_LOCATION, this.handleSelectDownload); ipcMain.on(DOWNLOADS_DROPDOWN_FOCUSED, this.clearAutoCloseTimeout); ipcMain.on(UPDATE_AVAILABLE, this.onUpdateAvailable); ipcMain.on(UPDATE_DOWNLOADED, this.onUpdateDownloaded); @@ -134,7 +137,8 @@ export class DownloadsManager extends JsonFileManager { this.willDownloadURLs.set(url, {filePath: saveDialogResult.filePath, bookmark: saveDialogResult.bookmark}); } else { const filename = this.createFilename(item); - const savePath = this.getSavePath(`${Config.downloadLocation}`, filename); + const downloadLocation = await this.verifyMacAppStoreDownloadFolder(filename); + const savePath = this.getSavePath(`${downloadLocation}`, filename); this.willDownloadURLs.set(url, {filePath: savePath}); } @@ -374,6 +378,46 @@ export class DownloadsManager extends JsonFileManager { this.saveAll(downloads); }; + private handleSelectDownload = (event: IpcMainInvokeEvent, startFrom: string) => { + return this.selectDefaultDownloadDirectory( + startFrom, + localizeMessage('main.downloadsManager.specifyDownloadsFolder', 'Specify the folder where files will download'), + ); + } + + private selectDefaultDownloadDirectory = async (startFrom: string, message: string) => { + log.debug('handleSelectDownload', startFrom); + + const result = await dialog.showOpenDialog({defaultPath: startFrom || Config.downloadLocation, + message, + properties: + ['openDirectory', 'createDirectory', 'dontAddToRecent', 'promptToCreate']}); + return result.filePaths[0]; + } + + private verifyMacAppStoreDownloadFolder = async (fileName: string) => { + let downloadLocation = Config.downloadLocation; + + // eslint-disable-next-line no-undef + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + if (__IS_MAC_APP_STORE__ && downloadLocation) { + try { + const savePath = this.getSavePath(downloadLocation, fileName); + fs.writeFileSync(savePath, ''); + fs.unlinkSync(savePath); + } catch (e) { + downloadLocation = await this.selectDefaultDownloadDirectory( + downloadLocation, + localizeMessage('main.downloadsManager.resetDownloadsFolder', 'Please reset the folder where files will download'), + ); + Config.set('downloadLocation', downloadLocation); + } + } + + return downloadLocation; + } + private markFileAsDeleted = (item: DownloadedItem) => { const fileId = this.getDownloadedFileId(item); const file = this.downloads[fileId];