Add subscription manager within profile settings. Add Upcoming video information. Other changes
This commit is contained in:
parent
20b379c269
commit
2a0c062915
20
appveyor.yml
20
appveyor.yml
|
@ -1,20 +0,0 @@
|
|||
image: Visual Studio 2017
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
cache:
|
||||
- node_modules
|
||||
- '%USERPROFILE%\.electron'
|
||||
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
install:
|
||||
- ps: Install-Product node 12 x64
|
||||
- npm install
|
||||
|
||||
build_script:
|
||||
- npm run build
|
||||
|
||||
test: off
|
|
@ -1,4 +1,5 @@
|
|||
.bubblePadding {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 115px;
|
||||
padding: 10px;
|
||||
|
@ -25,6 +26,20 @@
|
|||
-webkit-border-radius: 200px 200px 200px 200px;
|
||||
}
|
||||
|
||||
.selected {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: #EEEEEE;
|
||||
font-size: 25px;
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: 12px;
|
||||
}
|
||||
|
||||
.channelName {
|
||||
font-size: 13px;
|
||||
height: 60px;
|
||||
|
|
|
@ -7,18 +7,26 @@ export default Vue.extend({
|
|||
type: String,
|
||||
required: true
|
||||
},
|
||||
channelId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
channelThumbnail: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
showSelected: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
selected: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goToChannel: function () {
|
||||
console.log('Go to channel')
|
||||
handleClick: function () {
|
||||
if (this.showSelected) {
|
||||
this.selected = !this.selected
|
||||
}
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
<template>
|
||||
<div
|
||||
class="bubblePadding"
|
||||
@click="goToChannel(channelId)"
|
||||
@click="handleClick"
|
||||
>
|
||||
<img
|
||||
class="bubble"
|
||||
:src="channelThumbnail"
|
||||
>
|
||||
<div
|
||||
v-if="selected"
|
||||
class="bubble selected"
|
||||
>
|
||||
<font-awesome-icon
|
||||
icon="check"
|
||||
class="icon"
|
||||
/>
|
||||
</div>
|
||||
<div class="channelName">
|
||||
{{ channelName }}
|
||||
</div>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
}
|
||||
|
||||
.forceTextColor .ft-input {
|
||||
color: var(--text-with-main-color);
|
||||
color: #EEEEEE;
|
||||
background-color: var(--primary-input-color);
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
|||
}
|
||||
|
||||
.forceTextColor ::-webkit-input-placeholder {
|
||||
color: var(--text-with-main-color);
|
||||
color: #EEEEEE;
|
||||
}
|
||||
|
||||
.inputAction {
|
||||
|
@ -58,7 +58,7 @@
|
|||
}
|
||||
|
||||
.forceTextColor .inputAction {
|
||||
color: var(--text-with-main-color);
|
||||
color: #EEEEEE;
|
||||
}
|
||||
|
||||
.inputAction:hover {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
.card {
|
||||
width: 85%;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 30px;
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
import Vue from 'vue'
|
||||
import { mapActions } from 'vuex'
|
||||
|
||||
import FtCard from '../../components/ft-card/ft-card.vue'
|
||||
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
|
||||
import FtChannelBubble from '../../components/ft-channel-bubble/ft-channel-bubble.vue'
|
||||
import FtButton from '../../components/ft-button/ft-button.vue'
|
||||
import FtPrompt from '../../components/ft-prompt/ft-prompt.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'FtProfileAllChannelsList',
|
||||
components: {
|
||||
'ft-card': FtCard,
|
||||
'ft-flex-box': FtFlexBox,
|
||||
'ft-channel-bubble': FtChannelBubble,
|
||||
'ft-button': FtButton,
|
||||
'ft-prompt': FtPrompt
|
||||
},
|
||||
props: {
|
||||
profile: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
channels: [],
|
||||
selectedLength: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
profileList: function () {
|
||||
return this.$store.getters.getProfileList
|
||||
},
|
||||
selectedText: function () {
|
||||
const localeText = this.$t('Profile.$ selected')
|
||||
return localeText.replace('$', this.selectedLength)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
profile: function () {
|
||||
this.channels = [].concat(this.profileList[0].subscriptions).sort((a, b) => {
|
||||
const nameA = a.name.toLowerCase()
|
||||
const nameB = b.name.toLowerCase()
|
||||
if (nameA < nameB) {
|
||||
return -1
|
||||
}
|
||||
if (nameA > nameB) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}).filter((channel) => {
|
||||
const index = this.profile.subscriptions.findIndex((sub) => {
|
||||
return sub.id === channel.id
|
||||
})
|
||||
|
||||
return index === -1
|
||||
}).map((channel) => {
|
||||
channel.selected = false
|
||||
return channel
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
if (typeof this.profile.subscriptions !== 'undefined') {
|
||||
this.channels = [].concat(this.profileList[0].subscriptions).sort((a, b) => {
|
||||
const nameA = a.name.toLowerCase()
|
||||
const nameB = b.name.toLowerCase()
|
||||
if (nameA < nameB) {
|
||||
return -1
|
||||
}
|
||||
if (nameA > nameB) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}).filter((channel) => {
|
||||
const index = this.profile.subscriptions.findIndex((sub) => {
|
||||
return sub.id === channel.id
|
||||
})
|
||||
|
||||
return index === -1
|
||||
}).map((channel) => {
|
||||
channel.selected = false
|
||||
return channel
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleChannelClick: function (index) {
|
||||
this.channels[index].selected = !this.channels[index].selected
|
||||
this.selectedLength = this.channels.filter((channel) => {
|
||||
return channel.selected
|
||||
}).length
|
||||
},
|
||||
|
||||
addChannelToProfile: function () {
|
||||
if (this.selectedLength === 0) {
|
||||
this.showToast({
|
||||
message: this.$t('Profile.No channel(s) have been selected')
|
||||
})
|
||||
} else {
|
||||
const subscriptions = this.channels.filter((channel) => {
|
||||
return channel.selected
|
||||
})
|
||||
|
||||
const profile = JSON.parse(JSON.stringify(this.profile))
|
||||
profile.subscriptions = profile.subscriptions.concat(subscriptions)
|
||||
this.updateProfile(profile)
|
||||
this.showToast({
|
||||
message: this.$t('Profile.Profile has been updated')
|
||||
})
|
||||
this.selectNone()
|
||||
}
|
||||
},
|
||||
|
||||
selectAll: function () {
|
||||
Object.keys(this.$refs).forEach((ref) => {
|
||||
if (typeof this.$refs[ref][0] !== 'undefined') {
|
||||
this.$refs[ref][0].selected = true
|
||||
}
|
||||
})
|
||||
|
||||
this.channels = this.channels.map((channel) => {
|
||||
channel.selected = true
|
||||
return channel
|
||||
})
|
||||
|
||||
this.selectedLength = this.channels.filter((channel) => {
|
||||
return channel.selected
|
||||
}).length
|
||||
},
|
||||
|
||||
selectNone: function () {
|
||||
Object.keys(this.$refs).forEach((ref) => {
|
||||
if (typeof this.$refs[ref][0] !== 'undefined') {
|
||||
this.$refs[ref][0].selected = false
|
||||
}
|
||||
})
|
||||
|
||||
this.channels = this.channels.map((channel) => {
|
||||
channel.selected = false
|
||||
return channel
|
||||
})
|
||||
|
||||
this.selectedLength = this.channels.filter((channel) => {
|
||||
return channel.selected
|
||||
}).length
|
||||
},
|
||||
|
||||
...mapActions([
|
||||
'showToast',
|
||||
'updateProfile'
|
||||
])
|
||||
}
|
||||
})
|
|
@ -0,0 +1,42 @@
|
|||
<template>
|
||||
<div>
|
||||
<ft-card class="card">
|
||||
<h2>
|
||||
{{ $t("Profile.Other Channels") }}
|
||||
</h2>
|
||||
<p>
|
||||
{{ selectedText }}
|
||||
</p>
|
||||
<ft-flex-box>
|
||||
<ft-channel-bubble
|
||||
v-for="(channel, index) in channels"
|
||||
:key="index"
|
||||
:ref="`all-channels-${index}`"
|
||||
:channel-name="channel.name"
|
||||
:channel-thumbnail="channel.thumbnail"
|
||||
:show-selected="true"
|
||||
@click="handleChannelClick(index)"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
<ft-flex-box>
|
||||
<ft-button
|
||||
:label="$t('Profile.Select All')"
|
||||
@click="selectAll"
|
||||
/>
|
||||
<ft-button
|
||||
:label="$t('Profile.Select None')"
|
||||
@click="selectNone"
|
||||
/>
|
||||
<ft-button
|
||||
:label="$t('Profile.Add Selected To Profile')"
|
||||
text-color="var(--text-with-main-color)"
|
||||
background-color="var(--primary-color)"
|
||||
@click="addChannelToProfile"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
</ft-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./ft-profile-all-channels-list.js" />
|
||||
<style scoped src="./ft-profile-all-channels-list.css" />
|
|
@ -0,0 +1,5 @@
|
|||
.card {
|
||||
width: 85%;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 15px;
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
import Vue from 'vue'
|
||||
import { mapActions } from 'vuex'
|
||||
|
||||
import FtCard from '../../components/ft-card/ft-card.vue'
|
||||
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
|
||||
import FtChannelBubble from '../../components/ft-channel-bubble/ft-channel-bubble.vue'
|
||||
import FtButton from '../../components/ft-button/ft-button.vue'
|
||||
import FtPrompt from '../../components/ft-prompt/ft-prompt.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'FtProfileChannelList',
|
||||
components: {
|
||||
'ft-card': FtCard,
|
||||
'ft-flex-box': FtFlexBox,
|
||||
'ft-channel-bubble': FtChannelBubble,
|
||||
'ft-button': FtButton,
|
||||
'ft-prompt': FtPrompt
|
||||
},
|
||||
props: {
|
||||
profile: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isMainProfile: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
showDeletePrompt: false,
|
||||
subscriptions: [],
|
||||
selectedLength: 0,
|
||||
componentKey: 0,
|
||||
deletePromptValues: [
|
||||
'yes',
|
||||
'no'
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
profileList: function () {
|
||||
return this.$store.getters.getProfileList
|
||||
},
|
||||
selectedText: function () {
|
||||
const localeText = this.$t('Profile.$ selected')
|
||||
return localeText.replace('$', this.selectedLength)
|
||||
},
|
||||
deletePromptMessage: function () {
|
||||
if (this.isMainProfile) {
|
||||
return this.$t('Profile["This is your primary profile. Are you sure you want to delete the selected channels? The same channels will be deleted in any profile they are found in."]')
|
||||
} else {
|
||||
return this.$t('Profile["Are you sure you want to delete the selected channels? This will not delete the channel from any other profile."]')
|
||||
}
|
||||
},
|
||||
deletePromptNames: function () {
|
||||
return [
|
||||
this.$t('Yes'),
|
||||
this.$t('No')
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
profile: function () {
|
||||
this.subscriptions = [].concat(this.profile.subscriptions.sort((a, b) => {
|
||||
const nameA = a.name.toLowerCase()
|
||||
const nameB = b.name.toLowerCase()
|
||||
if (nameA < nameB) {
|
||||
return -1
|
||||
}
|
||||
if (nameA > nameB) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}).map((channel) => {
|
||||
channel.selected = false
|
||||
return channel
|
||||
}))
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
if (typeof this.profile.subscriptions !== 'undefined') {
|
||||
this.subscriptions = [].concat(this.profile.subscriptions.sort((a, b) => {
|
||||
const nameA = a.name.toLowerCase()
|
||||
const nameB = b.name.toLowerCase()
|
||||
if (nameA < nameB) {
|
||||
return -1
|
||||
}
|
||||
if (nameA > nameB) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}).map((channel) => {
|
||||
channel.selected = false
|
||||
return channel
|
||||
}))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
displayDeletePrompt: function () {
|
||||
if (this.selectedLength === 0) {
|
||||
this.showToast({
|
||||
message: this.$t('Profile.No channel(s) have been selected')
|
||||
})
|
||||
} else {
|
||||
this.showDeletePrompt = true
|
||||
}
|
||||
},
|
||||
|
||||
handleDeletePromptClick: function (value) {
|
||||
if (value !== 'no' && value !== null) {
|
||||
if (this.isMainProfile) {
|
||||
const channelsToRemove = this.subscriptions.filter((channel) => {
|
||||
return channel.selected
|
||||
})
|
||||
|
||||
this.subscriptions = this.subscriptions.filter((channel) => {
|
||||
return !channel.selected
|
||||
})
|
||||
|
||||
this.profileList.forEach((x) => {
|
||||
const profile = JSON.parse(JSON.stringify(x))
|
||||
profile.subscriptions = profile.subscriptions.filter((channel) => {
|
||||
const index = channelsToRemove.findIndex((y) => {
|
||||
return y.id === channel.id
|
||||
})
|
||||
|
||||
return index === -1
|
||||
})
|
||||
this.updateProfile(profile)
|
||||
|
||||
this.showToast({
|
||||
message: this.$t('Profile.Profile has been updated')
|
||||
})
|
||||
this.selectNone()
|
||||
})
|
||||
} else {
|
||||
const profile = JSON.parse(JSON.stringify(this.profile))
|
||||
|
||||
this.subscriptions = this.subscriptions.filter((channel) => {
|
||||
return !channel.selected
|
||||
})
|
||||
|
||||
profile.subscriptions = this.subscriptions
|
||||
this.selectedLength = 0
|
||||
|
||||
this.updateProfile(profile)
|
||||
|
||||
this.showToast({
|
||||
message: this.$t('Profile.Profile has been updated')
|
||||
})
|
||||
this.selectNone()
|
||||
}
|
||||
}
|
||||
this.showDeletePrompt = false
|
||||
},
|
||||
|
||||
handleChannelClick: function (index) {
|
||||
this.subscriptions[index].selected = !this.subscriptions[index].selected
|
||||
this.selectedLength = this.subscriptions.filter((channel) => {
|
||||
return channel.selected
|
||||
}).length
|
||||
},
|
||||
|
||||
selectAll: function () {
|
||||
Object.keys(this.$refs).forEach((ref) => {
|
||||
if (typeof this.$refs[ref][0] !== 'undefined') {
|
||||
this.$refs[ref][0].selected = true
|
||||
}
|
||||
})
|
||||
|
||||
this.subscriptions = this.subscriptions.map((channel) => {
|
||||
channel.selected = true
|
||||
return channel
|
||||
})
|
||||
|
||||
this.selectedLength = this.subscriptions.filter((channel) => {
|
||||
return channel.selected
|
||||
}).length
|
||||
},
|
||||
|
||||
selectNone: function () {
|
||||
Object.keys(this.$refs).forEach((ref) => {
|
||||
if (typeof this.$refs[ref][0] !== 'undefined') {
|
||||
this.$refs[ref][0].selected = false
|
||||
}
|
||||
})
|
||||
|
||||
this.subscriptions = this.subscriptions.map((channel) => {
|
||||
channel.selected = false
|
||||
return channel
|
||||
})
|
||||
|
||||
this.selectedLength = this.subscriptions.filter((channel) => {
|
||||
return channel.selected
|
||||
}).length
|
||||
},
|
||||
|
||||
...mapActions([
|
||||
'showToast',
|
||||
'updateProfile'
|
||||
])
|
||||
}
|
||||
})
|
|
@ -0,0 +1,49 @@
|
|||
<template>
|
||||
<div>
|
||||
<ft-card class="card">
|
||||
<h2>
|
||||
{{ $t("Profile.Subscription List") }}
|
||||
</h2>
|
||||
<p>
|
||||
{{ selectedText }}
|
||||
</p>
|
||||
<ft-flex-box>
|
||||
<ft-channel-bubble
|
||||
v-for="(channel, index) in subscriptions"
|
||||
:key="index"
|
||||
:ref="`channel-${index}`"
|
||||
:channel-name="channel.name"
|
||||
:channel-thumbnail="channel.thumbnail"
|
||||
:show-selected="true"
|
||||
@click="handleChannelClick(index)"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
<ft-flex-box>
|
||||
<ft-button
|
||||
:label="$t('Profile.Select All')"
|
||||
@click="selectAll"
|
||||
/>
|
||||
<ft-button
|
||||
:label="$t('Profile.Select None')"
|
||||
@click="selectNone"
|
||||
/>
|
||||
<ft-button
|
||||
:label="$t('Profile.Delete Selected')"
|
||||
text-color="var(--text-with-main-color)"
|
||||
background-color="var(--primary-color)"
|
||||
@click="displayDeletePrompt"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
</ft-card>
|
||||
<ft-prompt
|
||||
v-if="showDeletePrompt"
|
||||
:label="deletePromptMessage"
|
||||
:option-names="deletePromptNames"
|
||||
:option-values="deletePromptValues"
|
||||
@click="handleDeletePromptClick"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./ft-profile-channel-list.js" />
|
||||
<style scoped src="./ft-profile-channel-list.css" />
|
|
@ -0,0 +1,45 @@
|
|||
.card {
|
||||
width: 85%;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.message {
|
||||
color: var(--tertiary-text-color);
|
||||
}
|
||||
|
||||
.profileName {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.bottomMargin {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.colorOptions {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.colorOption {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 10px;
|
||||
cursor: pointer;
|
||||
border-radius: 200px 200px 200px 200px;
|
||||
-webkit-border-radius: 200px 200px 200px 200px;
|
||||
}
|
||||
|
||||
.initial {
|
||||
font-size: 50px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
bottom: 27px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 680px) {
|
||||
.card {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
import Vue from 'vue'
|
||||
import { mapActions } from 'vuex'
|
||||
import FtCard from '../../components/ft-card/ft-card.vue'
|
||||
import FtPrompt from '../../components/ft-prompt/ft-prompt.vue'
|
||||
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
|
||||
import FtInput from '../../components/ft-input/ft-input.vue'
|
||||
import FtButton from '../../components/ft-button/ft-button.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'FtProfileEdit',
|
||||
components: {
|
||||
'ft-card': FtCard,
|
||||
'ft-prompt': FtPrompt,
|
||||
'ft-flex-box': FtFlexBox,
|
||||
'ft-input': FtInput,
|
||||
'ft-button': FtButton
|
||||
},
|
||||
props: {
|
||||
profile: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isNew: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
showDeletePrompt: false,
|
||||
profileId: '',
|
||||
profileName: '',
|
||||
profileBgColor: '',
|
||||
profileTextColor: '',
|
||||
profileSubscriptions: [],
|
||||
deletePromptValues: [
|
||||
'yes',
|
||||
'no'
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
colorValues: function () {
|
||||
return this.$store.getters.getColorValues
|
||||
},
|
||||
profileInitial: function () {
|
||||
return this.profileName.slice(0, 1).toUpperCase()
|
||||
},
|
||||
activeProfile: function () {
|
||||
return this.$store.getters.getActiveProfile
|
||||
},
|
||||
defaultProfile: function () {
|
||||
return this.$store.getters.getDefaultProfile
|
||||
},
|
||||
deletePromptLabel: function () {
|
||||
return `${this.$t('Profile.Are you sure you want to delete this profile?')} ${this.$t('Profile["All subscriptions will also be deleted."]')}`
|
||||
},
|
||||
deletePromptNames: function () {
|
||||
return [
|
||||
this.$t('Yes'),
|
||||
this.$t('No')
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
profileBgColor: async function (val) {
|
||||
this.profileTextColor = await this.calculateColorLuminance(val)
|
||||
}
|
||||
},
|
||||
mounted: async function () {
|
||||
this.profileId = this.$route.params.id
|
||||
this.profileName = this.profile.name
|
||||
this.profileBgColor = this.profile.bgColor
|
||||
this.profileTextColor = this.profile.textColor
|
||||
this.profileSubscriptions = this.profile.subscriptions
|
||||
},
|
||||
methods: {
|
||||
openDeletePrompt: function () {
|
||||
this.showDeletePrompt = true
|
||||
},
|
||||
|
||||
handleDeletePrompt: function (response) {
|
||||
if (response === 'yes') {
|
||||
this.deleteProfile()
|
||||
} else {
|
||||
this.showDeletePrompt = false
|
||||
}
|
||||
},
|
||||
|
||||
saveProfile: function () {
|
||||
if (this.profileName === '') {
|
||||
this.showToast({
|
||||
message: this.$t('Profile.Your profile name cannot be empty')
|
||||
})
|
||||
return
|
||||
}
|
||||
const profile = {
|
||||
name: this.profileName,
|
||||
bgColor: this.profileBgColor,
|
||||
textColor: this.profileTextColor,
|
||||
subscriptions: this.profileSubscriptions
|
||||
}
|
||||
|
||||
if (!this.isNew) {
|
||||
profile._id = this.profileId
|
||||
}
|
||||
|
||||
console.log(profile)
|
||||
|
||||
this.updateProfile(profile)
|
||||
|
||||
if (this.isNew) {
|
||||
this.showToast({
|
||||
message: this.$t('Profile.Profile has been created')
|
||||
})
|
||||
this.$router.push({
|
||||
path: '/settings/profile/'
|
||||
})
|
||||
} else {
|
||||
this.showToast({
|
||||
message: this.$t('Profile.Profile has been updated')
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
setDefaultProfile: function () {
|
||||
this.updateDefaultProfile(this.profileId)
|
||||
const message = this.$t('Profile.Your default profile has been set to $').replace('$', this.profileName)
|
||||
this.showToast({
|
||||
message: message
|
||||
})
|
||||
},
|
||||
|
||||
deleteProfile: function () {
|
||||
this.removeProfile(this.profileId)
|
||||
const message = this.$t('Profile.Removed $ from your profiles').replace('$', this.profileName)
|
||||
this.showToast({
|
||||
message: message
|
||||
})
|
||||
if (this.defaultProfile === this.profileId) {
|
||||
this.updateDefaultProfile('allChannels')
|
||||
this.showToast({
|
||||
message: this.$t('Profile.Your default profile has been changed to your primary profile')
|
||||
})
|
||||
}
|
||||
if (this.activeProfile._id === this.profileId) {
|
||||
this.updateActiveProfile('allChannels')
|
||||
}
|
||||
this.$router.push({
|
||||
path: '/settings/profile/'
|
||||
})
|
||||
},
|
||||
|
||||
...mapActions([
|
||||
'showToast',
|
||||
'updateProfile',
|
||||
'removeProfile',
|
||||
'updateDefaultProfile',
|
||||
'updateActiveProfile',
|
||||
'calculateColorLuminance'
|
||||
])
|
||||
}
|
||||
})
|
|
@ -0,0 +1,99 @@
|
|||
<template>
|
||||
<div>
|
||||
<ft-card class="card">
|
||||
<h2>{{ $t("Profile.Edit Profile") }}</h2>
|
||||
<ft-flex-box>
|
||||
<ft-input
|
||||
class="profileName"
|
||||
placeholder="Profile Name"
|
||||
:value="profileName"
|
||||
:show-arrow="false"
|
||||
@input="e => profileName = e"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
<h3>{{ $t("Profile.Color Picker") }}</h3>
|
||||
<ft-flex-box
|
||||
class="bottomMargin colorOptions"
|
||||
>
|
||||
<div
|
||||
v-for="(color, index) in colorValues"
|
||||
:key="index"
|
||||
class="colorOption"
|
||||
:style="{ background: color }"
|
||||
@click="profileBgColor = color"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
<ft-flex-box
|
||||
class="bottomMargin"
|
||||
>
|
||||
<div>
|
||||
<label for="colorPicker">{{ $t("Profile.Custom Color") }}</label>
|
||||
<input
|
||||
id="colorPicker"
|
||||
v-model="profileBgColor"
|
||||
type="color"
|
||||
>
|
||||
</div>
|
||||
</ft-flex-box>
|
||||
<ft-flex-box>
|
||||
<ft-input
|
||||
class="profileName"
|
||||
placeholder=""
|
||||
:value="profileBgColor"
|
||||
:show-arrow="false"
|
||||
:disabled="true"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
<h3>{{ $t("Profile.Profile Preview") }}</h3>
|
||||
<ft-flex-box
|
||||
class="bottomMargin"
|
||||
>
|
||||
<div
|
||||
class="colorOption"
|
||||
:style="{ background: profileBgColor, color: profileTextColor }"
|
||||
style="cursor: default"
|
||||
>
|
||||
<p
|
||||
class="initial"
|
||||
>
|
||||
{{ profileInitial }}
|
||||
</p>
|
||||
</div>
|
||||
</ft-flex-box>
|
||||
<ft-flex-box>
|
||||
<ft-button
|
||||
v-if="isNew"
|
||||
:label="$t('Profile.Create Profile')"
|
||||
@click="saveProfile"
|
||||
/>
|
||||
<ft-button
|
||||
v-if="!isNew"
|
||||
:label="$t('Profile.Update Profile')"
|
||||
@click="saveProfile"
|
||||
/>
|
||||
<ft-button
|
||||
v-if="!isNew"
|
||||
:label="$t('Profile.Make Default Profile')"
|
||||
@click="setDefaultProfile"
|
||||
/>
|
||||
<ft-button
|
||||
v-if="profileId !== 'allChannels' && !isNew"
|
||||
:label="$t('Profile.Delete Profile')"
|
||||
text-color="var(--text-with-main-color)"
|
||||
background-color="var(--primary-color)"
|
||||
@click="openDeletePrompt"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
</ft-card>
|
||||
<ft-prompt
|
||||
v-if="showDeletePrompt"
|
||||
:label="deletePromptLabel"
|
||||
:option-names="deletePromptNames"
|
||||
:option-values="deletePromptValues"
|
||||
@click="handleDeletePrompt"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./ft-profile-edit.js" />
|
||||
<style scoped src="./ft-profile-edit.css" />
|
|
@ -62,6 +62,10 @@ export default Vue.extend({
|
|||
getTimestamp: {
|
||||
type: Function,
|
||||
required: true
|
||||
},
|
||||
isUpcoming: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
@click="$emit('theatreMode')"
|
||||
/>
|
||||
<ft-icon-button
|
||||
v-if="!isUpcoming"
|
||||
:title="$t('Change Format.Change Video Formats')"
|
||||
class="option"
|
||||
theme="secondary"
|
||||
|
|
|
@ -152,6 +152,7 @@ export default Vue.extend({
|
|||
$route() {
|
||||
// react to route changes...
|
||||
this.id = this.$route.params.id
|
||||
this.currentTab = 'videos'
|
||||
this.isLoading = true
|
||||
|
||||
if (!this.usingElectron) {
|
||||
|
@ -224,6 +225,10 @@ export default Vue.extend({
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
goToChannel: function (id) {
|
||||
this.$router.push({ path: `/channel/${id}` })
|
||||
},
|
||||
|
||||
getChannelInfoLocal: function () {
|
||||
this.apiUsed = 'local'
|
||||
ytch.getChannelInfo(this.id).then((response) => {
|
||||
|
|
|
@ -123,6 +123,7 @@
|
|||
:channel-name="channel.author"
|
||||
:channel-id="channel.authorId"
|
||||
:channel-thumbnail="channel.authorThumbnails[channel.authorThumbnails.length - 1].url"
|
||||
@click="goToChannel(channel.authorId)"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
</div>
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
.card {
|
||||
width: 85%;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.message {
|
||||
color: var(--tertiary-text-color);
|
||||
}
|
||||
|
||||
.profileName {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.bottomMargin {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.colorOptions {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.colorOption {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 10px;
|
||||
cursor: pointer;
|
||||
border-radius: 200px 200px 200px 200px;
|
||||
-webkit-border-radius: 200px 200px 200px 200px;
|
||||
}
|
||||
|
||||
.initial {
|
||||
font-size: 50px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
bottom: 27px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 680px) {
|
||||
.card {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
|
@ -1,62 +1,50 @@
|
|||
import Vue from 'vue'
|
||||
import { mapActions } from 'vuex'
|
||||
import FtLoader from '../../components/ft-loader/ft-loader.vue'
|
||||
import FtCard from '../../components/ft-card/ft-card.vue'
|
||||
import FtPrompt from '../../components/ft-prompt/ft-prompt.vue'
|
||||
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
|
||||
import FtInput from '../../components/ft-input/ft-input.vue'
|
||||
import FtButton from '../../components/ft-button/ft-button.vue'
|
||||
import FtProfileEdit from '../../components/ft-profile-edit/ft-profile-edit.vue'
|
||||
import FtProfileChannelList from '../../components/ft-profile-channel-list/ft-profile-channel-list.vue'
|
||||
import FtProfileAllChannelsList from '../../components/ft-profile-all-channels-list/ft-profile-all-channels-list.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'ProfileEdit',
|
||||
components: {
|
||||
'ft-loader': FtLoader,
|
||||
'ft-card': FtCard,
|
||||
'ft-prompt': FtPrompt,
|
||||
'ft-flex-box': FtFlexBox,
|
||||
'ft-input': FtInput,
|
||||
'ft-button': FtButton
|
||||
'ft-profile-edit': FtProfileEdit,
|
||||
'ft-profile-channel-list': FtProfileChannelList,
|
||||
'ft-profile-all-channels-list': FtProfileAllChannelsList
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
isLoading: false,
|
||||
showDeletePrompt: false,
|
||||
deletePromptLabel: '',
|
||||
isNew: false,
|
||||
profileId: '',
|
||||
profileName: '',
|
||||
profileBgColor: '',
|
||||
profileTextColor: '',
|
||||
profileSubscriptions: [],
|
||||
deletePromptValues: [
|
||||
'yes',
|
||||
'no'
|
||||
]
|
||||
profile: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
colorValues: function () {
|
||||
return this.$store.getters.getColorValues
|
||||
profileList: function () {
|
||||
return this.$store.getters.getProfileList
|
||||
},
|
||||
profileInitial: function () {
|
||||
return this.profileName.slice(0, 1).toUpperCase()
|
||||
},
|
||||
activeProfile: function () {
|
||||
return this.$store.getters.getActiveProfile
|
||||
},
|
||||
defaultProfile: function () {
|
||||
return this.$store.getters.getDefaultProfile
|
||||
},
|
||||
deletePromptNames: function () {
|
||||
return [
|
||||
this.$t('Yes'),
|
||||
this.$t('No')
|
||||
]
|
||||
isMainProfile: function () {
|
||||
return this.profileId === 'allChannels'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
profileBgColor: async function (val) {
|
||||
this.profileTextColor = await this.calculateColorLuminance(val)
|
||||
profileList: {
|
||||
handler: function () {
|
||||
this.grabProfileInfo(this.profileId).then((profile) => {
|
||||
if (profile === null) {
|
||||
this.showToast({
|
||||
message: this.$t('Profile.Profile could not be found')
|
||||
})
|
||||
this.$router.push({
|
||||
path: '/settings/profile/'
|
||||
})
|
||||
}
|
||||
this.profile = profile
|
||||
})
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted: async function () {
|
||||
|
@ -67,13 +55,18 @@ export default Vue.extend({
|
|||
|
||||
if (profileType === 'newProfile') {
|
||||
this.isNew = true
|
||||
this.profileBgColor = await this.getRandomColor()
|
||||
const bgColor = await this.getRandomColor()
|
||||
const textColor = await this.calculateColorLuminance(bgColor)
|
||||
this.profile = {
|
||||
name: '',
|
||||
bgColor: bgColor,
|
||||
textColor: textColor,
|
||||
subscriptions: []
|
||||
}
|
||||
this.isLoading = false
|
||||
} else {
|
||||
this.isNew = false
|
||||
this.profileId = this.$route.params.id
|
||||
console.log(this.profileId)
|
||||
console.log(this.$route.name)
|
||||
|
||||
this.grabProfileInfo(this.profileId).then((profile) => {
|
||||
if (profile === null) {
|
||||
|
@ -84,100 +77,17 @@ export default Vue.extend({
|
|||
path: '/settings/profile/'
|
||||
})
|
||||
}
|
||||
this.profileName = profile.name
|
||||
this.profileBgColor = profile.bgColor
|
||||
this.profileTextColor = profile.textColor
|
||||
this.profileSubscriptions = profile.subscriptions
|
||||
this.profile = profile
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openDeletePrompt: function () {
|
||||
this.showDeletePrompt = true
|
||||
},
|
||||
|
||||
handleDeletePrompt: function (response) {
|
||||
if (response === 'yes') {
|
||||
this.deleteProfile()
|
||||
} else {
|
||||
this.showDeletePrompt = false
|
||||
}
|
||||
},
|
||||
|
||||
saveProfile: function () {
|
||||
if (this.profileName === '') {
|
||||
this.showToast({
|
||||
message: this.$t('Profile.Your profile name cannot be empty')
|
||||
})
|
||||
return
|
||||
}
|
||||
const profile = {
|
||||
name: this.profileName,
|
||||
bgColor: this.profileBgColor,
|
||||
textColor: this.profileTextColor,
|
||||
subscriptions: this.profileSubscriptions
|
||||
}
|
||||
|
||||
if (!this.isNew) {
|
||||
profile._id = this.profileId
|
||||
}
|
||||
|
||||
console.log(profile)
|
||||
|
||||
this.updateProfile(profile)
|
||||
|
||||
if (this.isNew) {
|
||||
this.showToast({
|
||||
message: this.$t('Profile.Profile has been created')
|
||||
})
|
||||
this.$router.push({
|
||||
path: '/settings/profile/'
|
||||
})
|
||||
} else {
|
||||
this.showToast({
|
||||
message: this.$t('Profile.Profile has been updated')
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
setDefaultProfile: function () {
|
||||
this.updateDefaultProfile(this.profileId)
|
||||
const message = this.$t('Profile.Your default profile has been set to $').replace('$', this.profileName)
|
||||
this.showToast({
|
||||
message: message
|
||||
})
|
||||
},
|
||||
|
||||
deleteProfile: function () {
|
||||
this.removeProfile(this.profileId)
|
||||
const message = this.$t('Profile.Removed $ from your profiles').replace('$', this.profileName)
|
||||
this.showToast({
|
||||
message: message
|
||||
})
|
||||
if (this.defaultProfile === this.profileId) {
|
||||
this.updateDefaultProfile('allChannels')
|
||||
this.showToast({
|
||||
message: this.$t('Profile.Your default profile has been changed to your primary profile')
|
||||
})
|
||||
}
|
||||
if (this.activeProfile._id === this.profileId) {
|
||||
this.updateActiveProfile('allChannels')
|
||||
}
|
||||
this.$router.push({
|
||||
path: '/settings/profile/'
|
||||
})
|
||||
},
|
||||
|
||||
...mapActions([
|
||||
'showToast',
|
||||
'grabProfileInfo',
|
||||
'updateProfile',
|
||||
'removeProfile',
|
||||
'updateDefaultProfile',
|
||||
'updateActiveProfile',
|
||||
'calculateColorLuminance',
|
||||
'getRandomColor'
|
||||
'getRandomColor',
|
||||
'calculateColorLuminance'
|
||||
])
|
||||
}
|
||||
})
|
||||
|
|
|
@ -7,99 +7,20 @@
|
|||
<div
|
||||
v-else
|
||||
>
|
||||
<ft-card class="card">
|
||||
<h2>{{ $t("Profile.Edit Profile") }}</h2>
|
||||
<ft-flex-box>
|
||||
<ft-input
|
||||
class="profileName"
|
||||
placeholder="Profile Name"
|
||||
:value="profileName"
|
||||
:show-arrow="false"
|
||||
@input="e => profileName = e"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
<h3>{{ $t("Profile.Color Picker") }}</h3>
|
||||
<ft-flex-box
|
||||
class="bottomMargin colorOptions"
|
||||
>
|
||||
<div
|
||||
v-for="(color, index) in colorValues"
|
||||
:key="index"
|
||||
class="colorOption"
|
||||
:style="{ background: color }"
|
||||
@click="profileBgColor = color"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
<ft-flex-box
|
||||
class="bottomMargin"
|
||||
>
|
||||
<div>
|
||||
<label for="colorPicker">{{ $t("Profile.Custom Color") }}</label>
|
||||
<input
|
||||
id="colorPicker"
|
||||
v-model="profileBgColor"
|
||||
type="color"
|
||||
>
|
||||
</div>
|
||||
</ft-flex-box>
|
||||
<ft-flex-box>
|
||||
<ft-input
|
||||
class="profileName"
|
||||
placeholder=""
|
||||
:value="profileBgColor"
|
||||
:show-arrow="false"
|
||||
:disabled="true"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
<h3>{{ $t("Profile.Profile Preview") }}</h3>
|
||||
<ft-flex-box
|
||||
class="bottomMargin"
|
||||
>
|
||||
<div
|
||||
class="colorOption"
|
||||
:style="{ background: profileBgColor, color: profileTextColor }"
|
||||
style="cursor: default"
|
||||
>
|
||||
<p
|
||||
class="initial"
|
||||
>
|
||||
{{ profileInitial }}
|
||||
</p>
|
||||
</div>
|
||||
</ft-flex-box>
|
||||
<ft-flex-box>
|
||||
<ft-button
|
||||
v-if="isNew"
|
||||
:label="$t('Profile.Create Profile')"
|
||||
@click="saveProfile"
|
||||
/>
|
||||
<ft-button
|
||||
v-if="!isNew"
|
||||
:label="$t('Profile.Update Profile')"
|
||||
@click="saveProfile"
|
||||
/>
|
||||
<ft-button
|
||||
v-if="!isNew"
|
||||
:label="$t('Profile.Make Default Profile')"
|
||||
@click="setDefaultProfile"
|
||||
/>
|
||||
<ft-button
|
||||
v-if="profileId !== 'allChannels' && !isNew"
|
||||
:label="$t('Profile.Delete Profile')"
|
||||
text-color="var(--text-with-main-color)"
|
||||
background-color="var(--primary-color)"
|
||||
@click="openDeletePrompt"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
</ft-card>
|
||||
<ft-profile-edit
|
||||
:profile="profile"
|
||||
:is-new="isNew"
|
||||
/>
|
||||
<ft-profile-channel-list
|
||||
v-if="!isNew"
|
||||
:profile="profile"
|
||||
:is-main-profile="isMainProfile"
|
||||
/>
|
||||
<ft-profile-all-channels-list
|
||||
v-if="!isNew && !isMainProfile"
|
||||
:profile="profile"
|
||||
/>
|
||||
</div>
|
||||
<ft-prompt
|
||||
v-if="showDeletePrompt"
|
||||
:label="deletePromptLabel"
|
||||
:option-names="deletePromptNames"
|
||||
:option-values="deletePromptValues"
|
||||
@click="handleDeletePrompt"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@ export default Vue.extend({
|
|||
showYouTubeNoCookieEmbed: false,
|
||||
hidePlayer: false,
|
||||
isLive: false,
|
||||
isUpcoming: false,
|
||||
upcomingTimestamp: null,
|
||||
activeFormat: 'legacy',
|
||||
videoId: '',
|
||||
videoTitle: '',
|
||||
|
@ -215,8 +217,9 @@ export default Vue.extend({
|
|||
this.videoLikeCount = result.videoDetails.likes
|
||||
this.videoDislikeCount = result.videoDetails.dislikes
|
||||
this.isLive = result.player_response.videoDetails.isLiveContent
|
||||
this.isUpcoming = result.player_response.videoDetails.isUpcoming
|
||||
|
||||
if (!this.isLive) {
|
||||
if (!this.isLive && !this.isUpcoming) {
|
||||
const captionTracks =
|
||||
result.player_response.captions &&
|
||||
result.player_response.captions.playerCaptionsTracklistRenderer
|
||||
|
@ -243,7 +246,7 @@ export default Vue.extend({
|
|||
}
|
||||
}
|
||||
|
||||
if (this.isLive) {
|
||||
if (this.isLive && !this.isUpcoming) {
|
||||
this.enableLegacyFormat()
|
||||
|
||||
this.videoSourceList = result.formats.filter((format) => {
|
||||
|
@ -279,28 +282,39 @@ export default Vue.extend({
|
|||
} else {
|
||||
this.activeSourceList = this.videoSourceList
|
||||
}
|
||||
} else if (this.isUpcoming) {
|
||||
const upcomingTimestamp = new Date(result.videoDetails.liveBroadcastDetails.startTimestamp)
|
||||
this.upcomingTimestamp = upcomingTimestamp.toLocaleString()
|
||||
} else {
|
||||
this.videoLengthSeconds = parseInt(result.videoDetails.lengthSeconds)
|
||||
this.videoSourceList = result.player_response.streamingData.formats
|
||||
this.dashSrc = await this.createLocalDashManifest(result.player_response.streamingData.adaptiveFormats)
|
||||
|
||||
this.audioSourceList = result.player_response.streamingData.adaptiveFormats.filter((format) => {
|
||||
return format.mimeType.includes('audio')
|
||||
}).map((format) => {
|
||||
return {
|
||||
url: format.url,
|
||||
type: format.mimeType,
|
||||
label: 'Audio',
|
||||
qualityLabel: format.bitrate
|
||||
if (typeof result.player_response.streamingData.adaptiveFormats !== 'undefined') {
|
||||
this.dashSrc = await this.createLocalDashManifest(result.player_response.streamingData.adaptiveFormats)
|
||||
|
||||
this.audioSourceList = result.player_response.streamingData.adaptiveFormats.filter((format) => {
|
||||
return format.mimeType.includes('audio')
|
||||
}).map((format) => {
|
||||
return {
|
||||
url: format.url,
|
||||
type: format.mimeType,
|
||||
label: 'Audio',
|
||||
qualityLabel: format.bitrate
|
||||
}
|
||||
}).sort((a, b) => {
|
||||
return a.qualityLabel - b.qualityLabel
|
||||
})
|
||||
|
||||
if (this.activeFormat === 'audio') {
|
||||
this.activeSourceList = this.audioSourceList
|
||||
} else {
|
||||
this.activeSourceList = this.videoSourceList
|
||||
}
|
||||
}).sort((a, b) => {
|
||||
return a.qualityLabel - b.qualityLabel
|
||||
})
|
||||
|
||||
if (this.activeFormat === 'audio') {
|
||||
this.activeSourceList = this.audioSourceList
|
||||
} else {
|
||||
this.activeSourceList = this.videoSourceList
|
||||
this.audioSourceList = null
|
||||
this.dashSrc = null
|
||||
this.enableLegacyFormat()
|
||||
}
|
||||
|
||||
if (typeof result.player_response.storyboards !== 'undefined') {
|
||||
|
@ -528,6 +542,13 @@ export default Vue.extend({
|
|||
return
|
||||
}
|
||||
|
||||
if (this.dashSrc === null) {
|
||||
this.showToast({
|
||||
message: this.$t('Change Format.Dash formats are not available for this video')
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.activeFormat = 'dash'
|
||||
this.hidePlayer = true
|
||||
|
||||
|
@ -555,6 +576,13 @@ export default Vue.extend({
|
|||
return
|
||||
}
|
||||
|
||||
if (this.audioSourceList === null) {
|
||||
this.showToast({
|
||||
message: this.$t('Change Format.Audio formats are not available for this video')
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.activeFormat = 'audio'
|
||||
this.activeSourceList = this.audioSourceList
|
||||
this.hidePlayer = true
|
||||
|
|
|
@ -35,6 +35,30 @@
|
|||
grid-column: 1
|
||||
max-width: calc(80vh * 1.78)
|
||||
margin: 0 auto
|
||||
position: relative
|
||||
|
||||
.upcomingThumbnail
|
||||
width: 100%
|
||||
|
||||
.premiereDate
|
||||
color: #FFFFFF
|
||||
background-color: rgba(0, 0, 0, 0.7)
|
||||
width: 400px
|
||||
height: 60px
|
||||
border-radius: 5%
|
||||
position: absolute
|
||||
bottom: 5px
|
||||
|
||||
.premiereIcon
|
||||
float: left
|
||||
font-size: 25px
|
||||
margin-top: 12px
|
||||
margin-left: 8px
|
||||
padding: 5px
|
||||
|
||||
.premiereText
|
||||
margin-left: 50px
|
||||
margin-top: 10px
|
||||
|
||||
.watchVideo
|
||||
margin: 0px 8px 16px
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<div class="videoArea">
|
||||
<div class="videoAreaMargin">
|
||||
<ft-video-player
|
||||
v-if="!isLoading && !hidePlayer"
|
||||
v-if="!isLoading && !hidePlayer && !isUpcoming"
|
||||
ref="videoPlayer"
|
||||
:dash-src="dashSrc"
|
||||
:source-list="activeSourceList"
|
||||
|
@ -27,6 +27,30 @@
|
|||
@ended="handleVideoEnded"
|
||||
@error="handleVideoError"
|
||||
/>
|
||||
<div
|
||||
v-if="!isLoading && isUpcoming"
|
||||
class="videoPlayer"
|
||||
>
|
||||
<img
|
||||
:src="thumbnail"
|
||||
class="upcomingThumbnail"
|
||||
/>
|
||||
<div
|
||||
class='premiereDate'
|
||||
>
|
||||
<font-awesome-icon
|
||||
icon="satellite-dish"
|
||||
class="premiereIcon"
|
||||
/>
|
||||
<p
|
||||
class="premiereText"
|
||||
>
|
||||
Premieres on:
|
||||
<br />
|
||||
{{ upcomingTimestamp }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="infoArea">
|
||||
|
@ -43,6 +67,7 @@
|
|||
:dislike-count="videoDislikeCount"
|
||||
:view-count="videoViewCount"
|
||||
:get-timestamp="getTimestamp"
|
||||
:is-upcoming="isUpcoming"
|
||||
class="watchVideo"
|
||||
:class="{ theatreWatchVideo: useTheatreMode }"
|
||||
@theatreMode="toggleTheatreMode"
|
||||
|
|
|
@ -306,6 +306,16 @@ Profile:
|
|||
Your default profile has been changed to your primary profile: Your default profile
|
||||
has been changed to your primary profile
|
||||
$ is now the active profile: $ is now the active profile
|
||||
Subscription List: Subscription List
|
||||
Other Channels: Other Channels
|
||||
$ selected: $ selected
|
||||
Select All: Select All
|
||||
Select None: Select None
|
||||
Delete Selected: Delete Selected
|
||||
Add Selected To Profile: Add Selected To Profile
|
||||
No channel(s) have been selected: No channel(s) have been selected
|
||||
This is your primary profile. Are you sure you want to delete the selected channels? The same channels will be deleted in any profile they are found in.: This is your primary profile. Are you sure you want to delete the selected channels? The same channels will be deleted in any profile they are found in.
|
||||
Are you sure you want to delete the selected channels? This will not delete the channel from any other profile.: Are you sure you want to delete the selected channels? This will not delete the channel from any other profile.
|
||||
#On Channel Page
|
||||
Channel:
|
||||
Subscriber: Subscriber
|
||||
|
@ -435,6 +445,8 @@ Change Format:
|
|||
Use Dash Formats: Use Dash Formats
|
||||
Use Legacy Formats: Use Legacy Formats
|
||||
Use Audio Formats: Use Audio Formats
|
||||
Dash formats are not available for this video: Dash formats are not available for this video
|
||||
Audio formats are not available for this video: Audio formats are not available for this video
|
||||
Share:
|
||||
Share Video: Share Video
|
||||
Include Timestamp: Include Timestamp
|
||||
|
|
Loading…
Reference in New Issue