working theming

This commit is contained in:
SpikeHD
2022-06-02 19:03:32 -07:00
parent e3aade7955
commit 8d8b617198
7 changed files with 144 additions and 16 deletions

View File

@@ -16,8 +16,9 @@
"grasscutter_jar": "Set Grasscutter JAR",
"java_path": "Set Custom Java Path",
"grasscutter_with_game": "Automatically launch Grasscutter with game",
"language": "Select Language (requires restart)",
"background": "Set Custom Background (link or image file)"
"language": "Select Language",
"background": "Set Custom Background (link or image file)",
"theme": "Set Theme"
},
"downloads": {
"grasscutter_stable_data": "Download Grasscutter Stable Data",

View File

@@ -50,6 +50,7 @@ fn main() {
system_helpers::run_jar,
system_helpers::open_in_browser,
system_helpers::copy_file,
system_helpers::install_location,
proxy::set_proxy_addr,
proxy::generate_ca_files,
unzip::unzip,
@@ -145,8 +146,8 @@ async fn req_get(url: String) -> String {
}
#[tauri::command]
async fn get_theme_list() -> Vec<HashMap<String, String>> {
let theme_loc = format!("{}/themes", system_helpers::install_location());
async fn get_theme_list(dataDir: String) -> Vec<HashMap<String, String>> {
let theme_loc = format!("{}/themes", dataDir);
// Ensure folder exists
if !std::path::Path::new(&theme_loc).exists() {

View File

@@ -77,6 +77,7 @@ pub fn copy_file(path: String, new_path: String) -> bool {
}
}
#[tauri::command]
pub fn install_location() -> String {
let mut exe_path = std::env::current_exe().unwrap();

View File

@@ -18,9 +18,10 @@ import Game from './components/menu/Game'
import RightBar from './components/RightBar'
import { getConfigOption, setConfigOption } from '../utils/configuration'
import { invoke } from '@tauri-apps/api'
import { dataDir } from '@tauri-apps/api/path'
import { appDir, dataDir } from '@tauri-apps/api/path'
import { appWindow } from '@tauri-apps/api/window'
import { convertFileSrc } from '@tauri-apps/api/tauri'
import { getTheme, loadTheme } from '../utils/themes'
interface IProps {
[key: string]: never;
@@ -82,6 +83,13 @@ class App extends React.Component<IProps, IState> {
const game_path = game_exe.substring(0, game_exe.replace(/\\/g, '/').lastIndexOf('/'))
const root_path = game_path.substring(0, game_path.replace(/\\/g, '/').lastIndexOf('/'))
// Load a theme if it exists
const theme = await getConfigOption('theme')
if (theme) {
const themeObj = await getTheme(theme)
loadTheme(themeObj, document)
}
if(!custom_bg || !/png|jpg|jpeg$/.test(custom_bg)) {
if(game_path) {
// Get the bg by invoking, then set the background to that bg.

View File

@@ -1,13 +1,15 @@
import React from 'react'
import { invoke } from '@tauri-apps/api'
import { dataDir } from '@tauri-apps/api/path'
import DirInput from '../common/DirInput'
import Menu from './Menu'
import Tr, { getLanguages } from '../../../utils/language'
import './Options.css'
import { setConfigOption, getConfig, getConfigOption } from '../../../utils/configuration'
import Checkbox from '../common/Checkbox'
import Divider from './Divider'
import { invoke } from '@tauri-apps/api'
import { dataDir } from '@tauri-apps/api/path'
import { getThemeList } from '../../../utils/themes'
import './Options.css'
interface IProps {
closeFn: () => void;
@@ -21,6 +23,8 @@ interface IState {
language_options: { [key: string]: string }[],
current_language: string
bg_url_or_path: string
themes: string[]
theme: string
}
export default class Options extends React.Component<IProps, IState> {
@@ -34,7 +38,9 @@ export default class Options extends React.Component<IProps, IState> {
grasscutter_with_game: false,
language_options: [],
current_language: 'en',
bg_url_or_path: ''
bg_url_or_path: '',
themes: ['default'],
theme: ''
}
this.toggleGrasscutterWithGame = this.toggleGrasscutterWithGame.bind(this)
@@ -52,7 +58,9 @@ export default class Options extends React.Component<IProps, IState> {
grasscutter_with_game: config.grasscutter_with_game || false,
language_options: languages,
current_language: config.language || 'en',
bg_url_or_path: config.customBackground || ''
bg_url_or_path: config.customBackground || '',
themes: (await getThemeList()).map(t => t.name),
theme: config.theme || 'default'
})
this.forceUpdate()
@@ -70,8 +78,14 @@ export default class Options extends React.Component<IProps, IState> {
setConfigOption('java_path', value)
}
setLanguage(value: string) {
setConfigOption('language', value)
async setLanguage(value: string) {
await setConfigOption('language', value)
window.location.reload()
}
async setTheme(value: string) {
await setConfigOption('theme', value)
window.location.reload()
}
async toggleGrasscutterWithGame() {
@@ -140,6 +154,28 @@ export default class Options extends React.Component<IProps, IState> {
<Divider />
<div className='OptionSection'>
<div className='OptionLabel'>
<Tr text="options.theme" />
</div>
<div className='OptionValue'>
<select value={this.state.theme} onChange={(event) => {
this.setTheme(event.target.value)
}}>
{this.state.themes.map(t => (
<option
key={t}
value={t}>
{t}
</option>
))}
</select>
</div>
</div>
<Divider />
<div className='OptionSection'>
<div className='OptionLabel'>
<Tr text="options.java_path" />

View File

@@ -18,6 +18,7 @@ let defaultConfig: Configuration
language: 'en',
customBackground: '',
cert_generated: false,
theme: 'default'
}
})()
@@ -37,6 +38,7 @@ export interface Configuration {
language: string
customBackground: string
cert_generated: boolean
theme: string;
}
export async function setConfigOption(key: string, value: any): Promise<void> {

View File

@@ -1,4 +1,6 @@
import { invoke } from '@tauri-apps/api'
import { dataDir } from '@tauri-apps/api/path'
import { convertFileSrc } from '@tauri-apps/api/tauri'
interface Theme {
name: string
@@ -24,10 +26,34 @@ interface ThemeList extends Theme {
path: string
}
const defaultTheme = {
name: 'default',
version: '1.0.0',
description: 'Default theme',
includes: {
css: [],
js: []
},
path: 'default'
}
export async function getThemeList() {
// Do some invoke to backend to get the theme list
const themes = await invoke('get_theme_list') as BackendThemeList[]
const list: ThemeList[] = []
const themes = await invoke('get_theme_list', {
dataDir: `${await dataDir()}/cultivation`
}) as BackendThemeList[]
const list: ThemeList[] = [
// ALWAYS include default theme
{
name: 'default',
version: '1.0.0',
description: 'Default theme',
includes: {
css: [],
js: []
},
path: 'default'
}
]
themes.forEach(t => {
let obj
@@ -44,6 +70,59 @@ export async function getThemeList() {
return list
}
export async function loadTheme(theme: string) {
// Do some invoke to backend to load the theme
export async function getTheme(name: string) {
const themes = await getThemeList()
return themes.find(t => t.name === name) || defaultTheme
}
export async function loadTheme(theme: ThemeList, document: Document) {
// We are going to dynamically load stylesheets into the document
const head = document.head
// Get all CSS includes
const cssIncludes = theme.includes.css
const jsIncludes = theme.includes.js
// Load CSS files
cssIncludes.forEach(css => {
if (!css) return
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = convertFileSrc(theme.path + '/' + css)
head.appendChild(link)
})
// Load JS files
jsIncludes.forEach(js => {
if (!js) return
const script = document.createElement('script')
script.src = convertFileSrc(theme.path + '/' + js)
head.appendChild(script)
})
// Set custom background
if (theme.customBackgroundURL) {
document.body.style.backgroundImage = `url('${theme.customBackgroundURL}')`
}
// Set custom background
if (theme.customBackgroundPath) {
const bgPath = await dataDir() + 'cultivation/grasscutter/theme.png'
// Save the background to our data dir
await invoke('copy_file', {
path: theme.path + '/' + theme.customBackgroundPath,
new_path: bgPath
})
// Set the background
document.body.style.backgroundImage = `url('${bgPath}')`
}
return
}