diff --git a/Assets/WebsiteAssets/images/BadgeMacOSM1.png b/Assets/WebsiteAssets/images/BadgeMacOSM1.png new file mode 100644 index 000000000..3ce6cfee7 Binary files /dev/null and b/Assets/WebsiteAssets/images/BadgeMacOSM1.png differ diff --git a/Assets/WebsiteAssets/js/script.js b/Assets/WebsiteAssets/js/script.js index 902ca8358..f61464fbb 100644 --- a/Assets/WebsiteAssets/js/script.js +++ b/Assets/WebsiteAssets/js/script.js @@ -1,6 +1,31 @@ -function getOs() { +async function getOs() { + + // The macOS release is available for Intel and Apple silicon processors, + // and the only way to get that info is through this new + // `getHighEntropyValues` function (which is not available on all browsers). + // So here we either return "macOs" for Intel or "macOsM1" for Apple + // Silicon. If we don't know which it is, we return "macOsUndefined". + // https://stackoverflow.com/a/75177111/561309 + + if (navigator.appVersion.indexOf("Mac")!=-1) { + let platformInfo = null; + try { + platformInfo = await navigator.userAgentData.getHighEntropyValues(['architecture']) + } catch (error) { + console.warn('Failed getting Mac architecture:', error); + return 'macOsUndefined'; + } + + console.info('Got platform info:', platformInfo); + + if (platformInfo.architecture === 'arm') { + return "macOsM1"; + } else { + return "macOs"; + } + } + if (navigator.appVersion.indexOf("Win")!=-1) return "windows"; - if (navigator.appVersion.indexOf("Mac")!=-1) return "macOs"; if (navigator.appVersion.indexOf("X11")!=-1) return "linux"; if (navigator.appVersion.indexOf("Linux")!=-1) return "linux"; return null; @@ -45,7 +70,7 @@ function setupMobileMenu() { }); } -function setupDownloadPage() { +async function setupDownloadPage() { if (!$('.page-download').length) return; const downloadLinks = {}; @@ -55,6 +80,7 @@ function setupDownloadPage() { if (href.indexOf('-Setup') > 0) downloadLinks['windows'] = href; if (href.indexOf('.dmg') > 0) downloadLinks['macOs'] = href; + if (href.endsWith('arm64.DMG')) downloadLinks['macOsM1'] = href; if (href.indexOf('.AppImage') > 0) downloadLinks['linux'] = href; }); @@ -70,8 +96,17 @@ function setupDownloadPage() { if (mobileOs) { $('.page-download .intro').hide(); } else { - const os = getOs(); - if (!os || !downloadLinks[os]) { + const os = await getOs(); + + if (os === 'macOsUndefined') { + // If we don't know which macOS version it is, we let the user choose. + $('.main-content .intro').html('

The macOS release is available for Intel processors or for Apple Silicon (M1) processors. Please select your version:

'); + const macOsLink = $('.download-link-macOs'); + const macOsM1Link = $('.download-link-macOsM1'); + $('.macos-m1-info').after('

To find out what processor you have, click on the Apple logo in the macOS menu bar, choose About This Mac from the dropdown menu. If you have an Apple silicon it should say"Apple M1" under "Chip". Otherwise you have an Intel processor.

'); + $('.macos-m1-info').after(macOsM1Link); + $('.macos-m1-info').after(macOsLink); + } else if (!os || !downloadLinks[os]) { // If we don't know, display the section to manually download the app $('.page-download .get-it-desktop').show(); } else if (os === 'linux') { @@ -89,5 +124,5 @@ function setupDownloadPage() { $(function () { setupMobileMenu(); - setupDownloadPage(); + void setupDownloadPage(); }); diff --git a/packages/tools/update-readme-download.ts b/packages/tools/update-readme-download.ts index a00e115b9..1d8f818c0 100644 --- a/packages/tools/update-readme-download.ts +++ b/packages/tools/update-readme-download.ts @@ -13,6 +13,7 @@ async function msleep(ms: number) { export enum OS { MacOs = 'macos', + MacOsM1 = 'macosm1', Windows = 'windows', Android = 'android', Android32 = 'android32', @@ -31,7 +32,11 @@ export const downloadUrl = (release: GitHubRelease, os: OS, portable = false) => const githubUrl = 'github.com/laurent22/joplin/releases/download/'; const joplinDomain = 'objects.joplinusercontent.com/'; - if (ext === 'dmg' && os === OS.MacOs) return asset.browser_download_url.replace(githubUrl, joplinDomain); + if (name.endsWith('arm64.DMG') && os === OS.MacOsM1) { + return asset.browser_download_url.replace(githubUrl, joplinDomain); + } else if (ext === 'dmg' && os === OS.MacOs) { + return asset.browser_download_url.replace(githubUrl, joplinDomain); + } if (ext === 'exe' && os === OS.Windows) { if (portable) { @@ -81,29 +86,28 @@ async function main(argv: any) { const androidRelease = await gitHubLatestRelease('joplin-android'); - // const android32Url = downloadUrl(androidRelease, OS.Android32); const androidUrl = downloadUrl(androidRelease, OS.Android); const winUrl = downloadUrl(release, OS.Windows); const winPortableUrl = downloadUrl(release, OS.Windows, true); const macOsUrl = downloadUrl(release, OS.MacOs); + const macOsM1Url = downloadUrl(release, OS.MacOsM1); const linuxUrl = downloadUrl(release, OS.Linux); console.info('Windows: ', winUrl); console.info('Windows Portable: ', winPortableUrl); console.info('macOS: ', macOsUrl); + console.info('macOSM1: ', macOsM1Url); console.info('Linux: ', linuxUrl); console.info('Android: ', androidUrl); - // console.info('Android 32: ', android32Url); let content = readmeContent(); if (winUrl) content = content.replace(/(https:\/\/objects.joplinusercontent.com\/v\d+\.\d+\.\d+\/Joplin-Setup-.*?\.exe)/, winUrl); if (winPortableUrl) content = content.replace(/(https:\/\/objects.joplinusercontent.com\/v\d+\.\d+\.\d+\/JoplinPortable.exe)/, winPortableUrl); if (macOsUrl) content = content.replace(/(https:\/\/objects.joplinusercontent.com\/v\d+\.\d+\.\d+\/Joplin-.*?\.dmg)/, macOsUrl); + if (macOsM1Url) content = content.replace(/(https:\/\/objects.joplinusercontent.com\/v\d+\.\d+\.\d+\/Joplin-.*?arm64\.DMG)/, macOsM1Url); if (linuxUrl) content = content.replace(/(https:\/\/objects.joplinusercontent.com\/v\d+\.\d+\.\d+\/Joplin-.*?\.AppImage)/, linuxUrl); - if (androidUrl) content = content.replace(/(https:\/\/objects.joplinusercontent.com\/v\d+\.\d+\.\d+\/joplin-v\d+\.\d+\.\d+\.apk)/, androidUrl); - // if (android32Url) content = content.replace(/(https:\/\/objects.joplinusercontent.com\/v\d+\.\d+\.\d+\/joplin-v\d+\.\d+\.\d+-32bit\.apk)/, android32Url); setReadmeContent(content); } diff --git a/packages/tools/website/updateDownloadPage.ts b/packages/tools/website/updateDownloadPage.ts index c06af73d1..7a6d48e10 100644 --- a/packages/tools/website/updateDownloadPage.ts +++ b/packages/tools/website/updateDownloadPage.ts @@ -1,7 +1,7 @@ import { readFile } from 'fs-extra'; import { rootDir, insertContentIntoFile } from '../tool-utils'; -async function getReadmeMd() { +async function getInstallMd() { return readFile(`${rootDir}/readme/install.md`, 'utf8'); } @@ -9,25 +9,28 @@ async function createDownloadButtonsHtml(readmeMd: string): Promise = {}; output['windows'] = readmeMd.match(/()/)[0]; output['macOs'] = readmeMd.match(/()/)[0]; + output['macOsM1'] = readmeMd.match(/()/)[0]; output['linux'] = readmeMd.match(/()/)[0]; output['android'] = readmeMd.match(/(', '', desktopButtonsHtml.join(' ')); await insertContentIntoFile(`${rootDir}/readme/download.md`, '', '', mobileButtonsHtml.join(' ')); } + +const main = async () => { + await updateDownloadPage(); +}; + +if (require.main === module) { + // eslint-disable-next-line promise/prefer-await-to-then + main().catch((error) => { + console.error('Fatal error'); + console.error(error); + process.exit(1); + }); +} diff --git a/readme/download.md b/readme/download.md index 95c33c66b..038c2e098 100644 --- a/readme/download.md +++ b/readme/download.md @@ -10,7 +10,7 @@ Your download of Joplin is in progress. Access your notes on Windows, macOS or Linux. -Get it on Windows Get it on macOS Get it on Linux +Get it on Windows Get it on macOS Get it on macOS M1 (Silicon) Get it on Linux @@ -22,7 +22,7 @@ To synchronise your notes on all your devices, whether it's on desktop, mobile o Access your notes on your phone or tablet from the Android and iOS apps. -Get it on Google Play Get it on the App Store +Get it on Google Play Get it on the App Store ## More Joplin Versions diff --git a/readme/install.md b/readme/install.md index 1235fac83..2f0a04429 100644 --- a/readme/install.md +++ b/readme/install.md @@ -12,6 +12,7 @@ Operating System | Download ---|--- Windows (32 and 64-bit) | Get it on Windows macOS | Get it on macOS +macOS M1 (Apple Silicon) | Get it on macOS M1 (Silicon) Linux | Get it on Linux **On Windows**, you may also use the Portable version. The [portable application](https://en.wikipedia.org/wiki/Portable_application) allows installing the software on a portable device such as a USB key. Simply copy the file JoplinPortable.exe in any directory on that USB key ; the application will then create a directory called "JoplinProfile" next to the executable file.