From 46115de0501ff07cd23cc3aa302ccc7fb11bf07f Mon Sep 17 00:00:00 2001 From: alzamer Date: Mon, 8 Jan 2024 11:18:47 +0100 Subject: [PATCH 1/7] Added Blacklist QueuePopup button --- .../app/app/containers/QueuePopupButtons/index.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/app/app/containers/QueuePopupButtons/index.js b/packages/app/app/containers/QueuePopupButtons/index.js index 130d4317e6..d8a8683fb1 100644 --- a/packages/app/app/containers/QueuePopupButtons/index.js +++ b/packages/app/app/containers/QueuePopupButtons/index.js @@ -23,6 +23,7 @@ const QueuePopupButtons = ({ withAddToFavorites, withAddToDownloads, withAddToPlaylist, + withAddToBlacklist, handlePlayNow, handleAddFavorite, handleAddToDownloads, @@ -69,6 +70,14 @@ const QueuePopupButtons = ({ label='Download' /> )} + {withAddToBlacklist && ( + + )} ); @@ -104,7 +113,8 @@ QueuePopupButtons.propTypes = { withPlayNow: PropTypes.bool, withAddToFavorites: PropTypes.bool, withAddToDownloads: PropTypes.bool, - withAddToPlaylist: PropTypes.bool + withAddToPlaylist: PropTypes.bool, + withAddToBlacklist: PropTypes.bool }; QueuePopupButtons.defaultProps = { @@ -115,7 +125,8 @@ QueuePopupButtons.defaultProps = { withAddToPlaylist: true, withPlayNow: true, withAddToFavorites: true, - withAddToDownloads: true + withAddToDownloads: true, + withAddToBlacklist: true }; export default compose( From d0ca48cd384a36b38bd2890c0fa5ebaf80e40247 Mon Sep 17 00:00:00 2001 From: alzamer Date: Mon, 8 Jan 2024 12:23:08 +0100 Subject: [PATCH 2/7] Added Blacklist TrackPopup button --- .../app/containers/TrackPopupContainer/hooks.ts | 1 + .../app/containers/TrackPopupContainer/index.tsx | 5 ++++- .../app/containers/TrackTableContainer/index.tsx | 1 + packages/i18n/src/locales/en.json | 1 + packages/ui/lib/components/TrackPopup/index.tsx | 14 ++++++++++++++ 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/app/app/containers/TrackPopupContainer/hooks.ts b/packages/app/app/containers/TrackPopupContainer/hooks.ts index 32820e7e3e..5296124440 100644 --- a/packages/app/app/containers/TrackPopupContainer/hooks.ts +++ b/packages/app/app/containers/TrackPopupContainer/hooks.ts @@ -117,6 +117,7 @@ export const useTrackPopupProps = (track, thumb) => { textAddToPlaylist: t('add-to-playlist'), textCreatePlaylist: t('create-playlist'), textAddToDownloads: t('download'), + textAddToBlacklist: t('blacklist'), createPlaylistDialog: { title: t('create-playlist-dialog-title'), placeholder: t('create-playlist-dialog-placeholder'), diff --git a/packages/app/app/containers/TrackPopupContainer/index.tsx b/packages/app/app/containers/TrackPopupContainer/index.tsx index 6f9feef53d..3118529589 100644 --- a/packages/app/app/containers/TrackPopupContainer/index.tsx +++ b/packages/app/app/containers/TrackPopupContainer/index.tsx @@ -18,6 +18,7 @@ export type TrackPopupContainerProps = { withAddToFavorites?: boolean; withAddToPlaylist?: boolean; withAddToDownloads?: boolean; + withAddToBlacklist?: boolean; }; const TrackPopupContainer: React.FC = ({ @@ -31,7 +32,8 @@ const TrackPopupContainer: React.FC = ({ withPlayNow=true, withAddToFavorites=true, withAddToPlaylist=true, - withAddToDownloads=true + withAddToDownloads=true, + withAddToBlacklist=true }) => { const props = useTrackPopupProps(track, thumb); @@ -47,6 +49,7 @@ const TrackPopupContainer: React.FC = ({ withAddToFavorites={withAddToFavorites} withAddToPlaylist={withAddToPlaylist} withAddToDownloads={withAddToDownloads} + withAddToBlacklist={withAddToBlacklist} {...props} />; diff --git a/packages/app/app/containers/TrackTableContainer/index.tsx b/packages/app/app/containers/TrackTableContainer/index.tsx index cd07a78bf2..1ad98953aa 100644 --- a/packages/app/app/containers/TrackTableContainer/index.tsx +++ b/packages/app/app/containers/TrackTableContainer/index.tsx @@ -117,6 +117,7 @@ function TrackTableContainer ({ textAddToPlaylist: popupTranstation('add-to-playlist'), textCreatePlaylist: popupTranstation('create-playlist'), textAddToDownloads: popupTranstation('download'), + textAddToBlacklist: popupTranstation('blacklist'), createPlaylistDialog: { title: popupTranstation('create-playlist-dialog-title'), placeholder: popupTranstation('create-playlist-dialog-placeholder'), diff --git a/packages/i18n/src/locales/en.json b/packages/i18n/src/locales/en.json index a142ca28b2..76cf31fdb0 100644 --- a/packages/i18n/src/locales/en.json +++ b/packages/i18n/src/locales/en.json @@ -360,6 +360,7 @@ "download": "Download", "download-toast-body": "{{artist}} - {{track}} has been added to downloads.", "download-toast-title": "Track added to downloads", + "blacklist": "Blacklist", "favorite-toast-body": "{{artist}} - {{track}} has been added to favorites.", "favorite-toast-title": "Favorite track added", "play-next": "Play next", diff --git a/packages/ui/lib/components/TrackPopup/index.tsx b/packages/ui/lib/components/TrackPopup/index.tsx index 8c86e1bcec..b65f4a4b6c 100644 --- a/packages/ui/lib/components/TrackPopup/index.tsx +++ b/packages/ui/lib/components/TrackPopup/index.tsx @@ -25,6 +25,7 @@ export type TrackPopupProps = { withAddToFavorites?: boolean; withAddToPlaylist?: boolean; withAddToDownloads?: boolean; + withAddToBlacklist?: boolean; onAddToQueue?: () => void; onPlayNext?: () => void; @@ -43,6 +44,7 @@ export type TrackPopupStrings = { textAddToPlaylist: string; textCreatePlaylist: string; textAddToDownloads: string; + textAddToBlacklist: string; createPlaylistDialog: { title: string; placeholder: string; @@ -64,6 +66,7 @@ const TrackPopup: React.FC = ({ withAddToFavorites=true, withAddToPlaylist=true, withAddToDownloads=true, + withAddToBlacklist=true, strings={ textAddToQueue: 'Add to queue', textPlayNow: 'Play now', @@ -72,6 +75,7 @@ const TrackPopup: React.FC = ({ textAddToPlaylist: 'Add to playlist', textCreatePlaylist: 'Create new playlist', textAddToDownloads: 'Download', + textAddToBlacklist: 'Blacklist', createPlaylistDialog: { title: 'Input playlist name:', placeholder: 'Playlist name', @@ -171,6 +175,16 @@ const TrackPopup: React.FC = ({ label={strings.textAddToDownloads} /> )} + + {withAddToBlacklist && ( + + )} Date: Wed, 21 Feb 2024 21:06:01 +0100 Subject: [PATCH 3/7] Added Blacklist option to track popup --- packages/app/app/actions/blacklist.ts | 25 +++++++++++++++++++ .../app/containers/QueuePopupButtons/index.js | 22 ++++++++++++++-- .../containers/TrackTableContainer/index.tsx | 6 +++++ packages/app/app/reducers/blacklist.js | 20 +++++++++++++++ packages/app/app/reducers/index.ts | 2 ++ packages/core/src/persistence/store.js | 2 ++ .../ui/lib/components/TrackPopup/index.tsx | 6 +++-- .../components/TrackTable/Cells/TitleCell.tsx | 2 ++ .../ui/lib/components/TrackTable/index.tsx | 1 + .../ui/lib/components/TrackTable/types.ts | 2 ++ 10 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 packages/app/app/actions/blacklist.ts create mode 100644 packages/app/app/reducers/blacklist.js diff --git a/packages/app/app/actions/blacklist.ts b/packages/app/app/actions/blacklist.ts new file mode 100644 index 0000000000..6a6c6d8f87 --- /dev/null +++ b/packages/app/app/actions/blacklist.ts @@ -0,0 +1,25 @@ +import _, { flow, omit, unionWith } from 'lodash'; +import { store, Track } from '@nuclear/core'; +import { areTracksEqualByName, getTrackItem } from '@nuclear/ui'; + +import { safeAddUuid } from './helpers'; +import { createStandardAction } from 'typesafe-actions'; + +export const READ_BLACKLISTED = 'READ_BLACKLISTED'; +export const BLACKLIST_TRACK = 'BLACKLIST_TRACK'; +export const REMOVE_BLACKLISTED_TRACK = 'REMOVE_BLACKLISTED_TRACK'; + +export function addToBlacklist(track){ + const clonedTrack = flow(safeAddUuid, getTrackItem)(track); + + let blacklist = store.get('blacklist'); + const filteredTracks = blacklist.filter(t => !areTracksEqualByName(t, track)); + blacklist = [...filteredTracks, omit(clonedTrack, 'streams')]; + + store.set('blacklist', blacklist); + + return { + type: BLACKLIST_TRACK, + payload: blacklist + }; +} diff --git a/packages/app/app/containers/QueuePopupButtons/index.js b/packages/app/app/containers/QueuePopupButtons/index.js index d8a8683fb1..bd29233031 100644 --- a/packages/app/app/containers/QueuePopupButtons/index.js +++ b/packages/app/app/containers/QueuePopupButtons/index.js @@ -12,6 +12,7 @@ import * as QueueActions from '../../actions/queue'; import * as FavoritesActions from '../../actions/favorites'; import * as ToastActions from '../../actions/toasts'; import * as PlaylistsActions from '../../actions/playlists'; +import * as BlacklistActions from '../../actions/blacklist'; import { safeAddUuid } from '../../actions/helpers'; import { normalizeTrack } from '../../utils'; import { addTrackToPlaylist } from '../../components/PlayQueue/QueueMenu/QueueMenuMore'; @@ -27,7 +28,8 @@ const QueuePopupButtons = ({ handlePlayNow, handleAddFavorite, handleAddToDownloads, - handleAddToPlaylist + handleAddToPlaylist, + handleAddToBlacklist }) => ( <> {withPlayNow && ( @@ -72,7 +74,7 @@ const QueuePopupButtons = ({ )} {withAddToBlacklist && ( ({ downloadsActions: bindActionCreators(DownloadsActions, dispatch), queueActions: bindActionCreators(QueueActions, dispatch), favoritesActions: bindActionCreators(FavoritesActions, dispatch), + blacklistActions: bindActionCreators(BlacklistActions, dispatch), playlistsActions: bindActionCreators(PlaylistsActions, dispatch), toastActions: bindActionCreators(ToastActions, dispatch) }); @@ -152,6 +155,21 @@ export default compose( settings ); }, + handleAddToBlacklist: ({ + track, + settings, + blacklistActions, + toastActions + }) => () => { + const normalizedTrack = normalizeTrack(track); + blacklistActions.addToBlacklist(normalizedTrack); + toastActions.info( + 'Track added to blacklist', + `${track.artist} - ${track.name} has been added to blacklist.`, + , + settings + ); + }, handleAddToDownloads: ({ track, settings, diff --git a/packages/app/app/containers/TrackTableContainer/index.tsx b/packages/app/app/containers/TrackTableContainer/index.tsx index 1ad98953aa..f865f75d81 100644 --- a/packages/app/app/containers/TrackTableContainer/index.tsx +++ b/packages/app/app/containers/TrackTableContainer/index.tsx @@ -16,6 +16,7 @@ import * as queueActions from '../../actions/queue'; import * as playerActions from '../../actions/player'; import * as playlistActions from '../../actions/playlists'; import * as favoritesActions from '../../actions/favorites'; +import * as blacklistActions from '../../actions/blacklist'; import { favoritesSelectors } from '../../selectors/favorites'; import { safeAddUuid } from '../../actions/helpers'; @@ -71,6 +72,10 @@ function TrackTableContainer ({ dispatch(favoritesActions.addFavoriteTrack(track)); }, [dispatch]); + const onAddToBlacklist = useCallback((track: Track) => { + dispatch(blacklistActions.addToBlacklist(track)); + }, [dispatch]); + const onRemoveFromFavorites = useCallback((track: Track) => { dispatch(favoritesActions.removeFavoriteTrack(track)); }, [dispatch]); @@ -152,6 +157,7 @@ function TrackTableContainer ({ onPlayNext={onPlayNext} onPlayAll={onPlayAll} onAddToFavorites={Boolean(displayAddToFavorites) && onAddToFavorites} + onAddToBlacklist={onAddToBlacklist} onRemoveFromFavorites={onRemoveFromFavorites} onAddToDownloads={Boolean(displayAddToDownloads) && onAddToDownloads} onAddToPlaylist={onAddToPlaylist} diff --git a/packages/app/app/reducers/blacklist.js b/packages/app/app/reducers/blacklist.js new file mode 100644 index 0000000000..366e426e16 --- /dev/null +++ b/packages/app/app/reducers/blacklist.js @@ -0,0 +1,20 @@ +import { + READ_BLACKLISTED, + BLACKLIST_TRACK, + REMOVE_BLACKLISTED_TRACK +} from '../actions/blacklist'; + +const initialState = []; + +const BlacklistReducer = (state = initialState, action) => { + switch (action.type) { + case READ_BLACKLISTED: + case BLACKLIST_TRACK: + case REMOVE_BLACKLISTED_TRACK: + return { ...action.payload }; + default: + return state; + } +}; + +export default BlacklistReducer; diff --git a/packages/app/app/reducers/index.ts b/packages/app/app/reducers/index.ts index 5eb13ff682..efe7f2287c 100644 --- a/packages/app/app/reducers/index.ts +++ b/packages/app/app/reducers/index.ts @@ -5,6 +5,7 @@ import DashboardReducer from './dashboard'; import DownloadsReducer from './downloads'; import EqualizerReducer from './equalizer'; import FavoritesReducer from './favorites'; +import BlacklistReducer from './blacklist'; import GithubReducer from './github'; import GithubContribReducer from './githubContrib'; import LyricsReducer from './lyrics'; @@ -29,6 +30,7 @@ const rootReducer = combineReducers({ downloads: DownloadsReducer, equalizer: EqualizerReducer, favorites: FavoritesReducer, + blacklist: BlacklistReducer, github: GithubReducer, githubContrib: GithubContribReducer, importfavs: ImportFavsReducer, diff --git a/packages/core/src/persistence/store.js b/packages/core/src/persistence/store.js index f0d9c301f1..5d0bd165f6 100644 --- a/packages/core/src/persistence/store.js +++ b/packages/core/src/persistence/store.js @@ -24,6 +24,8 @@ function initStore() { setIfUnset('downloads', []); + setIfUnset('blacklist', []); + setIfUnset('equalizer', { selected: 'Default' }); diff --git a/packages/ui/lib/components/TrackPopup/index.tsx b/packages/ui/lib/components/TrackPopup/index.tsx index b65f4a4b6c..65c4d27ab8 100644 --- a/packages/ui/lib/components/TrackPopup/index.tsx +++ b/packages/ui/lib/components/TrackPopup/index.tsx @@ -34,6 +34,7 @@ export type TrackPopupProps = { onAddToPlaylist?: ({ name }: { name: string }) => void; onCreatePlaylist?: ({ name }: { name: string }) => void; onAddToDownloads?: () => void; + onAddToBlacklist?: () => void; }; export type TrackPopupStrings = { @@ -89,7 +90,8 @@ const TrackPopup: React.FC = ({ onAddToFavorites, onAddToPlaylist, onCreatePlaylist, - onAddToDownloads + onAddToDownloads, + onAddToBlacklist }) => { const [isCreatePlaylistDialogOpen, setIsCreatePlaylistDialogOpen] = useState(false); @@ -179,7 +181,7 @@ const TrackPopup: React.FC = ({ {withAddToBlacklist && ( & TrackTableExtraProps> = ({ onAddToPlaylist, onCreatePlaylist, onAddToDownloads, + onAddToBlacklist, playlists, popupActionStrings }) => & TrackTableExtraProps> = ({ onAddToPlaylist={(playlist: { name: string }) => onAddToPlaylist(row.original, playlist)} onCreatePlaylist={(options: { name: string }) => onCreatePlaylist(row.original, options)} onAddToDownloads={() => onAddToDownloads(row.original)} + onAddToBlacklist={() => onAddToBlacklist(row.original)} withPlayNow={Boolean(onPlay)} withPlayNext={Boolean(onPlayNext)} diff --git a/packages/ui/lib/components/TrackTable/index.tsx b/packages/ui/lib/components/TrackTable/index.tsx index d3ccc8153a..998523d452 100644 --- a/packages/ui/lib/components/TrackTable/index.tsx +++ b/packages/ui/lib/components/TrackTable/index.tsx @@ -52,6 +52,7 @@ function TrackTable({ displayPosition = true, displayThumbnail = true, displayFavorite = true, + displayBlacklist = true, displayArtist = true, displayAlbum = true, displayDuration = true, diff --git a/packages/ui/lib/components/TrackTable/types.ts b/packages/ui/lib/components/TrackTable/types.ts index b6a7647aad..ad305fe296 100644 --- a/packages/ui/lib/components/TrackTable/types.ts +++ b/packages/ui/lib/components/TrackTable/types.ts @@ -20,6 +20,7 @@ export type TrackTableExtraProps = { onPlayAll?: (tracks: T[]) => void; onAddToQueue?: (track: T) => void; onAddToFavorites?: (track: T) => void; + onAddToBlacklist?: (track: T) => void, onRemoveFromFavorites?: (track: T) => void; onAddToPlaylist?: (track: T, { name }: { name: string }) => void; onCreatePlaylist?: (track: T, { name }: { name: string }) => void; @@ -55,6 +56,7 @@ export type TrackTableSettings = { displayPosition?: boolean; displayThumbnail?: boolean; displayFavorite?: boolean; + displayBlacklist?: boolean; displayArtist?: boolean; displayAlbum?: boolean; displayDuration?: boolean; From aff5aa082051d91b64ffbe508e3de1d0fc8493a9 Mon Sep 17 00:00:00 2001 From: alzamer Date: Wed, 21 Feb 2024 21:12:58 +0100 Subject: [PATCH 4/7] Deleted unused imports --- packages/app/app/actions/blacklist.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/app/app/actions/blacklist.ts b/packages/app/app/actions/blacklist.ts index 6a6c6d8f87..7927bf7887 100644 --- a/packages/app/app/actions/blacklist.ts +++ b/packages/app/app/actions/blacklist.ts @@ -1,9 +1,8 @@ -import _, { flow, omit, unionWith } from 'lodash'; -import { store, Track } from '@nuclear/core'; +import _, { flow, omit } from 'lodash'; +import { store } from '@nuclear/core'; import { areTracksEqualByName, getTrackItem } from '@nuclear/ui'; import { safeAddUuid } from './helpers'; -import { createStandardAction } from 'typesafe-actions'; export const READ_BLACKLISTED = 'READ_BLACKLISTED'; export const BLACKLIST_TRACK = 'BLACKLIST_TRACK'; From 2a6d568a7cf3aefc2cbcbe00ac55c86bdc668a96 Mon Sep 17 00:00:00 2001 From: alzamer Date: Sun, 25 Feb 2024 15:30:08 +0100 Subject: [PATCH 5/7] Added Blacklist bookmark to settings --- packages/app/app/actions/blacklist.ts | 24 ++++- .../app/app/components/Settings/index.tsx | 95 +++++++++++++++++-- packages/app/app/reducers/blacklist.js | 2 +- packages/app/app/selectors/blacklist.ts | 3 + packages/core/src/settings/index.ts | 10 +- packages/i18n/src/locales/en.json | 4 +- .../components/TrackTable/Cells/TitleCell.tsx | 83 ++++++++-------- .../ui/lib/components/TrackTable/types.ts | 5 +- 8 files changed, 173 insertions(+), 53 deletions(-) create mode 100644 packages/app/app/selectors/blacklist.ts diff --git a/packages/app/app/actions/blacklist.ts b/packages/app/app/actions/blacklist.ts index 7927bf7887..64e80b99e6 100644 --- a/packages/app/app/actions/blacklist.ts +++ b/packages/app/app/actions/blacklist.ts @@ -1,4 +1,4 @@ -import _, { flow, omit } from 'lodash'; +import { flow, omit } from 'lodash'; import { store } from '@nuclear/core'; import { areTracksEqualByName, getTrackItem } from '@nuclear/ui'; @@ -8,7 +8,7 @@ export const READ_BLACKLISTED = 'READ_BLACKLISTED'; export const BLACKLIST_TRACK = 'BLACKLIST_TRACK'; export const REMOVE_BLACKLISTED_TRACK = 'REMOVE_BLACKLISTED_TRACK'; -export function addToBlacklist(track){ +export function addToBlacklist(track) { const clonedTrack = flow(safeAddUuid, getTrackItem)(track); let blacklist = store.get('blacklist'); @@ -22,3 +22,23 @@ export function addToBlacklist(track){ payload: blacklist }; } + +export function removeBlacklistedTrack(track) { + let blacklist = store.get('blacklist'); + blacklist = blacklist.filter(t => !areTracksEqualByName(t, track)); + + store.set('blacklist', blacklist); + + return { + type: REMOVE_BLACKLISTED_TRACK, + payload: blacklist + }; +} + +export function readBlacklist() { + const blacklist = store.get('blacklist'); + return { + type: READ_BLACKLISTED, + payload: blacklist + }; +} diff --git a/packages/app/app/components/Settings/index.tsx b/packages/app/app/components/Settings/index.tsx index 058bf363b4..90ec7e5473 100644 --- a/packages/app/app/components/Settings/index.tsx +++ b/packages/app/app/components/Settings/index.tsx @@ -1,20 +1,25 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { remote } from 'electron'; import { Button, Input, Radio, Segment, Icon } from 'semantic-ui-react'; import cx from 'classnames'; import _ from 'lodash'; import { useTranslation } from 'react-i18next'; import { SettingType } from '@nuclear/core'; -import { Dropdown, Range } from '@nuclear/ui'; +import { Dropdown, Range, TrackTable } from '@nuclear/ui'; import i18n from '@nuclear/i18n'; - import Header from '../Header'; import Spacer from '../Spacer'; - +import { connect } from 'react-redux'; import styles from './styles.scss'; import { LastFmSocialIntegration } from './Integrations/LastFmSocialIntegration'; import { MastodonSocialIntegration } from './Integrations/MastodonSocialIntegration'; import { RootState } from '../../reducers'; +import { playlistsSelectors } from '../../selectors/playlists'; +import { useSelector } from 'react-redux'; +import { blacklistSelector } from '../../selectors/blacklist'; +import * as BlacklistActions from '../../actions/blacklist'; +import { useDispatch } from 'react-redux'; +import { bindActionCreators } from 'redux'; const volumeSliderColors = { fillColor: { r: 248, g: 248, b: 242, a: 1 }, @@ -45,6 +50,7 @@ export type SettingsProps = { mastodon: RootState['mastodon']; settings: RootState['settings']; options: object; + blacklistActions: any; } const Settings: React.FC = ({ @@ -54,8 +60,16 @@ const Settings: React.FC = ({ importfavs, mastodon, settings, - options + options, + blacklistActions }) => { + const dispatch = useDispatch(); + const blacklisted = useSelector(blacklistSelector); + + useEffect(() => { + dispatch(BlacklistActions.readBlacklist()); + }, [dispatch]); + const isChecked = (option) => { return typeof settings[option.name] !== 'undefined' ? settings[option.name] @@ -136,6 +150,58 @@ const Settings: React.FC = ({ ); + const trackTableTranslation = useTranslation('track-table').t; + const trackTableStrings = { + addSelectedTracksToQueue: trackTableTranslation('add-selected-tracks-to-queue'), + addSelectedTracksToDownloads: trackTableTranslation('add-selected-tracks-to-downloads'), + addSelectedTracksToFavorites: trackTableTranslation('add-selected-tracks-to-favorites'), + playSelectedTracksNow: trackTableTranslation('play-selected-tracks-now'), + tracksSelectedLabelSingular: trackTableTranslation('tracks-selected-label-singular'), + tracksSelectedLabelPlural: trackTableTranslation('tracks-selected-label-plural') + }; + const playlists = useSelector(playlistsSelectors.localPlaylists); + const popupTranstation = useTranslation('track-popup').t; + const popupStrings = { + textAddToQueue: popupTranstation('add-to-queue'), + textPlayNow: popupTranstation('play-now'), + textPlayNext: popupTranstation('play-next'), + textAddToFavorites: popupTranstation('add-to-favorite'), + textAddToPlaylist: popupTranstation('add-to-playlist'), + textCreatePlaylist: popupTranstation('create-playlist'), + textAddToDownloads: popupTranstation('download'), + textAddToBlacklist: popupTranstation('blacklist'), + createPlaylistDialog: { + title: popupTranstation('create-playlist-dialog-title'), + placeholder: popupTranstation('create-playlist-dialog-placeholder'), + accept: popupTranstation('create-playlist-dialog-accept'), + cancel: popupTranstation('create-playlist-dialog-cancel') + } + }; + const renderTableOption = () => ( + } + thumbnailHeader={} + artistHeader={t('artist')} + titleHeader={t('title')} + albumHeader={t('album')} + durationHeader={t('duration')} + strings={trackTableStrings} + playlists={playlists.data} + popupActionStrings={popupStrings} + isTrackFavorite={null} + onDelete={blacklistActions} + displayPosition={false} + displayThumbnail={false} + displayAlbum={false} + displayDuration={false} + displayFavorite={false} + displayCustom={false} + selectable={false} + displayButtons={false} + /> + ); + const renderSliderOption = (option) => (
@@ -203,6 +269,8 @@ const Settings: React.FC = ({ renderNodeOption(option)} {option.type === SettingType.DIRECTORY && renderDirectoryOption(option)} + {option.type === SettingType.TABLE && + renderTableOption()}
); @@ -252,4 +320,19 @@ const Settings: React.FC = ({ ); }; -export default Settings; +function mapStateToProps(state) { + return { + blacklist: state.blacklist + }; +} + +function mapDispatchToProps(dispatch) { + return { + blacklistActions: bindActionCreators(BlacklistActions.removeBlacklistedTrack, dispatch) + }; +} + +export default connect( + mapStateToProps, + mapDispatchToProps +)(Settings); diff --git a/packages/app/app/reducers/blacklist.js b/packages/app/app/reducers/blacklist.js index 366e426e16..29338576cd 100644 --- a/packages/app/app/reducers/blacklist.js +++ b/packages/app/app/reducers/blacklist.js @@ -11,7 +11,7 @@ const BlacklistReducer = (state = initialState, action) => { case READ_BLACKLISTED: case BLACKLIST_TRACK: case REMOVE_BLACKLISTED_TRACK: - return { ...action.payload }; + return [...action.payload]; default: return state; } diff --git a/packages/app/app/selectors/blacklist.ts b/packages/app/app/selectors/blacklist.ts new file mode 100644 index 0000000000..578d1cd870 --- /dev/null +++ b/packages/app/app/selectors/blacklist.ts @@ -0,0 +1,3 @@ +import { RootState } from '../reducers'; + +export const blacklistSelector = (s: RootState) => s.blacklist; diff --git a/packages/core/src/settings/index.ts b/packages/core/src/settings/index.ts index 79fffdef48..c004fd6ecd 100644 --- a/packages/core/src/settings/index.ts +++ b/packages/core/src/settings/index.ts @@ -8,6 +8,7 @@ export enum SettingType { NUMBER = 'number', STRING = 'string', DIRECTORY = 'directory', + TABLE = 'table' } type SettingCategory = @@ -20,7 +21,8 @@ type SettingCategory = | 'downloads' | 'developer' | 'visualizer' - | 'social'; + | 'social' + | 'blacklist'; type SettingOption = { key: string; @@ -377,5 +379,11 @@ export const settingsConfig: Array = [ category: 'playback', type: SettingType.BOOLEAN, default: true + }, + { + name: 'blacklist', + prettyName: '', + category: 'blacklist', + type: SettingType.TABLE } ]; diff --git a/packages/i18n/src/locales/en.json b/packages/i18n/src/locales/en.json index 76cf31fdb0..083a8d3ca5 100644 --- a/packages/i18n/src/locales/en.json +++ b/packages/i18n/src/locales/en.json @@ -338,7 +338,9 @@ "use-stream-verification": "Use stream verification", "use-stream-verification-description": "Use stream verification. Loads the streams the community has verified as being correct for the tracks you play. Also allows you to vote on streams. See documentation for details.", "youtube": "Youtube", - "yt-api-key": "Youtube API Key" + "yt-api-key": "Youtube API Key", + "blacklist": "Blacklisted tracks", + "blacklist-description": "Remove tracks from blacklist" }, "tags": { "albums": "Top Albums", diff --git a/packages/ui/lib/components/TrackTable/Cells/TitleCell.tsx b/packages/ui/lib/components/TrackTable/Cells/TitleCell.tsx index ed98f2846f..8ee1198865 100644 --- a/packages/ui/lib/components/TrackTable/Cells/TitleCell.tsx +++ b/packages/ui/lib/components/TrackTable/Cells/TitleCell.tsx @@ -20,7 +20,8 @@ const TitleCell: React.FC & TrackTableExtraProps> = ({ onAddToDownloads, onAddToBlacklist, playlists, - popupActionStrings + popupActionStrings, + displayButtons = true }) => } data-testid='title-cell' @@ -30,54 +31,58 @@ const TitleCell: React.FC & TrackTableExtraProps> = ({ {value} - -