aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/src/app/app.component.ts6
-rw-r--r--client/src/app/core/theme/theme.service.ts91
2 files changed, 83 insertions, 14 deletions
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts
index 6b18e5feb..1724bbd1a 100644
--- a/client/src/app/app.component.ts
+++ b/client/src/app/app.component.ts
@@ -71,6 +71,9 @@ export class AppComponent implements OnInit {
71 ngOnInit () { 71 ngOnInit () {
72 document.getElementById('incompatible-browser').className += ' browser-ok' 72 document.getElementById('incompatible-browser').className += ' browser-ok'
73 73
74 this.loadPlugins()
75 this.themeService.initialize()
76
74 this.authService.loadClientCredentials() 77 this.authService.loadClientCredentials()
75 78
76 if (this.isUserLoggedIn()) { 79 if (this.isUserLoggedIn()) {
@@ -86,9 +89,6 @@ export class AppComponent implements OnInit {
86 this.serverService.loadVideoPrivacies() 89 this.serverService.loadVideoPrivacies()
87 this.serverService.loadVideoPlaylistPrivacies() 90 this.serverService.loadVideoPlaylistPrivacies()
88 91
89 this.loadPlugins()
90 this.themeService.initialize()
91
92 // Do not display menu on small screens 92 // Do not display menu on small screens
93 if (this.screenService.isInSmallView()) { 93 if (this.screenService.isInSmallView()) {
94 this.isMenuDisplayed = false 94 this.isMenuDisplayed = false
diff --git a/client/src/app/core/theme/theme.service.ts b/client/src/app/core/theme/theme.service.ts
index 012488075..b312e8f7a 100644
--- a/client/src/app/core/theme/theme.service.ts
+++ b/client/src/app/core/theme/theme.service.ts
@@ -4,13 +4,21 @@ import { ServerService } from '@app/core/server'
4import { environment } from '../../../environments/environment' 4import { environment } from '../../../environments/environment'
5import { PluginService } from '@app/core/plugins/plugin.service' 5import { PluginService } from '@app/core/plugins/plugin.service'
6import { ServerConfigTheme } from '@shared/models' 6import { ServerConfigTheme } from '@shared/models'
7import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
7 8
8@Injectable() 9@Injectable()
9export class ThemeService { 10export class ThemeService {
10 11
12 private static KEYS = {
13 LAST_ACTIVE_THEME: 'last_active_theme'
14 }
15
11 private oldThemeName: string 16 private oldThemeName: string
12 private themes: ServerConfigTheme[] = [] 17 private themes: ServerConfigTheme[] = []
13 18
19 private themeFromLocalStorage: ServerConfigTheme
20 private themeDOMLinksFromLocalStorage: HTMLLinkElement[] = []
21
14 constructor ( 22 constructor (
15 private auth: AuthService, 23 private auth: AuthService,
16 private pluginService: PluginService, 24 private pluginService: PluginService,
@@ -18,22 +26,30 @@ export class ThemeService {
18 ) {} 26 ) {}
19 27
20 initialize () { 28 initialize () {
29 // Try to load from local storage first, so we don't have to wait network requests
30 this.loadAndSetFromLocalStorage()
31
21 this.server.configLoaded 32 this.server.configLoaded
22 .subscribe(() => { 33 .subscribe(() => {
23 this.injectThemes() 34 const themes = this.server.getConfig().theme.registered
35
36 this.removeThemeFromLocalStorageIfNeeded(themes)
37 this.injectThemes(themes)
24 38
25 this.listenUserTheme() 39 this.listenUserTheme()
26 }) 40 })
27 } 41 }
28 42
29 private injectThemes () { 43 private injectThemes (themes: ServerConfigTheme[], fromLocalStorage = false) {
30 this.themes = this.server.getConfig().theme.registered 44 this.themes = themes
31 45
32 console.log('Injecting %d themes.', this.themes.length) 46 console.log('Injecting %d themes.', this.themes.length)
33 47
34 const head = document.getElementsByTagName('head')[0] 48 const head = this.getHeadElement()
35 49
36 for (const theme of this.themes) { 50 for (const theme of this.themes) {
51 // Already added this theme?
52 if (fromLocalStorage === false && this.themeFromLocalStorage && this.themeFromLocalStorage.name === theme.name) continue
37 53
38 for (const css of theme.css) { 54 for (const css of theme.css) {
39 const link = document.createElement('link') 55 const link = document.createElement('link')
@@ -45,12 +61,16 @@ export class ThemeService {
45 link.setAttribute('title', theme.name) 61 link.setAttribute('title', theme.name)
46 link.setAttribute('disabled', '') 62 link.setAttribute('disabled', '')
47 63
64 if (fromLocalStorage === true) this.themeDOMLinksFromLocalStorage.push(link)
65
48 head.appendChild(link) 66 head.appendChild(link)
49 } 67 }
50 } 68 }
51 } 69 }
52 70
53 private getCurrentTheme () { 71 private getCurrentTheme () {
72 if (this.themeFromLocalStorage) return this.themeFromLocalStorage.name
73
54 if (this.auth.isLoggedIn()) { 74 if (this.auth.isLoggedIn()) {
55 const theme = this.auth.getUser().theme 75 const theme = this.auth.getUser().theme
56 if (theme !== 'instance-default') return theme 76 if (theme !== 'instance-default') return theme
@@ -70,13 +90,7 @@ export class ThemeService {
70 } 90 }
71 91
72 private updateCurrentTheme () { 92 private updateCurrentTheme () {
73 if (this.oldThemeName) { 93 if (this.oldThemeName) this.removeThemePlugins(this.oldThemeName)
74 const oldTheme = this.getTheme(this.oldThemeName)
75 if (oldTheme) {
76 console.log('Removing scripts of old theme %s.', this.oldThemeName)
77 this.pluginService.removePlugin(oldTheme)
78 }
79 }
80 94
81 const currentTheme = this.getCurrentTheme() 95 const currentTheme = this.getCurrentTheme()
82 96
@@ -90,12 +104,20 @@ export class ThemeService {
90 this.pluginService.addPlugin(theme, true) 104 this.pluginService.addPlugin(theme, true)
91 105
92 this.pluginService.reloadLoadedScopes() 106 this.pluginService.reloadLoadedScopes()
107
108 peertubeLocalStorage.setItem(ThemeService.KEYS.LAST_ACTIVE_THEME, JSON.stringify(theme))
109 } else {
110 peertubeLocalStorage.removeItem(ThemeService.KEYS.LAST_ACTIVE_THEME)
93 } 111 }
94 112
95 this.oldThemeName = currentTheme 113 this.oldThemeName = currentTheme
96 } 114 }
97 115
98 private listenUserTheme () { 116 private listenUserTheme () {
117 // We don't need them anymore
118 this.themeFromLocalStorage = undefined
119 this.themeDOMLinksFromLocalStorage = []
120
99 if (!this.auth.isLoggedIn()) { 121 if (!this.auth.isLoggedIn()) {
100 this.updateCurrentTheme() 122 this.updateCurrentTheme()
101 } 123 }
@@ -104,6 +126,53 @@ export class ThemeService {
104 .subscribe(() => this.updateCurrentTheme()) 126 .subscribe(() => this.updateCurrentTheme())
105 } 127 }
106 128
129 private loadAndSetFromLocalStorage () {
130 const lastActiveThemeString = peertubeLocalStorage.getItem(ThemeService.KEYS.LAST_ACTIVE_THEME)
131 if (!lastActiveThemeString) return
132
133 try {
134 const lastActiveTheme = JSON.parse(lastActiveThemeString)
135 this.themeFromLocalStorage = lastActiveTheme
136
137 this.injectThemes([ lastActiveTheme ], true)
138 this.updateCurrentTheme()
139 } catch (err) {
140 console.error('Cannot parse last active theme.', err)
141 return
142 }
143 }
144
145 private removeThemePlugins (themeName: string) {
146 const oldTheme = this.getTheme(themeName)
147 if (oldTheme) {
148 console.log('Removing scripts of old theme %s.', themeName)
149 this.pluginService.removePlugin(oldTheme)
150 }
151 }
152
153 private removeThemeFromLocalStorageIfNeeded (themes: ServerConfigTheme[]) {
154 if (!this.themeFromLocalStorage) return
155
156 const loadedTheme = themes.find(t => t.name === this.themeFromLocalStorage.name)
157 if (!loadedTheme || loadedTheme.version !== this.themeFromLocalStorage.version) {
158 // Need to remove this theme: we loaded an old version or a theme that does not exist anymore
159 this.removeThemePlugins(this.themeFromLocalStorage.name)
160 this.oldThemeName = undefined
161
162 const head = this.getHeadElement()
163 for (const htmlLinkElement of this.themeDOMLinksFromLocalStorage) {
164 head.removeChild(htmlLinkElement)
165 }
166
167 this.themeFromLocalStorage = undefined
168 this.themeDOMLinksFromLocalStorage = []
169 }
170 }
171
172 private getHeadElement () {
173 return document.getElementsByTagName('head')[0]
174 }
175
107 private getTheme (name: string) { 176 private getTheme (name: string) {
108 return this.themes.find(t => t.name === name) 177 return this.themes.find(t => t.name === name)
109 } 178 }