Repository navigation
Expand file tree
/
Copy pathplugin.js
More file actions
124 lines (116 loc) · 6.67 KB
/
Copy pathplugin.js
File metadata and controls
124 lines (116 loc) · 6.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Native - makes Cider look and behave like Music on macOS.
// One plugin, one menu entry ("… > Plugins > Native…"), and every part can be switched on or off live from that sheet.
// Console: CiderNative.open() | .discover() | .set('sidebar', false) | .setEnabled(false) | .diagnostics()
import { PARTS, PART, STORAGE_KEY, LEGACY_KEYS, RENAMED_KEYS, PLAYER_SCALE, defaultSettings, parseSettings, migrateLegacy, isOn, configOn, activeStyles, recommendedPlan } from './settings.js';
import { STYLES } from './styles.js';
import { app, ls, warn, refreshAppearance } from './core.js';
import { startSidebar, stopSidebar, setDiscoverRow, startUpNext, stopUpNext, sidebarDiagnostics } from './sidebar.js';
import { startPlayer, stopPlayer, setPlayerScale, playerDiagnostics } from './player.js';
import { startNotifications, stopNotifications, startShortcuts, stopShortcuts, startWindowControls, stopWindowControls, startIcons, stopIcons, iconsDiagnostics, audioReport } from './system.js';
import { openPanel } from './panel.js';
import { startDiscover, stopDiscover, openDiscover, discoverDiagnostics, discoverDebug } from './discover.js';
const VERSION = '1.4.0';
const MODULES = {
sidebar: { start: (s) => startSidebar({ discover: isOn(s, 'discover') }), stop: stopSidebar },
discover: { start: startDiscover, stop: stopDiscover },
upNext: { start: startUpNext, stop: stopUpNext },
player: { start: (s) => startPlayer({ scale: PLAYER_SCALE[s.playerSize] }), stop: stopPlayer },
windowControls: { start: startWindowControls, stop: stopWindowControls },
icons: { start: startIcons, stop: stopIcons },
notifications: { start: startNotifications, stop: stopNotifications },
shortcuts: { start: startShortcuts, stop: stopShortcuts },
};
let settings = defaultSettings();
const running = new Set();
const config = () => app()?.config;
const getValue = (path) => { try { return config()?.getValue?.(path); } catch { return undefined; } };
const save = () => ls.set(STORAGE_KEY, JSON.stringify(settings));
// ---- applying settings ----
function applyStyles() {
const want = settings.enabled ? ['base', ...activeStyles(settings)] : [];
for (const el of document.querySelectorAll('style[data-native]')) if (!want.includes(el.dataset.native)) el.remove();
for (const id of want) {
if (document.querySelector(`style[data-native="${id}"]`) || !STYLES[id]) continue;
const st = document.createElement('style'); st.dataset.native = id; st.textContent = STYLES[id]; document.head.appendChild(st);
}
refreshAppearance();
}
function applyModules() {
for (const p of PARTS) {
if (!p.module) continue;
const want = isOn(settings, p.id), mod = MODULES[p.module];
try {
if (want && !running.has(p.module)) { mod.start(settings); running.add(p.module); }
else if (!want && running.has(p.module)) { mod.stop(); running.delete(p.module); }
} catch (err) { warn(`${p.module} failed to ${want ? 'start' : 'stop'}`, err); }
}
setDiscoverRow(isOn(settings, 'discover'));
setPlayerScale(PLAYER_SCALE[settings.playerSize]);
}
const apply = () => { applyStyles(); applyModules(); };
function writeConfig(pairs) {
const c = config(); if (!c?.setValue) return;
for (const [path, value] of pairs) if (getValue(path) !== undefined) c.setValue(path, value); // never creates unknown keys
c.saveConfig?.();
}
// ---- public API (panel + console) ----
const api = {
version: VERSION,
state: () => ({ ...settings, parts: { ...settings.parts }, config: Object.fromEntries(PARTS.filter((p) => p.config).map((p) => [p.id, configOn(p, getValue)])) }),
set(id, on) {
const p = PART[id]; if (!p || p.choice) return;
if (p.config) { writeConfig([[p.config.path, on ? p.config.on : p.config.off]]); return; }
settings.parts[id] = !!on; save(); apply();
},
setEnabled(on) { settings.enabled = !!on; save(); apply(); },
setPlayerSize(size) { if (PLAYER_SCALE[size]) { settings.playerSize = size; save(); setPlayerScale(PLAYER_SCALE[size]); } },
reset() { settings = { ...defaultSettings(), recommendedApplied: true }; save(); writeConfig(recommendedPlan(getValue)); apply(); },
open: () => openPanel(api),
discover: () => openDiscover(),
discoverDebug,
audioReport,
diagnostics: (opts) => ({
version: VERSION, settings: api.state(), modules: [...running], styles: [...document.querySelectorAll('style[data-native]')].map((e) => e.dataset.native),
path: (() => { try { return app()?.PodRouter?.()?.currentPath ?? null; } catch { return null; } })(),
sidebar: sidebarDiagnostics(), player: playerDiagnostics(), icons: iconsDiagnostics(), discover: discoverDiagnostics(opts),
}),
};
// ---- first run: settings from the four plugins and the theme this one replaces ----
function migrate() {
const s = migrateLegacy(ls.get);
// keep "already sized once" flags so the user's sidebar / Up Next widths are not reset
if (ls.get('native-sidebars/width-v1') === '1') ls.set('native/sidebar-width', '1');
if (ls.get('native-sidebars/upnext-width-v2') === '1') ls.set('native/upnext-width', '1');
for (const [from, to] of Object.entries(RENAMED_KEYS)) { const v = ls.get(from); if (v !== null && ls.get(to) === null) ls.set(to, v); ls.del(from); }
for (const k of LEGACY_KEYS) ls.del(k);
// The old "Native" theme's stylesheets are part of this plugin now: switch them off in Cider's theme list, keeping the
// user's choice of the two optional ones (red accent, system font).
try {
const vapp = (document.querySelector('[data-v-app]') || document.getElementById('q-app'))?.__vue_app__;
const store = vapp?.config?.globalProperties?.$pinia?._s?.get('theme-store');
const old = [...(store?.appliedThemes ?? [])].filter((t) => typeof t === 'string' && t.startsWith('native/'));
if (old.length) {
if (!old.includes('native/accent-red.css')) s.parts.accent = false;
if (!old.includes('native/system-font.css')) s.parts.font = false;
for (const t of old) { const i = t.indexOf('/'); store.toggleTheme(t.slice(0, i), t.slice(i + 1)); }
}
} catch (err) { warn('could not retire the old Native theme', err); }
return s;
}
function registerMenu() {
const menu = window.__PLUGINSYS__?.Components?.MainMenu; if (!menu) return false;
menu.addMenuItem({ label: 'Native…', onClick: () => api.open() });
return true;
}
export default {
name: 'Native', identifier: 'native', pluginKitVersion: 1,
setup() {
const raw = ls.get(STORAGE_KEY);
settings = raw ? parseSettings(raw) : migrate();
if (!settings.recommendedApplied) { writeConfig(recommendedPlan(getValue)); settings.recommendedApplied = true; }
save();
window.CiderNative = api;
apply();
if (!registerMenu()) setTimeout(registerMenu, 1500); // the plugin API object can appear slightly after plugins load
},
};