diff --git a/src/images/defaultBanner.png b/src/images/defaultBanner.png new file mode 100644 index 000000000..6e129c165 Binary files /dev/null and b/src/images/defaultBanner.png differ diff --git a/src/js/channels.js b/src/js/channels.js index f7f13fa9f..368d687c5 100644 --- a/src/js/channels.js +++ b/src/js/channels.js @@ -85,6 +85,10 @@ function goToChannel(channelId) { data.latestVideos.forEach((video) => { displayVideo(video, 'channel'); }); + + if (typeof(channelView.banner) === 'undefined') { + window.setTimeout(() => {$('.channelViewBanner').get(0).height = 200;}, 50); + } }, (errorData) => { showToast(errorData.responseJSON.error); loadingView.seen = false; diff --git a/src/js/init.js b/src/js/init.js index d714203ac..1031ea2b7 100644 --- a/src/js/init.js +++ b/src/js/init.js @@ -68,8 +68,6 @@ let init = function () { //let winHeight = 800; win = new BrowserWindow({ - width: 1200, - height: 800, autoHideMenuBar: true, webPreferences: { nodeIntegration: true, @@ -77,25 +75,7 @@ let init = function () { icon: path.join(__dirname, '..', 'icons', 'iconColor.png') }); - settingsDb.findOne({ - _id: 'bounds' - }, function (err, doc) { - if (typeof doc !== "object" || typeof doc.value !== "object") { - return; - } - - const {maximized, ...bounds} = doc.value; - const allDisplaysSummaryWidth = screen - .getAllDisplays() - .reduce((accumulator, {size: {width}}) => accumulator + width, 0); - - if (allDisplaysSummaryWidth >= bounds.x) { - win.setBounds(bounds); - } - if (maximized) { - win.maximize(); - } - }); + win.setBounds({width: 1200, height: 800}); settingsDb.findOne({ _id: 'useTor' @@ -132,7 +112,7 @@ let init = function () { }); if (process.env = 'development') { - //win.webContents.openDevTools(); + win.webContents.openDevTools(); } win.on('closed', () => { @@ -225,6 +205,30 @@ let init = function () { const menu = Menu.buildFromTemplate(template); Menu.setApplicationMenu(menu); + settingsDb.findOne({ + _id: 'bounds' + }, function (err, doc) { + if (doc === null) { + return; + } + + if (typeof doc !== "object" || typeof doc.value !== "object") { + return; + } + + const {maximized, ...bounds} = doc.value; + const allDisplaysSummaryWidth = screen + .getAllDisplays() + .reduce((accumulator, {size: {width}}) => accumulator + width, 0); + + if (allDisplaysSummaryWidth >= bounds.x) { + win.setBounds({"x":bounds.x,"y":bounds.y,"width":bounds.width,"height":bounds.height}); + } + if (maximized) { + win.maximize(); + } + }); + /** * Sets proxy when setProxy event is sent from renderer * diff --git a/src/js/settings.js b/src/js/settings.js index 228549bab..3ecdfe032 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -180,11 +180,13 @@ function checkDefaultSettings() { 'distractionFreeMode': false, 'hideWatchedSubs': false, 'videoView': 'grid', - 'profileList': [{ - name: 'Default', + 'profileList': [ + { + name: 'All Channels', color: randomColor - }, ], - 'defaultProfile': 'Default', + }, + ], + 'defaultProfile': 'All Channels', }; ft.log(settingDefaults); @@ -221,7 +223,7 @@ function checkDefaultSettings() { }, { $set: { profile: [{ - value: 'Default' + value: 'All Channels' }] } }, {}, (err, newDoc) => { @@ -856,7 +858,7 @@ function importSubscriptions() { let colorPaletteKeys = Object.keys(colorPalette); let randomColor = colorPalette[colorPaletteKeys[colorPaletteKeys.length * Math.random() << 0]]; editProfileView.isNewProfile = true; - editProfileView.newProfileColor = randomColor; + editProfileView.newProfileColorText = randomColor; editProfileView.newProfileName = profile.value; editProfileView.updateProfile(false); } diff --git a/src/js/subscriptions.js b/src/js/subscriptions.js index a91acb0dd..0d675d1d4 100644 --- a/src/js/subscriptions.js +++ b/src/js/subscriptions.js @@ -84,23 +84,25 @@ function addSubscription(data, useToast = true, profile = '') { * * @return {Void} */ -function removeSubscription(channelId) { +function removeSubscription(channelId, profile = profileSelectView.activeProfile.name, displayToast = true) { subDb.find({ channelId: channelId }, (err, docs) => { - if (docs[0].profile.length > 1) { + if (docs[0].profile.length > 1 && profile !== 'All Profiles') { subDb.update({ channelId: channelId, }, { $pull: { profile: { - value: profileSelectView.activeProfile.name + value: profile } } - }, (err, numAdded) => { + }, { multi: true },(err, numRemoved) => { // Refresh the list of subscriptions on the side navigation bar. displaySubs(); - showToast('Removed channel from subscriptions.'); + if (displayToast) { + showToast('Removed channel from subscriptions.'); + } }); } else { subDb.remove({ @@ -108,7 +110,9 @@ function removeSubscription(channelId) { }, {}, (err, numRemoved) => { // Refresh the list of subscriptions on the side navigation bar. displaySubs(); - showToast('Removed channel from subscriptions.'); + if (displayToast) { + showToast('Removed channel from subscriptions.'); + } }); } }); @@ -198,9 +202,11 @@ function addSubsToView(videoList) { }); } - videoList = videoList.filter(a => { + if (profileSelectView.activeProfile.name !== 'All Channels') { + videoList = videoList.filter(a => { return a.profile.map(x => x.value).indexOf(profileSelectView.activeProfile.name) !== -1 - }); + }); + } videoList.sort((a, b) => { return b.published - a.published; @@ -278,16 +284,20 @@ function displaySubs() { subList.innerHTML = ''; // Sort alphabetically - subDb.find({ - profile: { - $elemMatch: { - value: profileSelectView.activeProfile.name - } - } - }).sort({ + subDb.find().sort({ channelName: 1 }).exec((err, subs) => { - subs.forEach((channel) => { + let subFilter; + if (profileSelectView.activeProfile.name === 'All Channels' || typeof(profileSelectView.activeProfile.name) === 'undefined') { + subFilter = subs; + } + else { + subFilter = subs.filter(a => { + return a.profile.find((name) => {return name.value === profileSelectView.activeProfile.name }); + }); + } + + subFilter.forEach((channel) => { // Grab subscriptions.html to be used as a template. const subsTemplate = require('./templates/subscriptions.html') mustache.parse(subsTemplate); diff --git a/src/js/templates.js b/src/js/templates.js index 5c25ff29c..21bf3b4d2 100644 --- a/src/js/templates.js +++ b/src/js/templates.js @@ -923,15 +923,32 @@ let subscriptionManagerView = new Vue({ if (isNewProfile) { editProfileView.profileName = ''; editProfileView.profileColor = ''; - editProfileView.newProfileName = ''; - editProfileView.newProfileColor = ''; + editProfileView.newProfileName = 'Profile ' + (this.profileList.length + 1); + let colorPaletteKeys = Object.keys(editProfileView.colorPalette); + let randomColor = colorPalette[colorPaletteKeys[colorPaletteKeys.length * Math.random() << 0]]; + editProfileView.newProfileColorText = randomColor; editProfileView.subscriptionList = []; } else { editProfileView.profileName = this.profileList[index].name; editProfileView.profileColor = this.profileList[index].color; editProfileView.newProfileName = this.profileList[index].name; - editProfileView.newProfileColor = this.profileList[index].color; - // Sort alphabetically + editProfileView.newProfileColorText = this.profileList[index].color; + if (this.profileList[index].name === 'All Channels') { + // Sort alphabetically + subDb.find({ + }).sort({ + channelName: 1 + }).exec((err, subs) => { + let list = []; + subs.forEach((sub) => { + sub.checked = false; + list.push(sub); + }); + editProfileView.subscriptionList = list; + }); + } + else { + // Sort alphabetically subDb.find({ profile: { $elemMatch: { @@ -948,8 +965,10 @@ let subscriptionManagerView = new Vue({ }); editProfileView.subscriptionList = list; }); + } } editProfileView.seen = true; + loadingView.seen = false; //backButtonView.lastView = subscriptionManagerView; } }, @@ -976,7 +995,7 @@ let editProfileView = new Vue({ profileName: '', profileColor: '', newProfileName: '', - newProfileColor: '', + newProfileColorText: '', selectedProfile: '', colorPalette: { red: '#d50000', @@ -999,7 +1018,7 @@ let editProfileView = new Vue({ }, methods: { changeProfileColor: function (value) { - this.newProfileColor = value; + this.newProfileColorText = value; }, selectAll: function () { this.subscriptionList.forEach(channel => { @@ -1012,6 +1031,11 @@ let editProfileView = new Vue({ }); }, defaultProfile: function () { + if (editProfileView.profileName === settingsView.defaultProfile) { + showToast('This profile is already set as your default.'); + return; + } + settingsDb.update({ _id: 'defaultProfile' }, { @@ -1087,6 +1111,11 @@ let editProfileView = new Vue({ }); }, updateProfile: function (updateView = true) { + if (this.newProfileName === '') { + showToast('Profile name cannot be blank.'); + return; + } + let patt = new RegExp("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"); if (patt.test(this.newProfileColor)) { if (this.isNewProfile) { @@ -1121,7 +1150,7 @@ let editProfileView = new Vue({ if (updateView) { hideViews(); subscriptionManagerView.seen = true; - showToast('The' + newProfile.name + ' profile has been added!'); + showToast('The ' + newProfile.name + ' profile has been added!'); } }); } @@ -1244,7 +1273,11 @@ let editProfileView = new Vue({ showToast('Select a profile other than the one being edited.'); return; } - let confirmString = 'Would you like to move the selected channels to the ' + this.selectedProfile + ' profile?'; + if (this.selectedProfile === 'All Channels') { + showToast('There is no need to move channels to "All Channels".'); + return; + } + let confirmString = 'Would you like to move the selected channel(s) to the ' + this.selectedProfile + ' profile?'; confirmFunction(confirmString, () => { let amountRemoved = 0; this.subscriptionList.forEach(channel => { @@ -1318,7 +1351,11 @@ let editProfileView = new Vue({ showToast('Select a profile other than the one being edited.'); return; } - let confirmString = 'Would you like to copy the selected channels to the ' + this.selectedProfile + ' profile?'; + if (this.selectedProfile === 'All Channels') { + showToast('There is no need to copy channels to "All Channels".'); + return; + } + let confirmString = 'Would you like to copy the selected channel(s) to the ' + this.selectedProfile + ' profile?'; confirmFunction(confirmString, () => { let amountCopied = 0; this.subscriptionList.forEach(channel => { @@ -1369,52 +1406,55 @@ let editProfileView = new Vue({ }); }, deleteChannel: function () { - let confirmString = 'Are you sure you want to delete the selected channels from this profile?'; + let confirmString = 'Are you sure you want to delete the selected channel(s) from this profile?'; let amountDeleted = 0; + if (this.amountSelected === 0) { + showToast('A channel must be selected before it can be deleted.'); + return; + } + confirmFunction(confirmString, () => { this.subscriptionList.forEach((channel, index) => { + console.log(channel); if (channel.checked) { - subDb.update({ - channelId: channel.channelId, - }, { - $pull: { - profile: { - value: editProfileView.profileName - } - } - }, { - multi: true - }, (err, numRemoved) => { - if (err) { - console.log(err); - } + removeSubscription(channel.channelId, editProfileView.profileName, false); - let subMap = subscriptionView.fullVideoList.map(x => x.author === channel.channelName); - for (let i = 0; i < subMap.length; i++) { - if (subMap[i]) { + let subViewListMap = subscriptionView.fullVideoList.map(x => x.author === channel.channelName); + + for (let i = 0; i < subViewListMap.length; i++) { + if (subViewListMap[i]) { let subProfileIndex = subscriptionView.fullVideoList[i].profile.findIndex(x => x.value === editProfileView.profileName); subscriptionView.fullVideoList[i].profile.splice(subProfileIndex, 1); } } - editProfileView.subscriptionList.splice(index, 1); - }); - - amountDeleted++; + amountDeleted++; } + }); window.setTimeout(() => { // Refresh the list of subscriptions on the side navigation bar and subscriptions view. displaySubs(); addSubsToView(subscriptionView.fullVideoList); showToast(amountDeleted + ' channel(s) have been deleted from this profile.'); + this.subscriptionList = this.subscriptionList.filter(a => { + return !a.checked; + }); }, 500); }); }, }, computed: { + newProfileColor: function () { + if (this.newProfileColorText[0] === '#') { + return this.newProfileColorText; + } + else { + return '#' + this.newProfileColorText; + } + }, isDefaultProfile: function () { return settingsView.defaultProfile === this.profileName; }, diff --git a/src/style/channel.css b/src/style/channel.css index caf2d7986..fd48b80ba 100644 --- a/src/style/channel.css +++ b/src/style/channel.css @@ -15,10 +15,17 @@ along with FreeTube. If not, see . */ +.channelDefaultBanner { + width: 100%; + height: 200px; +} + .channelViewBanner { width: 100%; max-height: 200px; margin-bottom: 30px; + background-color: black; + background-image: url('../images/defaultBanner.png'); } .channelViewImage { diff --git a/src/style/main.css b/src/style/main.css index aeaaf2a37..a1b7361f0 100644 --- a/src/style/main.css +++ b/src/style/main.css @@ -322,13 +322,13 @@ a { .searchBar { position: absolute; - right: -75px; + left: 40%; top: 0; - width: 750px; + width: 650px; } .searchBar input { - width: 75%; + width: 94%; color: black; } @@ -558,21 +558,25 @@ a { #confirmFunction { position: fixed; + margin-left: 250px; + margin-right: auto; + left: 4%; + right: 4%; top: 50%; - left: 30%; - width: 800px; - height: 65px; - font-weight: bold; - line-height: 65px; - visibility: hidden; + height: 45px; + line-height: 45px; + padding: 10px; z-index: 1; - -webkit-box-shadow: 5px 5px 15px -5px rgba(0, 0, 0, 0.75); - -moz-box-shadow: 5px 5px 15px -5px rgba(0, 0, 0, 0.75); - box-shadow: 5px 5px 15px -5px rgba(0, 0, 0, 0.75); + visibility: hidden; + -webkit-box-shadow: 4px -2px 51px -6px rgba(0, 0, 0, 0.75); + -webkit-transition: opacity 0.4s ease-in-out; + -moz-transition: opacity 0.4s ease-in-out; + -ms-transition: opacity 0.4s ease-in-out; + -o-transition: opacity 0.4s ease-in-out; } #confirmMessage { - margin-left: 15px; + font-weight: bold; } .confirmButton { @@ -583,11 +587,15 @@ a { #confirmYes { right: 90px; + line-height: 65px; + font-weight: bold; color: #2196f3; } #confirmNo { right: 20px; + line-height: 65px; + font-weight: bold; } #getNextPage { diff --git a/src/templates/editProfileView.html b/src/templates/editProfileView.html index 758773e50..106c42873 100644 --- a/src/templates/editProfileView.html +++ b/src/templates/editProfileView.html @@ -1,5 +1,10 @@
+
+

Subscription List for {{profileName}} Profile

+

This profile is empty. Add subscriptions to this profile to manage them.

+
+

Subscription List for {{profileName}} Profile

{{amountSelected}} Selected


@@ -10,6 +15,24 @@
{{channel.channelName}}



+
+
+ SELECT ALL +
+
+ SELECT NONE +
+
+ MOVE SELECTED TO +
+
+ COPY SELECTED TO +
+
+ DELETE SELECTED +
+
+
+ +

Color Picker

@@ -48,10 +57,11 @@

- +

-

New Profile Color

+

New Profile Color

+

Selected Profile Color

@@ -66,7 +76,7 @@
MAKE DEFAULT PROFILE
-
+
DELETE PROFILE
diff --git a/src/templates/subscriptionManagerView.html b/src/templates/subscriptionManagerView.html index e95c40b07..4e8025cd9 100644 --- a/src/templates/subscriptionManagerView.html +++ b/src/templates/subscriptionManagerView.html @@ -10,7 +10,7 @@
- +
Add New Profile