diff --git a/src/constants.js b/src/constants.js index 36ad4ee471e17..6904dfab6bb9f 100644 --- a/src/constants.js +++ b/src/constants.js @@ -55,6 +55,11 @@ const DBActions = { UPDATE_PLAYLIST: 'db-action-history-update-playlist', }, + PROFILES: { + ADD_CHANNEL: 'db-action-profiles-add-channel', + REMOVE_CHANNEL: 'db-action-profiles-remove-channel' + }, + PLAYLISTS: { UPSERT_VIDEO: 'db-action-playlists-upsert-video-by-playlist-name', UPSERT_VIDEOS: 'db-action-playlists-upsert-videos-by-playlist-name', @@ -77,6 +82,11 @@ const SyncEvents = { UPDATE_PLAYLIST: 'sync-history-update-playlist', }, + PROFILES: { + ADD_CHANNEL: 'sync-profiles-add-channel', + REMOVE_CHANNEL: 'sync-profiles-remove-channel' + }, + PLAYLISTS: { UPSERT_VIDEO: 'sync-playlists-upsert-video', DELETE_VIDEO: 'sync-playlists-delete-video', diff --git a/src/datastores/handlers/base.js b/src/datastores/handlers/base.js index b630327899ee1..4a7db5cbb8c3d 100644 --- a/src/datastores/handlers/base.js +++ b/src/datastores/handlers/base.js @@ -86,6 +86,36 @@ class Profiles { return db.profiles.updateAsync({ _id: profile._id }, profile, { upsert: true }) } + static addChannelToProfiles(channel, profileIds) { + if (profileIds.length === 1) { + return db.profiles.updateAsync( + { _id: profileIds[0] }, + { $push: { subscriptions: channel } } + ) + } else { + return db.profiles.updateAsync( + { _id: { $in: profileIds } }, + { $push: { subscriptions: channel } }, + { multi: true } + ) + } + } + + static removeChannelFromProfiles(channelId, profileIds) { + if (profileIds.length === 1) { + return db.profiles.updateAsync( + { _id: profileIds[0] }, + { $pull: { subscriptions: { id: channelId } } } + ) + } else { + return db.profiles.updateAsync( + { _id: { $in: profileIds } }, + { $pull: { subscriptions: { id: channelId } } }, + { multi: true } + ) + } + } + static delete(id) { return db.profiles.removeAsync({ _id: id }) } diff --git a/src/datastores/handlers/electron.js b/src/datastores/handlers/electron.js index 6f57a7d83ba10..cc0b473a3b990 100644 --- a/src/datastores/handlers/electron.js +++ b/src/datastores/handlers/electron.js @@ -89,6 +89,26 @@ class Profiles { ) } + static addChannelToProfiles(channel, profileIds) { + return ipcRenderer.invoke( + IpcChannels.DB_PROFILES, + { + action: DBActions.PROFILES.ADD_CHANNEL, + data: { channel, profileIds } + } + ) + } + + static removeChannelFromProfiles(channelId, profileIds) { + return ipcRenderer.invoke( + IpcChannels.DB_PROFILES, + { + action: DBActions.PROFILES.REMOVE_CHANNEL, + data: { channelId, profileIds } + } + ) + } + static delete(id) { return ipcRenderer.invoke( IpcChannels.DB_PROFILES, diff --git a/src/datastores/handlers/web.js b/src/datastores/handlers/web.js index d6073dc7039f3..93ffa3d68c8ff 100644 --- a/src/datastores/handlers/web.js +++ b/src/datastores/handlers/web.js @@ -59,6 +59,14 @@ class Profiles { return baseHandlers.profiles.upsert(profile) } + static addChannelToProfiles(channel, profileIds) { + return baseHandlers.profiles.addChannelToProfiles(channel, profileIds) + } + + static removeChannelFromProfiles(channelId, profileIds) { + return baseHandlers.profiles.removeChannelFromProfiles(channelId, profileIds) + } + static delete(id) { return baseHandlers.profiles.delete(id) } diff --git a/src/main/index.js b/src/main/index.js index 3b88eaab24429..e6af7ccc21859 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -1124,6 +1124,24 @@ function runApp() { ) return null + case DBActions.PROFILES.ADD_CHANNEL: + await baseHandlers.profiles.addChannelToProfiles(data.channel, data.profileIds) + syncOtherWindows( + IpcChannels.SYNC_PROFILES, + event, + { event: SyncEvents.PROFILES.ADD_CHANNEL, data } + ) + return null + + case DBActions.PROFILES.REMOVE_CHANNEL: + await baseHandlers.profiles.removeChannelFromProfiles(data.channelId, data.profileIds) + syncOtherWindows( + IpcChannels.SYNC_PROFILES, + event, + { event: SyncEvents.PROFILES.REMOVE_CHANNEL, data } + ) + return null + case DBActions.GENERAL.DELETE: await baseHandlers.profiles.delete(data) syncOtherWindows( diff --git a/src/renderer/components/ft-subscribe-button/ft-subscribe-button.js b/src/renderer/components/ft-subscribe-button/ft-subscribe-button.js index 9a85032176cc0..dabc61e811ee8 100644 --- a/src/renderer/components/ft-subscribe-button/ft-subscribe-button.js +++ b/src/renderer/components/ft-subscribe-button/ft-subscribe-button.js @@ -6,7 +6,7 @@ import FtButton from '../../components/ft-button/ft-button.vue' import FtPrompt from '../../components/ft-prompt/ft-prompt.vue' import { MAIN_PROFILE_ID } from '../../../constants' -import { deepCopy, showToast } from '../../helpers/utils' +import { showToast } from '../../helpers/utils' import { getFirstCharacter } from '../../helpers/strings' export default defineComponent({ @@ -118,31 +118,27 @@ export default defineComponent({ this.handleUnsubscription(profile) } } else { - const currentProfile = deepCopy(profile) - const subscription = { - id: this.channelId, - name: this.channelName, - thumbnail: this.channelThumbnail - } - currentProfile.subscriptions.push(subscription) - - this.updateProfile(currentProfile) - showToast(this.$t('Channel.Added channel to your subscriptions')) + const profileIds = [profile._id] if (profile._id !== MAIN_PROFILE_ID) { - const primaryProfile = deepCopy(this.profileList.find(prof => { + const primaryProfile = this.profileList.find(prof => { return prof._id === MAIN_PROFILE_ID - })) - - const index = primaryProfile.subscriptions.findIndex((channel) => { - return channel.id === this.channelId }) - if (index === -1) { - primaryProfile.subscriptions.push(subscription) - this.updateProfile(primaryProfile) + if (!this.isProfileSubscribed(primaryProfile)) { + profileIds.push(MAIN_PROFILE_ID) } } + + const channel = { + id: this.channelId, + name: this.channelName, + thumbnail: this.channelThumbnail + } + + this.addChannelToProfiles({ channel, profileIds }) + + showToast(this.$t('Channel.Added channel to your subscriptions')) } if (this.isProfileDropdownEnabled && this.openDropdownOnSubscribe && !this.isProfileDropdownOpen) { @@ -169,30 +165,34 @@ export default defineComponent({ }, handleUnsubscription: function (profile) { - const currentProfile = deepCopy(profile) - currentProfile.subscriptions = currentProfile.subscriptions.filter((channel) => { - return channel.id !== this.channelId - }) - - this.updateProfile(currentProfile) - showToast(this.$t('Channel.Channel has been removed from your subscriptions')) + const profileIds = [profile._id] if (profile._id === MAIN_PROFILE_ID) { // Check if a subscription exists in a different profile. // Remove from there as well. - let duplicateSubscriptions = 0 this.profileList.forEach((profileInList) => { if (profileInList._id === MAIN_PROFILE_ID) { return } - duplicateSubscriptions += this.unsubscribe(profileInList, this.channelId) + + if (this.isProfileSubscribed(profileInList)) { + profileIds.push(profileInList._id) + } }) + } - if (duplicateSubscriptions > 0) { - const message = this.$t('Channel.Removed subscription from {count} other channel(s)', { count: duplicateSubscriptions }) - showToast(message) - } + this.removeChannelFromProfiles({ + channelId: this.channelId, + profileIds + }) + + showToast(this.$t('Channel.Channel has been removed from your subscriptions')) + + if (profile._id === MAIN_PROFILE_ID && profileIds.length > 1) { + showToast(this.$t('Channel.Removed subscription from {count} other channel(s)', { + count: profileIds.length - 1 + })) } }, @@ -207,30 +207,14 @@ export default defineComponent({ }, isProfileSubscribed: function (profile) { - return this.subscriptionInfoForProfile(profile) !== null - }, - - unsubscribe: function(profile, channelId) { - const parsedProfile = deepCopy(profile) - const index = parsedProfile.subscriptions.findIndex((channel) => { - return channel.id === channelId + return profile.subscriptions.some((channel) => { + return channel.id === this.channelId }) - - if (index !== -1) { - // use filter instead of splice in case the subscription appears multiple times - // https://github.com/FreeTubeApp/FreeTube/pull/3468#discussion_r1179290877 - parsedProfile.subscriptions = parsedProfile.subscriptions.filter((x) => { - return x.id !== channelId - }) - - this.updateProfile(parsedProfile) - return 1 - } - return 0 }, ...mapActions([ - 'updateProfile' + 'addChannelToProfiles', + 'removeChannelFromProfiles' ]) } }) diff --git a/src/renderer/store/modules/profiles.js b/src/renderer/store/modules/profiles.js index 188ad27d6086f..7345c1fa04d4f 100644 --- a/src/renderer/store/modules/profiles.js +++ b/src/renderer/store/modules/profiles.js @@ -172,6 +172,24 @@ const actions = { } }, + async addChannelToProfiles({ commit }, { channel, profileIds }) { + try { + await DBProfileHandlers.addChannelToProfiles(channel, profileIds) + commit('addChannelToProfiles', { channel, profileIds }) + } catch (errMessage) { + console.error(errMessage) + } + }, + + async removeChannelFromProfiles({ commit }, { channelId, profileIds }) { + try { + await DBProfileHandlers.removeChannelFromProfiles(channelId, profileIds) + commit('removeChannelFromProfiles', { channelId, profileIds }) + } catch (errMessage) { + console.error(errMessage) + } + }, + async removeProfile({ commit }, profileId) { try { await DBProfileHandlers.delete(profileId) @@ -214,6 +232,22 @@ const mutations = { state.profileList.sort(profileSort) }, + addChannelToProfiles(state, { channel, profileIds }) { + for (const id of profileIds) { + state.profileList.find(profile => profile._id === id).subscriptions.push(channel) + } + }, + + removeChannelFromProfiles(state, { channelId, profileIds }) { + for (const id of profileIds) { + const profile = state.profileList.find(profile => profile._id === id) + + // use filter instead of splice in case the subscription appears multiple times + // https://github.com/FreeTubeApp/FreeTube/pull/3468#discussion_r1179290877 + profile.subscriptions = profile.subscriptions.filter(channel => channel.id !== channelId) + } + }, + removeProfileFromList(state, profileId) { const i = state.profileList.findIndex((profile) => { return profile._id === profileId diff --git a/src/renderer/store/modules/settings.js b/src/renderer/store/modules/settings.js index 0e81afa7d950f..e080dd225e67e 100644 --- a/src/renderer/store/modules/settings.js +++ b/src/renderer/store/modules/settings.js @@ -530,6 +530,14 @@ const customActions = { commit('upsertProfileToList', data) break + case SyncEvents.PROFILES.ADD_CHANNEL: + commit('addChannelToProfiles', data) + break + + case SyncEvents.PROFILES.REMOVE_CHANNEL: + commit('removeChannelFromProfiles', data) + break + case SyncEvents.GENERAL.DELETE: commit('removeProfileFromList', data) break