Merge remote-tracking branch 'origin/main'

# Conflicts:
#	src/ui/App.tsx
This commit is contained in:
KingRainbow44
2022-06-02 19:48:32 -04:00
12 changed files with 156 additions and 51 deletions

View File

@@ -1,9 +1,11 @@
use crate::system_helpers::*;
#[tauri::command]
pub async fn get_lang(window: tauri::Window, lang: String) -> String {
let lang = lang.to_lowercase();
// Send contents of language file back
let contents = match std::fs::read_to_string(format!("./lang/{}.json", lang)) {
let contents = match std::fs::read_to_string(format!("{}/lang/{}.json", install_location(), lang)) {
Ok(x) => x,
Err(e) => {
emit_lang_err(window, format!("Failed to read language file: {}", e));
@@ -19,7 +21,7 @@ pub async fn get_languages() -> std::collections::HashMap<String, String> {
// for each lang file, set the key as the filename and the value as the lang_name contained in the file
let mut languages = std::collections::HashMap::new();
let mut lang_files = std::fs::read_dir("./lang").unwrap();
let mut lang_files = std::fs::read_dir(format!("{}/lang", install_location())).unwrap();
while let Some(entry) = lang_files.next() {
let entry = entry.unwrap();

View File

@@ -29,6 +29,12 @@ lazy_static! {
fn main() {
process_watcher();
// Make BG folder if it doesn't exist
let bg_folder = format!("{}/bg", system_helpers::install_location());
if !std::path::Path::new(&bg_folder).exists() {
std::fs::create_dir_all(&bg_folder).unwrap();
}
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
enable_process_watcher,
@@ -42,6 +48,7 @@ fn main() {
system_helpers::run_program,
system_helpers::run_jar,
system_helpers::open_in_browser,
system_helpers::copy_file,
proxy::set_proxy_addr,
proxy::generate_ca_files,
unzip::unzip,
@@ -50,7 +57,8 @@ fn main() {
downloader::download_file,
downloader::stop_download,
lang::get_lang,
lang::get_languages
lang::get_languages,
web::valid_url
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
@@ -136,7 +144,8 @@ async fn req_get(url: String) -> String {
}
#[tauri::command]
async fn get_bg_file(bg_path: String) -> String {
async fn get_bg_file(bg_path: String, appdata: String) -> String {
let copy_loc = appdata;
let query = web::query("https://api.grasscutters.xyz/cultivation/query").await;
let response_data: APIQuery = match serde_json::from_str(&query) {
Ok(data) => data,
@@ -149,9 +158,8 @@ async fn get_bg_file(bg_path: String) -> String {
let file_name = response_data.bg_file.to_string();
// First we see if the file already exists in our local bg folder.
if file_helpers::dir_exists(format!(".\\bg\\{}", file_name).as_str()) {
let cwd = std::env::current_dir().unwrap();
return format!("{}\\{}", cwd.display(), response_data.bg_file.as_str());
if file_helpers::dir_exists(format!("{}\\bg\\{}", copy_loc, file_name).as_str()) {
return format!("{}\\{}", copy_loc, response_data.bg_file.as_str());
}
// Now we check if the bg folder, which is one directory above the game_path, exists.
@@ -169,13 +177,12 @@ async fn get_bg_file(bg_path: String) -> String {
}
// The image exists, lets copy it to our local '\bg' folder.
let bg_img_path_local = format!(".\\bg\\{}", file_name.as_str());
let bg_img_path_local = format!("{}\\bg\\{}", copy_loc, file_name.as_str());
return match std::fs::copy(bg_img_path, bg_img_path_local) {
Ok(_) => {
// Copy was successful, lets return true.
let cwd = std::env::current_dir().unwrap();
format!("{}\\{}", cwd.display(), response_data.bg_file.as_str())
format!("{}\\{}", copy_loc, response_data.bg_file.as_str())
}
Err(e) => {
// Copy failed, lets return false

View File

@@ -4,6 +4,8 @@ use std::process::Command;
use tauri;
use open;
use crate::file_helpers;
#[tauri::command]
pub fn run_program(path: String) {
// Open the program from the specified path.
@@ -54,3 +56,32 @@ pub fn open_in_browser(url: String) {
Err(e) => println!("Failed to open URL: {}", e),
};
}
#[tauri::command]
pub fn copy_file(path: String, new_path: String) -> bool {
let filename = &path.split("/").last().unwrap();
let mut new_path_buf = std::path::PathBuf::from(&new_path);
// If the new path doesn't exist, create it.
if !file_helpers::dir_exists(new_path_buf.pop().to_string().as_str()) {
std::fs::create_dir_all(&new_path).unwrap();
}
// Copy old to new
match std::fs::copy(&path, format!("{}/{}", new_path, filename)) {
Ok(_) => true,
Err(e) => {
println!("Failed to copy file: {}", e);
false
}
}
}
pub fn install_location() -> String {
let mut exe_path = std::env::current_exe().unwrap();
// Get the path to the executable.
exe_path.pop();
return exe_path.to_str().unwrap().to_string();
}

View File

@@ -5,4 +5,14 @@ pub(crate) async fn query(site: &str) -> String {
let response = client.get(site).header(USER_AGENT, "cultivation").send().await.unwrap();
return response.text().await.unwrap();
}
#[tauri::command]
pub(crate) async fn valid_url(url: String) -> bool {
// Check if we get a 200 response
let client = reqwest::Client::new();
let response = client.get(url).header(USER_AGENT, "cultivation").send().await.unwrap();
return response.status().as_str() == "200";
}

View File

@@ -18,6 +18,15 @@
"$DATA/cultivation/*"
]
},
"protocol": {
"all": true,
"asset": true,
"assetScope": [
"$DATA",
"$DATA/cultivation",
"$DATA/cultivation/*"
]
},
"all": true
},
"bundle": {
@@ -54,7 +63,7 @@
}
},
"security": {
"csp": null
"csp": "default-src 'self'; img-src 'self' asset: https://asset.localhost"
},
"updater": {
"active": false

View File

@@ -27,11 +27,8 @@ select:focus {
}
.App {
background-repeat: no-repeat;
background-size: cover;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover !important;
background-position: center !important;
}
.TopButton {

View File

@@ -20,6 +20,7 @@ import { getConfigOption, setConfigOption } from '../utils/configuration'
import { invoke } from '@tauri-apps/api'
import { dataDir } from '@tauri-apps/api/path'
import { appWindow } from '@tauri-apps/api/window'
import { convertFileSrc } from '@tauri-apps/api/tauri'
interface IProps {
[key: string]: never;
@@ -34,6 +35,8 @@ interface IState {
bgFile: string;
}
const DEFAULT_BG = 'https://api.grasscutters.xyz/content/bgfile'
const downloadHandler = new DownloadHandler()
class App extends React.Component<IProps, IState> {
@@ -45,7 +48,7 @@ class App extends React.Component<IProps, IState> {
miniDownloadsOpen: false,
downloadsOpen: false,
gameDownloadsOpen: false,
bgFile: 'https://api.grasscutters.xyz/content/bgfile',
bgFile: DEFAULT_BG,
}
listen('lang_error', (payload) => {
@@ -76,23 +79,39 @@ class App extends React.Component<IProps, IState> {
const cert_generated = await getConfigOption('cert_generated')
const game_exe = await getConfigOption('game_install_path')
const custom_bg = await getConfigOption('customBackground')
const game_path = game_exe.substring(0, game_exe.lastIndexOf('\\'))
const root_path = game_path.substring(0, game_path.lastIndexOf('\\'))
const game_path = game_exe.substring(0, game_exe.replace(/\\/g, '/').lastIndexOf('/'))
const root_path = game_path.substring(0, game_path.replace(/\\/g, '/').lastIndexOf('/'))
if(!custom_bg) {
if(!custom_bg || !/png|jpg|jpeg$/.test(custom_bg)) {
if(game_path) {
// Get the bg by invoking, then set the background to that bg.
const bgLoc: string = await invoke('get_bg_file', {
bgPath: root_path
bgPath: root_path,
appdata: await dataDir()
})
bgLoc && this.setState({
bgFile: bgLoc
})
}, this.forceUpdate)
}
} else this.setState({
bgFile: custom_bg
})
} else {
const isUrl = /^(?:http(s)?:\/\/)/gm.test(custom_bg)
if (!isUrl) {
this.setState({
bgFile: convertFileSrc(custom_bg)
}, this.forceUpdate)
} else {
// Check if URL returns a valid image.
const isValid = await invoke('valid_url', {
url: custom_bg
})
this.setState({
bgFile: isValid ? custom_bg : DEFAULT_BG
}, this.forceUpdate)
}
}
if (!cert_generated) {
// Generate the certificate
@@ -109,15 +128,13 @@ class App extends React.Component<IProps, IState> {
isDownloading: downloadHandler.getDownloads().filter(d => d.status !== 'finished')?.length > 0
})
}, 1000)
console.log('mounting app component with background: ' + this.state.bgFile)
}
render() {
return (
<div className="App" style={
this.state.bgFile ? {
background: `url(${this.state.bgFile} fixed`,
background: `url("${this.state.bgFile}") fixed`,
} : {}
}>
<TopBar

View File

@@ -7,14 +7,14 @@
align-items: center;
justify-content: flex-start;
height: calc(100vh - 190px);
height: 100vh;
width: 80px;
right: 0%;
z-index: 99;
background-color: rgba(77, 77, 77, 0.6);
z-index: 99;
z-index: 999;
}
.BarImg:hover {

View File

@@ -107,7 +107,12 @@ export default class ServerLaunchSection extends React.Component<IProps, IState>
}
// Launch the program
await invoke('run_program', { path: config.game_install_path })
const gameExists = await invoke('dir_exists', {
path: config.game_install_path
})
if (gameExists) await invoke('run_program', { path: config.game_install_path })
else alert('Game not found! At: ' + config.game_install_path)
}
async launchServer() {

View File

@@ -30,12 +30,6 @@ export default class TextInput extends React.Component<IProps, IState> {
}
static getDerivedStateFromProps(props: IProps, state: IState) {
if (!props.readOnly) {
return {
value: state.value
}
}
return { value: props.value || '' }
}

View File

@@ -10,6 +10,7 @@ import './Downloads.css'
import Divider from './Divider'
import { getConfigOption, setConfigOption } from '../../../utils/configuration'
import { invoke } from '@tauri-apps/api'
import { listen } from '@tauri-apps/api/event'
const STABLE_REPO_DOWNLOAD = 'https://github.com/Grasscutters/Grasscutter/archive/refs/heads/stable.zip'
const DEV_REPO_DOWNLOAD = 'https://github.com/Grasscutters/Grasscutter/archive/refs/heads/development.zip'
@@ -48,12 +49,16 @@ export default class Downloads extends React.Component<IProps, IState> {
this.downloadGrasscutterStable = this.downloadGrasscutterStable.bind(this)
this.downloadGrasscutterLatest = this.downloadGrasscutterLatest.bind(this)
this.downloadResources = this.downloadResources.bind(this)
this.disableButtons = this.disableButtons.bind(this)
this.toggleButtons = this.toggleButtons.bind(this)
}
async componentDidMount() {
const gc_path = await getConfigOption('grasscutter_path')
listen('jar_extracted', () => {
this.setState({ grasscutter_set: true }, this.forceUpdate)
})
if (!gc_path || gc_path === '') {
this.setState({
grasscutter_set: false,
@@ -102,43 +107,43 @@ export default class Downloads extends React.Component<IProps, IState> {
async downloadGrasscutterStableRepo() {
const folder = await this.getGrasscutterFolder()
this.props.downloadManager.addDownload(STABLE_REPO_DOWNLOAD, folder + '\\grasscutter_repo.zip', () =>{
unzip(folder + '\\grasscutter_repo.zip', folder + '\\')
unzip(folder + '\\grasscutter_repo.zip', folder + '\\', this.toggleButtons)
})
this.disableButtons()
this.toggleButtons()
}
async downloadGrasscutterDevRepo() {
const folder = await this.getGrasscutterFolder()
this.props.downloadManager.addDownload(DEV_REPO_DOWNLOAD, folder + '\\grasscutter_repo.zip', () =>{
unzip(folder + '\\grasscutter_repo.zip', folder + '\\')
unzip(folder + '\\grasscutter_repo.zip', folder + '\\', this.toggleButtons)
})
this.disableButtons()
this.toggleButtons()
}
async downloadGrasscutterStable() {
const folder = await this.getGrasscutterFolder()
this.props.downloadManager.addDownload(STABLE_DOWNLOAD, folder + '\\grasscutter.zip', () =>{
unzip(folder + '\\grasscutter.zip', folder + '\\')
unzip(folder + '\\grasscutter.zip', folder + '\\', this.toggleButtons)
})
// Also add repo download
this.downloadGrasscutterStableRepo()
this.disableButtons()
this.toggleButtons()
}
async downloadGrasscutterLatest() {
const folder = await this.getGrasscutterFolder()
this.props.downloadManager.addDownload(DEV_DOWNLOAD, folder + '\\grasscutter.zip', () =>{
unzip(folder + '\\grasscutter.zip', folder + '\\')
unzip(folder + '\\grasscutter.zip', folder + '\\', this.toggleButtons)
})
// Also add repo download
this.downloadGrasscutterDevRepo()
this.disableButtons()
this.toggleButtons()
}
async downloadResources() {
@@ -150,18 +155,23 @@ export default class Downloads extends React.Component<IProps, IState> {
path: folder + '\\Resources',
newName: 'resources'
})
this.toggleButtons()
})
})
this.disableButtons()
this.toggleButtons()
}
disableButtons() {
async toggleButtons() {
const gc_path = await getConfigOption('grasscutter_path')
// Set states since we know we are downloading something if this is called
this.setState({
grasscutter_downloading: this.props.downloadManager.downloadingJar(),
resources_downloading: this.props.downloadManager.downloadingResources(),
repo_downloading: this.props.downloadManager.downloadingRepo()
repo_downloading: this.props.downloadManager.downloadingRepo(),
grasscutter_set: gc_path && gc_path !== '',
})
}

View File

@@ -6,6 +6,8 @@ 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'
interface IProps {
closeFn: () => void;
@@ -36,6 +38,7 @@ export default class Options extends React.Component<IProps, IState> {
}
this.toggleGrasscutterWithGame = this.toggleGrasscutterWithGame.bind(this)
this.setCustomBackground = this.setCustomBackground.bind(this)
}
async componentDidMount() {
@@ -80,8 +83,28 @@ export default class Options extends React.Component<IProps, IState> {
})
}
setCustomBackground(value: string) {
setConfigOption('customBackground', value)
async setCustomBackground(value: string) {
const isUrl = /^(?:http(s)?:\/\/)/gm.test(value)
if (!value) return await setConfigOption('customBackground', '')
if (!isUrl) {
const filename = value.replace(/\\/g, '/').split('/').pop()
const localBgPath = (await dataDir() as string).replace(/\\/g, '/')
await setConfigOption('customBackground', `${localBgPath}/cultivation/bg/${filename}`)
// Copy the file over to the local directory
await invoke('copy_file', {
path: value.replace(/\\/g, '/'),
newPath: `${localBgPath}cultivation/bg/`
})
window.location.reload()
} else {
await setConfigOption('customBackground', value)
window.location.reload()
}
}
render() {