Add Desktop Notifications
This commit is contained in:
committed by
Deluan Quintão
parent
b8d47d1db4
commit
2397a7e464
@@ -22,6 +22,7 @@ import {
|
|||||||
playQueueReducer,
|
playQueueReducer,
|
||||||
albumViewReducer,
|
albumViewReducer,
|
||||||
activityReducer,
|
activityReducer,
|
||||||
|
settingsReducer,
|
||||||
} from './reducers'
|
} from './reducers'
|
||||||
import createAdminStore from './store/createAdminStore'
|
import createAdminStore from './store/createAdminStore'
|
||||||
import { i18nProvider } from './i18n'
|
import { i18nProvider } from './i18n'
|
||||||
@@ -50,6 +51,7 @@ const App = () => (
|
|||||||
theme: themeReducer,
|
theme: themeReducer,
|
||||||
addToPlaylistDialog: addToPlaylistDialogReducer,
|
addToPlaylistDialog: addToPlaylistDialogReducer,
|
||||||
activity: activityReducer,
|
activity: activityReducer,
|
||||||
|
settings: settingsReducer,
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ export * from './themes'
|
|||||||
export * from './albumView'
|
export * from './albumView'
|
||||||
export * from './dialogs'
|
export * from './dialogs'
|
||||||
export * from './serverEvents'
|
export * from './serverEvents'
|
||||||
|
export * from './settings'
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export const SET_NOTIFICATIONS_STATE = 'SET_NOTIFICATIONS_STATE'
|
||||||
|
|
||||||
|
export const setNotificationsState = (enabled) => ({
|
||||||
|
type: SET_NOTIFICATIONS_STATE,
|
||||||
|
data: enabled,
|
||||||
|
})
|
||||||
@@ -18,6 +18,7 @@ import themes from '../themes'
|
|||||||
import config from '../config'
|
import config from '../config'
|
||||||
import PlayerToolbar from './PlayerToolbar'
|
import PlayerToolbar from './PlayerToolbar'
|
||||||
import { useHotkeys } from 'react-hotkeys-hook'
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
|
import { sendNotification, baseUrl } from '../utils'
|
||||||
|
|
||||||
const useStyle = makeStyles((theme) => ({
|
const useStyle = makeStyles((theme) => ({
|
||||||
audioTitle: {
|
audioTitle: {
|
||||||
@@ -54,6 +55,7 @@ const Player = () => {
|
|||||||
const queue = useSelector((state) => state.queue)
|
const queue = useSelector((state) => state.queue)
|
||||||
const current = queue.current || {}
|
const current = queue.current || {}
|
||||||
const { authenticated } = useAuthState()
|
const { authenticated } = useAuthState()
|
||||||
|
const showNotifications = useSelector((state) => state.settings.notifications || false)
|
||||||
|
|
||||||
const visible = authenticated && queue.queue.length > 0
|
const visible = authenticated && queue.queue.length > 0
|
||||||
const classes = useStyle({ visible })
|
const classes = useStyle({ visible })
|
||||||
@@ -230,9 +232,12 @@ const Player = () => {
|
|||||||
label: `${info.name} - ${info.singer}`,
|
label: `${info.name} - ${info.singer}`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if (showNotifications) {
|
||||||
|
sendNotification(info.name, `${info.singer} - ${info.album}`, baseUrl(info.cover))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch, showNotifications]
|
||||||
)
|
)
|
||||||
|
|
||||||
const onAudioPause = useCallback(
|
const onAudioPause = useCallback(
|
||||||
|
|||||||
+4
-2
@@ -262,7 +262,8 @@
|
|||||||
"songsAddedToPlaylist": "Added 1 song to playlist |||| Added %{smart_count} songs to playlist",
|
"songsAddedToPlaylist": "Added 1 song to playlist |||| Added %{smart_count} songs to playlist",
|
||||||
"noPlaylistsAvailable": "None available",
|
"noPlaylistsAvailable": "None available",
|
||||||
"delete_user_title": "Delete user '%{name}'",
|
"delete_user_title": "Delete user '%{name}'",
|
||||||
"delete_user_content": "Are you sure you want to delete this user and all their data (including playlists and preferences)?"
|
"delete_user_content": "Are you sure you want to delete this user and all their data (including playlists and preferences)?",
|
||||||
|
"notifications_blocked": "You have blocked Notifications for this site in your browser's settings or your browser does not support notifications."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"library": "Library",
|
"library": "Library",
|
||||||
@@ -274,7 +275,8 @@
|
|||||||
"options": {
|
"options": {
|
||||||
"theme": "Theme",
|
"theme": "Theme",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"defaultView": "Default View"
|
"defaultView": "Default View",
|
||||||
|
"desktop_notifications": "Desktop Notifications"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"albumList": "Albums",
|
"albumList": "Albums",
|
||||||
|
|||||||
@@ -8,10 +8,15 @@ import {
|
|||||||
useLocale,
|
useLocale,
|
||||||
useSetLocale,
|
useSetLocale,
|
||||||
useTranslate,
|
useTranslate,
|
||||||
|
BooleanInput,
|
||||||
|
useNotify,
|
||||||
} from 'react-admin'
|
} from 'react-admin'
|
||||||
import { makeStyles } from '@material-ui/core/styles'
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
import HelpOutlineIcon from '@material-ui/icons/HelpOutline'
|
import HelpOutlineIcon from '@material-ui/icons/HelpOutline'
|
||||||
import { changeTheme } from '../actions'
|
import {
|
||||||
|
changeTheme,
|
||||||
|
setNotificationsState,
|
||||||
|
} from '../actions'
|
||||||
import themes from '../themes'
|
import themes from '../themes'
|
||||||
import { docsUrl } from '../utils'
|
import { docsUrl } from '../utils'
|
||||||
import { useGetLanguageChoices } from '../i18n'
|
import { useGetLanguageChoices } from '../i18n'
|
||||||
@@ -119,6 +124,45 @@ const SelectDefaultView = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NotificationsToggle = (props) => {
|
||||||
|
const translate = useTranslate()
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
const notify = useNotify()
|
||||||
|
const currentSetting = useSelector((state) => state.settings.notifications)
|
||||||
|
const current = (() => {
|
||||||
|
if (!("Notification" in window) || Notification.permission !== 'granted') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return currentSetting
|
||||||
|
})()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BooleanInput
|
||||||
|
{...props}
|
||||||
|
source='notifications'
|
||||||
|
label={translate('menu.personal.options.desktop_notifications')}
|
||||||
|
defaultValue={current}
|
||||||
|
onChange={async (notificationsEnabled) => {
|
||||||
|
if (notificationsEnabled) {
|
||||||
|
if (!('Notification' in window) || Notification.permission === 'denied') {
|
||||||
|
notify(translate('message.notifications_blocked'), 'warning')
|
||||||
|
notificationsEnabled = false
|
||||||
|
} else {
|
||||||
|
const response = await Notification.requestPermission()
|
||||||
|
if (response !== 'granted') {
|
||||||
|
notificationsEnabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!notificationsEnabled) {
|
||||||
|
// Need to turn switch off
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dispatch(setNotificationsState(notificationsEnabled))
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const Personal = () => {
|
const Personal = () => {
|
||||||
const translate = useTranslate()
|
const translate = useTranslate()
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
@@ -130,6 +174,7 @@ const Personal = () => {
|
|||||||
<SelectTheme />
|
<SelectTheme />
|
||||||
<SelectLanguage />
|
<SelectLanguage />
|
||||||
<SelectDefaultView />
|
<SelectDefaultView />
|
||||||
|
<NotificationsToggle />
|
||||||
</SimpleForm>
|
</SimpleForm>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ export * from './dialogReducer'
|
|||||||
export * from './playQueue'
|
export * from './playQueue'
|
||||||
export * from './albumView'
|
export * from './albumView'
|
||||||
export * from './activityReducer'
|
export * from './activityReducer'
|
||||||
|
export * from './settingsReducer'
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ const mapToAudioLists = (item) => {
|
|||||||
trackId: id,
|
trackId: id,
|
||||||
name: item.title,
|
name: item.title,
|
||||||
singer: item.artist,
|
singer: item.artist,
|
||||||
|
album: item.album,
|
||||||
albumId: item.albumId,
|
albumId: item.albumId,
|
||||||
artistId: item.albumArtistId,
|
artistId: item.albumArtistId,
|
||||||
duration: item.duration,
|
duration: item.duration,
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { SET_NOTIFICATIONS_STATE } from '../actions'
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
notifications: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const settingsReducer = (previousState = initialState, payload) => {
|
||||||
|
const { type, data } = payload
|
||||||
|
switch (type) {
|
||||||
|
case SET_NOTIFICATIONS_STATE:
|
||||||
|
return {
|
||||||
|
...previousState,
|
||||||
|
notifications: data
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return previousState
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,6 +50,7 @@ export default ({
|
|||||||
theme: state.theme,
|
theme: state.theme,
|
||||||
queue: pick(state.queue, ['queue', 'volume']),
|
queue: pick(state.queue, ['queue', 'volume']),
|
||||||
albumView: state.albumView,
|
albumView: state.albumView,
|
||||||
|
settings: state.settings,
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
1000
|
1000
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from './baseUrl'
|
export * from './baseUrl'
|
||||||
export * from './docsUrl'
|
export * from './docsUrl'
|
||||||
export * from './formatters'
|
export * from './formatters'
|
||||||
|
export * from './notifications'
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
export const sendNotification = (title, body = '', image = '') => {
|
||||||
|
checkForNotificationPermission()
|
||||||
|
new Notification(title, {
|
||||||
|
body: body,
|
||||||
|
icon: image,
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkForNotificationPermission = () => {
|
||||||
|
return 'Notification' in window && Notification.permission === 'granted'
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user