mirror of
https://github.com/Myxelium/Bridge-Multi.git
synced 2026-04-11 14:19:38 +00:00
Fix settings page
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
<div *ngIf="settingsLoaded" style="display: flex; flex-direction: column; height: 100%">
|
<div *ngIf="settingsLoaded" class="flex flex-col h-screen">
|
||||||
<app-toolbar></app-toolbar>
|
<app-toolbar></app-toolbar>
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<div id="sidebarCard" *ngIf="selectedVersion" class="ui fluid card">
|
<div id="sidebarCard" *ngIf="selectedVersion" class="ui fluid card">
|
||||||
<div class="ui placeholder" [ngClass]="{ placeholder: albumArtSrc === '', inverted: settingsService.theme === 'Dark' }">
|
<div class="ui placeholder" [ngClass]="{ placeholder: albumArtSrc === '', inverted: settingsService.theme === 'dark' }">
|
||||||
<img *ngIf="albumArtSrc !== null" class="ui square image" [src]="albumArtSrc" />
|
<img *ngIf="albumArtSrc !== null" class="ui square image" [src]="albumArtSrc" />
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="charts.length > 1" id="chartDropdown" class="ui fluid right labeled scrolling icon dropdown button">
|
<div *ngIf="charts.length > 1" id="chartDropdown" class="ui fluid right labeled scrolling icon dropdown button">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<table
|
<table
|
||||||
id="resultTable"
|
id="resultTable"
|
||||||
class="ui stackable selectable single sortable fixed line striped compact small table"
|
class="ui stackable selectable single sortable fixed line striped compact small table"
|
||||||
[class.inverted]="settingsService.theme === 'Dark'">
|
[class.inverted]="settingsService.theme === 'dark'">
|
||||||
<!-- TODO: maybe have some of these tags customizable? E.g. small/large/compact/padded -->
|
<!-- TODO: maybe have some of these tags customizable? E.g. small/large/compact/padded -->
|
||||||
<!-- TODO: learn semantic themes in order to change the $mobileBreakpoint global variable (better search table adjustment) -->
|
<!-- TODO: learn semantic themes in order to change the $mobileBreakpoint global variable (better search table adjustment) -->
|
||||||
<thead>
|
<thead>
|
||||||
|
|||||||
@@ -1,64 +1,68 @@
|
|||||||
<h3 class="ui header">Paths</h3>
|
<div class="p-8 flex flex-col gap-3">
|
||||||
<div class="ui form">
|
<label class="form-control w-full">
|
||||||
<div class="field">
|
<div class="label">
|
||||||
<label>Chart library directory</label>
|
<span class="label-text">Chart library directory</span>
|
||||||
<div class="ui action input">
|
</div>
|
||||||
|
<div class="join w-full">
|
||||||
<input
|
<input
|
||||||
[value]="settingsService.libraryDirectory || 'No folder selected'"
|
[value]="settingsService.libraryDirectory || 'No folder selected'"
|
||||||
class="default-cursor"
|
class="join-item input input-bordered cursor-default pointer-events-none flex-1"
|
||||||
readonly
|
readonly
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="No directory selected!" />
|
placeholder="No directory selected!" />
|
||||||
<button *ngIf="settingsService.libraryDirectory !== undefined" (click)="openLibraryDirectory()" class="ui button">Open Folder</button>
|
<button *ngIf="settingsService.libraryDirectory !== undefined" (click)="openLibraryDirectory()" class="join-item btn btn-neutral">
|
||||||
<button (click)="getLibraryDirectory()" class="ui button positive">Choose</button>
|
Open Folder
|
||||||
|
</button>
|
||||||
|
<button (click)="getLibraryDirectory()" class="join-item btn btn-primary">Choose</button>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="form-control w-full max-w-xs">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">Theme</span>
|
||||||
|
</div>
|
||||||
|
<div class="dropdown dropdown-hover">
|
||||||
|
<label tabindex="0" class="btn btn-neutral">{{ capitalize(settingsService.theme) }}</label>
|
||||||
|
<ul tabindex="0" class="dropdown-content z-[2] menu p-2 shadow bg-neutral text-neutral-content rounded-box w-36">
|
||||||
|
<li>
|
||||||
|
<h2 class="menu-title text-neutral-content text-opacity-50">Dark</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a (click)="setTheme('business')">Business</a></li>
|
||||||
|
<li><a (click)="setTheme('dark')">Dark</a></li>
|
||||||
|
<li><a (click)="setTheme('halloween')">Halloween</a></li>
|
||||||
|
<li><a (click)="setTheme('night')">Night</a></li>
|
||||||
|
<li><a (click)="setTheme('synthwave')">Synthwave</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<h2 class="menu-title text-neutral-content text-opacity-50">Light</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a (click)="setTheme('aqua')">Aqua</a></li>
|
||||||
|
<li><a (click)="setTheme('emerald')">Emerald</a></li>
|
||||||
|
<li><a (click)="setTheme('lemonade')">Lemonade</a></li>
|
||||||
|
<li><a (click)="setTheme('valentine')">Valentine</a></li>
|
||||||
|
<li><a (click)="setTheme('winter')">Winter</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="absolute bottom-8 right-8 flex gap-6">
|
||||||
|
<div class="join">
|
||||||
|
<button *ngIf="updateAvailable" class="join-item btn btn-primary" (click)="downloadUpdate()">
|
||||||
|
<i class="bi text-xl" [ngClass]="updateDownloaded ? 'bi-arrow-repeat' : 'bi-cloud-arrow-down'"></i>{{ downloadUpdateText }}
|
||||||
|
</button>
|
||||||
|
<button *ngIf="updateAvailable === null" class="join-item btn btn-warning" [class.disabled]="updateRetrying" (click)="retryUpdate()">
|
||||||
|
<i class="bi bi-arrow-repeat text-xl" [class.loading]="updateRetrying"></i>{{ retryUpdateText }}
|
||||||
|
</button>
|
||||||
|
<button class="join-item btn btn-outline btn-disabled">{{ currentVersion }}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tooltip tooltip-left" data-tip="Toggle developer tools">
|
||||||
|
<button class="btn btn-primary btn-square btn-neutral" (click)="toggleDevTools()">
|
||||||
|
<i class="bi bi-gear text-lg"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="ui header">Downloads</h3>
|
|
||||||
<div class="ui form">
|
|
||||||
<div class="field">
|
|
||||||
<div appCheckbox #videoCheckbox class="ui checkbox" (checked)="downloadVideos($event)">
|
|
||||||
<input type="checkbox" />
|
|
||||||
<label>Download video backgrounds</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label>Google rate limit delay</label>
|
|
||||||
<div id="rateLimitInput" class="ui right labeled input">
|
|
||||||
<input type="number" [value]="settingsService.rateLimitDelay" (input)="changeRateLimit($event)" />
|
|
||||||
<div class="ui basic label">sec</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="settingsService.rateLimitDelay < 30" class="ui warning message">
|
|
||||||
<i class="exclamation circle icon"></i>
|
|
||||||
<b>Warning:</b> downloading files from Google with a delay less than about 30 seconds will eventually cause Google to refuse download requests from
|
|
||||||
this program for a few hours. This limitation will be removed in a future update.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3 class="ui header">Theme</h3>
|
|
||||||
<div #themeDropdown class="ui selection dropdown mr">
|
|
||||||
<input type="hidden" name="sort" [value]="settingsService.theme" />
|
|
||||||
<i class="dropdown icon"></i>
|
|
||||||
<div class="default text">{{ settingsService.theme }}</div>
|
|
||||||
<div class="menu">
|
|
||||||
<div class="item" [attr.data-value]="i" *ngFor="let theme of settingsService.builtinThemes; let i = index">{{ theme }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="bottom">
|
|
||||||
<div class="ui buttons">
|
|
||||||
<button *ngIf="updateAvailable" class="ui labeled icon positive button" (click)="downloadUpdate()">
|
|
||||||
<i class="left alternate icon" [ngClass]="updateDownloaded ? 'sync' : 'cloud download'"></i>{{ downloadUpdateText }}
|
|
||||||
</button>
|
|
||||||
<button *ngIf="updateAvailable === null" class="ui labeled yellow icon button" [class.disabled]="updateRetrying" (click)="retryUpdate()">
|
|
||||||
<i class="left alternate sync alternate icon" [class.loading]="updateRetrying"></i>{{ retryUpdateText }}
|
|
||||||
</button>
|
|
||||||
<button id="versionNumberButton" class="ui basic disabled button">{{ currentVersion }}</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button class="ui basic icon button" data-tooltip="Toggle developer tools" data-position="top right" (click)="toggleDevTools()">
|
|
||||||
<i class="cog icon"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
:host {
|
|
||||||
flex: 1;
|
|
||||||
padding: 2em;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.default-cursor {
|
|
||||||
cursor: default;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#rateLimitInput {
|
|
||||||
width: unset !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 2em;
|
|
||||||
right: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#versionNumberButton {
|
|
||||||
margin-right: 1em;
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core'
|
import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core'
|
||||||
|
|
||||||
import { CheckboxDirective } from 'src-angular/app/core/directives/checkbox.directive'
|
import { capitalize } from 'lodash'
|
||||||
import { SettingsService } from 'src-angular/app/core/services/settings.service'
|
import { SettingsService } from 'src-angular/app/core/services/settings.service'
|
||||||
|
import { themes } from 'src-shared/Settings'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-settings',
|
selector: 'app-settings',
|
||||||
templateUrl: './settings.component.html',
|
templateUrl: './settings.component.html',
|
||||||
styleUrls: ['./settings.component.scss'],
|
|
||||||
})
|
})
|
||||||
export class SettingsComponent implements OnInit, AfterViewInit {
|
export class SettingsComponent implements OnInit {
|
||||||
@ViewChild('themeDropdown', { static: true }) themeDropdown: ElementRef
|
@ViewChild('themeDropdown', { static: true }) themeDropdown: ElementRef
|
||||||
@ViewChild(CheckboxDirective, { static: true }) videoCheckbox: CheckboxDirective
|
|
||||||
|
|
||||||
updateAvailable: boolean | null = false
|
updateAvailable: boolean | null = false
|
||||||
loginClicked = false
|
loginClicked = false
|
||||||
@@ -52,17 +51,6 @@ export class SettingsComponent implements OnInit, AfterViewInit {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
|
||||||
// TODO
|
|
||||||
// $(this.themeDropdown.nativeElement).dropdown({
|
|
||||||
// onChange: (_value: string, text: string) => {
|
|
||||||
// this.settingsService.theme = text
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
|
|
||||||
this.videoCheckbox.check(this.settingsService.downloadVideos)
|
|
||||||
}
|
|
||||||
|
|
||||||
async downloadVideos(isChecked: boolean) {
|
async downloadVideos(isChecked: boolean) {
|
||||||
this.settingsService.downloadVideos = isChecked
|
this.settingsService.downloadVideos = isChecked
|
||||||
}
|
}
|
||||||
@@ -85,9 +73,12 @@ export class SettingsComponent implements OnInit, AfterViewInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changeRateLimit(event: Event) {
|
setTheme(theme: typeof themes[number]) {
|
||||||
const inputElement = event.srcElement as HTMLInputElement
|
this.settingsService.theme = theme
|
||||||
this.settingsService.rateLimitDelay = Number(inputElement.value)
|
}
|
||||||
|
|
||||||
|
capitalize(text: string) {
|
||||||
|
return capitalize(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadUpdate() {
|
downloadUpdate() {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<div class="navbar p-0 min-h-0 bg-base-100" style="-webkit-app-region: drag">
|
<div class="navbar p-0 min-h-0 bg-base-100" style="-webkit-app-region: drag">
|
||||||
<div style="-webkit-app-region: no-drag">
|
<div style="-webkit-app-region: no-drag">
|
||||||
<button class="btn btn-square btn-ghost rounded-none px-14 cursor-default" routerLinkActive="btn-active" routerLink="/browse">Browse</button>
|
<button class="btn btn-square btn-ghost rounded-none px-10 cursor-default" routerLinkActive="btn-active" routerLink="/browse">Browse</button>
|
||||||
<!-- TODO <a class="btn btn-square btn-ghost rounded-none cursor-default" routerLinkActive="btn-active" routerLink="/library">Library</a> -->
|
<!-- TODO <a class="btn btn-square btn-ghost rounded-none cursor-default" routerLinkActive="btn-active" routerLink="/library">Library</a> -->
|
||||||
<button class="btn btn-square btn-ghost rounded-none px-12 cursor-default" routerLinkActive="btn-active" routerLink="/settings">
|
<button class="btn btn-square btn-ghost rounded-none px-10 cursor-default" routerLinkActive="btn-active" routerLink="/settings">
|
||||||
<i *ngIf="updateAvailable" class="teal small circle icon"></i>
|
<i *ngIf="updateAvailable" class="teal small circle icon"></i>
|
||||||
<i *ngIf="updateAvailable === null" class="small yellow exclamation triangle icon"></i>
|
<i *ngIf="updateAvailable === null" class="small yellow exclamation triangle icon"></i>
|
||||||
Settings
|
Settings
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
<button class="btn btn-square btn-ghost rounded-none cursor-default" (click)="toggleMaximized()">
|
<button class="btn btn-square btn-ghost rounded-none cursor-default" (click)="toggleMaximized()">
|
||||||
<i class="bi" [ngClass]="isMaximized ? 'bi-window-stack' : 'bi-window'"></i>
|
<i class="bi" [ngClass]="isMaximized ? 'bi-window-stack' : 'bi-window'"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-square btn-ghost rounded-none hover:bg-red-600/20 cursor-default" (click)="close()"><i class="bi bi-x-lg"></i></button>
|
<button class="btn btn-square btn-ghost rounded-none hover:bg-red-600/20 cursor-default" (click)="close()">
|
||||||
|
<i class="bi bi-x-lg"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { DOCUMENT } from '@angular/common'
|
||||||
|
import { Inject, Injectable } from '@angular/core'
|
||||||
|
|
||||||
import { Settings } from '../../../../src-shared/Settings'
|
import { Settings, themes } from '../../../../src-shared/Settings'
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class SettingsService {
|
export class SettingsService {
|
||||||
readonly builtinThemes = ['Default', 'Dark']
|
|
||||||
|
|
||||||
private settings: Settings
|
private settings: Settings
|
||||||
private currentThemeLink: HTMLLinkElement
|
|
||||||
|
constructor(
|
||||||
|
@Inject(DOCUMENT) private document: Document,
|
||||||
|
) { }
|
||||||
|
|
||||||
async loadSettings() {
|
async loadSettings() {
|
||||||
this.settings = await window.electron.invoke.getSettings()
|
this.settings = await window.electron.invoke.getSettings()
|
||||||
if (this.settings.theme !== this.builtinThemes[0]) {
|
if (!themes.includes(this.settings.theme)) {
|
||||||
|
this.changeTheme('dark')
|
||||||
|
} else {
|
||||||
this.changeTheme(this.settings.theme)
|
this.changeTheme(this.settings.theme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,15 +27,8 @@ export class SettingsService {
|
|||||||
window.electron.emit.setSettings(this.settings)
|
window.electron.emit.setSettings(this.settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
changeTheme(theme: string) {
|
changeTheme(theme: typeof themes[number]) {
|
||||||
if (this.currentThemeLink !== undefined) this.currentThemeLink.remove()
|
this.document.documentElement.setAttribute('data-theme', theme)
|
||||||
if (theme === 'Default') { return }
|
|
||||||
|
|
||||||
const link = document.createElement('link')
|
|
||||||
link.type = 'text/css'
|
|
||||||
link.rel = 'stylesheet'
|
|
||||||
link.href = `./assets/themes/${theme.toLowerCase()}.css`
|
|
||||||
this.currentThemeLink = document.head.appendChild(link)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Individual getters/setters
|
// Individual getters/setters
|
||||||
@@ -53,7 +51,7 @@ export class SettingsService {
|
|||||||
get theme() {
|
get theme() {
|
||||||
return this.settings.theme
|
return this.settings.theme
|
||||||
}
|
}
|
||||||
set theme(newValue: string) {
|
set theme(newValue: typeof themes[number]) {
|
||||||
this.settings.theme = newValue
|
this.settings.theme = newValue
|
||||||
this.changeTheme(newValue)
|
this.changeTheme(newValue)
|
||||||
this.saveSettings()
|
this.saveSettings()
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ async function loadWindow(retries = 0) {
|
|||||||
try {
|
try {
|
||||||
await mainWindow.loadURL(getLoadUrl())
|
await mainWindow.loadURL(getLoadUrl())
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('FAILED TO LOAD WINDOW #', retries)
|
await new Promise<void>(resolve => setTimeout(resolve, 1000))
|
||||||
await loadWindow(retries + 1)
|
await loadWindow(retries + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,25 @@
|
|||||||
|
export const themes = [
|
||||||
|
'business',
|
||||||
|
'dark',
|
||||||
|
'halloween',
|
||||||
|
'night',
|
||||||
|
'synthwave',
|
||||||
|
'aqua',
|
||||||
|
'emerald',
|
||||||
|
'lemonade',
|
||||||
|
'valentine',
|
||||||
|
'winter',
|
||||||
|
'aren',
|
||||||
|
'froogs',
|
||||||
|
] as const
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents Bridge's user settings.
|
* Represents Bridge's user settings.
|
||||||
*/
|
*/
|
||||||
export interface Settings {
|
export interface Settings {
|
||||||
rateLimitDelay: number // Number of seconds to wait between each file download from Google servers
|
rateLimitDelay: number // Number of seconds to wait between each file download from Google servers
|
||||||
downloadVideos: boolean // If background videos should be downloaded
|
downloadVideos: boolean // If background videos should be downloaded
|
||||||
theme: string // The name of the currently enabled UI theme
|
theme: typeof themes[number] // The name of the currently enabled UI theme
|
||||||
libraryPath: string | undefined // The path to the user's library
|
libraryPath: string | undefined // The path to the user's library
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,6 +29,6 @@ export interface Settings {
|
|||||||
export const defaultSettings: Settings = {
|
export const defaultSettings: Settings = {
|
||||||
rateLimitDelay: 31,
|
rateLimitDelay: 31,
|
||||||
downloadVideos: true,
|
downloadVideos: true,
|
||||||
theme: 'Default',
|
theme: 'dark',
|
||||||
libraryPath: undefined,
|
libraryPath: undefined,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user