Repository: hovancik/stretchly (js)

Issue:
Redundant title notification on macOS Big Sur 
<!--

Have you read Code of Conduct? By filing an Issue, you are expected to comply with it, including treating everyone with respect: https://github.com/hovancik/stretchly/blob/master/CODE_OF_CONDUCT.md

-->

### Prerequisites

- [✅] I'm using latest version: v1.3.0 <!-- type your version from `Preferences` -  `About` -->
- [✅] I've checked [Known issues](https://github.com/hovancik/stretchly#known-issues)
- [✅] I've checked [Open issues](https://github.com/hovancik/stretchly/issues)

### Description

In the latest update of macOS, each notification includes the app name and icon, so it would be good to hide the second 'Stretchly' in Big Sur.

Operating system: macOS Big Sur 11.0.1 <!-- type your OS and version -->

### Steps to Reproduce

1. Wait for a break notification
2. See the duplicate app name

**Expected behavior:** No duplication of name

**Actual behavior:** Duplication of name

**Reproduces how often:** Every notification

### Additional Information

Screenshot for reference:
<img width="390" alt="Screenshot 2020-11-13 at 12 36 47" src="https://user-images.githubusercontent.com/10728085/99073519-f2eb2a00-25ad-11eb-95a1-a9461d31800d.png">

Probably can be mitigated with a small fix, see #745 


Pull request:
Don't show notification title for macOS Big Sur
closes #767 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f1d8c4..4c10c0e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 ### Fixed
 - notification of new version being showed even disabled
 - browser tab non-responsive after resuming
+- don't show notification title for macOS Big Sur
 
 ## [1.3.0] - 2020-11-08
 ### Added
diff --git a/app/process.js b/app/process.js
index c99d95e..dcb8e58 100644
--- a/app/process.js
+++ b/app/process.js
@@ -2,6 +2,7 @@ const { ipcRenderer, shell, remote } = require('electron')
 const VersionChecker = require('./utils/versionChecker')
 const i18next = remote.require('i18next')
 const semver = require('semver')
+const { shouldShowNotificationTitle } = require('./utils/utils')
 
 ipcRenderer.on('playSound', (event, file, volume) => {
   const audio = new Audio(`audio/${file}.wav`)
@@ -30,19 +31,18 @@ ipcRenderer.on('checkVersion', (event, { oldVersion, notify, silent }) => {
 })
 
 ipcRenderer.on('showNotification', (event, { text, silent }) => {
-  // only set a visible title for non-windows platforms and windows before 10.0.19042 (20H2 Update)
-  const showTitle = (process.platform !== 'win32' || process.getSystemVersion().split('.')[2] < 19042)
-
-  new Notification(showTitle ? 'Stretchly' : '', { // eslint-disable-line no-new
+  const title = shouldShowNotificationTitle(process.platform, process.getSystemVersion()) ? 'Stretchly' : ''
+  new Notification(title, { // eslint-disable-line no-new
     body: text,
-    silent
+    silent: silent
   })
 })
 
 function notifyNewVersion (silent) {
-  const notification = new Notification('Stretchly', {
+  const title = shouldShowNotificationTitle(process.platform, process.getSystemVersion()) ? 'Stretchly' : ''
+  const notification = new Notification(title, {
     body: i18next.t('process.newVersionAvailable'),
-    silent
+    silent: silent
   })
   notification.onclick = () => shell.openExternal('https://hovancik.net/stretchly/downloads')
 }
diff --git a/app/utils/utils.js b/app/utils/utils.js
index 428c2ae..512f1ed 100644
--- a/app/utils/utils.js
+++ b/app/utils/utils.js
@@ -1,3 +1,5 @@
+const semver = require('semver')
+
 // TODO if I am not wrong, formatting function are mathematically the same
 // Would be nice to not have the same code
 const formatTimeRemaining = function (milliseconds, i18next = require('i18next')) {
@@ -67,10 +69,21 @@ function formatKeyboardShortcut (keyboardShortcut) {
   return keyboardShortcut.replace('Or', '/').replace('+', ' + ')
 }
 
+function shouldShowNotificationTitle (platform, systemVersion) {
+  if (platform === 'win32' && semver.gte(semver.coerce(systemVersion), '10.0.19042')) {
+    return false
+  }
+  if (platform === 'darwin' && semver.gte(semver.coerce(systemVersion), '10.16.0')) {
+    return false
+  }
+  return true
+}
+
 module.exports = {
   formatTimeRemaining,
   formatTimeIn,
   canPostpone,
   canSkip,
-  formatKeyboardShortcut
+  formatKeyboardShortcut,
+  shouldShowNotificationTitle
 }


Test patch:
diff --git a/test/utils.js b/test/utils.js
index 0b9dfb4..89dbc58 100644
--- a/test/utils.js
+++ b/test/utils.js
@@ -1,7 +1,8 @@
 const chai = require('chai')
 const {
   formatTimeRemaining, formatTimeIn,
-  canSkip, canPostpone, formatKeyboardShortcut
+  canSkip, canPostpone, formatKeyboardShortcut,
+  shouldShowNotificationTitle
 } = require('../app/utils/utils')
 const i18next = require('i18next')
 const path = require('path')
@@ -137,4 +138,24 @@ describe('canSkip and canPostpone', () => {
       formatKeyboardShortcut('Command+X').should.equal('Command + X')
     })
   })
+
+  describe('shouldShowNotificationTitle', () => {
+    it('works for older windows', () => {
+      shouldShowNotificationTitle('win32', '10.0.19041').should.equal(true)
+      shouldShowNotificationTitle('win32', '6.3.9600').should.equal(true)
+    })
+    it('works for new windows', () => {
+      shouldShowNotificationTitle('win32', '10.0.19042').should.equal(false)
+    })
+    it('works for older mac', () => {
+      shouldShowNotificationTitle('darwin', '10.15.1').should.equal(true)
+    })
+    it('works for new mac', () => {
+      shouldShowNotificationTitle('darwin', '10.16').should.equal(false)
+      shouldShowNotificationTitle('darwin', '11.0.1').should.equal(false)
+    })
+    it('works for others', () => {
+      shouldShowNotificationTitle('linux', '1.0.0').should.equal(true)
+    })
+  })
 })