mirror of
https://github.com/Grasscutters/Cultivation.git
synced 2025-12-14 16:14:48 +01:00
show installed mods
This commit is contained in:
@@ -9,8 +9,8 @@ static API_URL: &str = "https://api.gamebanana.com";
|
|||||||
static SITE_URL: &str = "https://gamebanana.com";
|
static SITE_URL: &str = "https://gamebanana.com";
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_download_links(modId: String) -> String {
|
pub async fn get_download_links(mod_id: String) -> String {
|
||||||
let res = web::query(format!("{}/apiv9/Mod/{}/DownloadPage", SITE_URL, modId).as_str()).await;
|
let res = web::query(format!("{}/apiv9/Mod/{}/DownloadPage", SITE_URL, mod_id).as_str()).await;
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ pub async fn list_mods(path: String) -> HashMap<String, String> {
|
|||||||
mod_info_strings.insert(
|
mod_info_strings.insert(
|
||||||
path.to_str().unwrap().to_string(),
|
path.to_str().unwrap().to_string(),
|
||||||
format!(
|
format!(
|
||||||
"{{ name: \"{}\" }}",
|
"{{ \"name\": \"{}\" }}",
|
||||||
path.file_name().unwrap().to_str().unwrap()
|
path.file_name().unwrap().to_str().unwrap()
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { getInstalledMods, getMods, ModData } from '../../../utils/gamebanana'
|
import { getInstalledMods, getMods, ModData, PartialModData } from '../../../utils/gamebanana'
|
||||||
import { LoadingCircle } from './LoadingCircle'
|
import { LoadingCircle } from './LoadingCircle'
|
||||||
|
|
||||||
import './ModList.css'
|
import './ModList.css'
|
||||||
@@ -15,7 +15,7 @@ interface IState {
|
|||||||
installedList:
|
installedList:
|
||||||
| {
|
| {
|
||||||
path: string
|
path: string
|
||||||
info: unknown
|
info: ModData | PartialModData
|
||||||
}[]
|
}[]
|
||||||
| null
|
| null
|
||||||
}
|
}
|
||||||
@@ -34,9 +34,23 @@ export class ModList extends React.Component<IProps, IState> {
|
|||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
if (this.props.mode === 'installed') {
|
if (this.props.mode === 'installed') {
|
||||||
const installedMods = await getInstalledMods()
|
const installedMods = (await getInstalledMods()).map((mod) => {
|
||||||
|
// Check if it's a partial mod, and if so, fill in some pseudo-data
|
||||||
|
if (!('id' in mod.info)) {
|
||||||
|
const newInfo = mod.info as PartialModData
|
||||||
|
|
||||||
console.log(installedMods)
|
newInfo.images = []
|
||||||
|
newInfo.submitter = { name: 'Unknown' }
|
||||||
|
newInfo.likes = 0
|
||||||
|
newInfo.views = 0
|
||||||
|
|
||||||
|
mod.info = newInfo
|
||||||
|
|
||||||
|
return mod
|
||||||
|
}
|
||||||
|
|
||||||
|
return mod
|
||||||
|
})
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
installedList: installedMods,
|
installedList: installedMods,
|
||||||
@@ -63,7 +77,9 @@ export class ModList extends React.Component<IProps, IState> {
|
|||||||
(this.state.installedList && this.props.mode === 'installed') ? (
|
(this.state.installedList && this.props.mode === 'installed') ? (
|
||||||
<div className="ModListInner">
|
<div className="ModListInner">
|
||||||
{this.props.mode === 'installed'
|
{this.props.mode === 'installed'
|
||||||
? this.state.installedList?.map((mod) => <></>)
|
? this.state.installedList?.map((mod) => (
|
||||||
|
<ModTile path={mod.path} mod={mod.info} key={mod.info.name} onClick={this.downloadMod} />
|
||||||
|
))
|
||||||
: this.state.modList?.map((mod: ModData) => (
|
: this.state.modList?.map((mod: ModData) => (
|
||||||
<ModTile mod={mod} key={mod.id} onClick={this.downloadMod} />
|
<ModTile mod={mod} key={mod.id} onClick={this.downloadMod} />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
padding: 0 0 0 10px;
|
padding: 0 0 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ModTileOpen,
|
||||||
.ModTileDownload {
|
.ModTileDownload {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ModData } from '../../../utils/gamebanana'
|
import { ModData, PartialModData } from '../../../utils/gamebanana'
|
||||||
|
|
||||||
import './ModTile.css'
|
import './ModTile.css'
|
||||||
import Like from '../../../resources/icons/like.svg'
|
import Like from '../../../resources/icons/like.svg'
|
||||||
import Eye from '../../../resources/icons/eye.svg'
|
import Eye from '../../../resources/icons/eye.svg'
|
||||||
import Download from '../../../resources/icons/download.svg'
|
import Download from '../../../resources/icons/download.svg'
|
||||||
|
import Folder from '../../../resources/icons/folder.svg'
|
||||||
|
import { shell } from '@tauri-apps/api'
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
mod: ModData
|
mod: ModData | PartialModData
|
||||||
|
path?: string
|
||||||
onClick: (mod: ModData) => void
|
onClick: (mod: ModData) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +27,10 @@ export class ModTile extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async openInExplorer() {
|
||||||
|
if (this.props.path) shell.open(this.props.path)
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { mod } = this.props
|
const { mod } = this.props
|
||||||
|
|
||||||
@@ -32,13 +39,26 @@ export class ModTile extends React.Component<IProps, IState> {
|
|||||||
className="ModListItem"
|
className="ModListItem"
|
||||||
onMouseEnter={() => this.setState({ hover: true })}
|
onMouseEnter={() => this.setState({ hover: true })}
|
||||||
onMouseLeave={() => this.setState({ hover: false })}
|
onMouseLeave={() => this.setState({ hover: false })}
|
||||||
onClick={() => this.props.onClick(mod)}
|
onClick={() => {
|
||||||
|
// Disable downloading installed mods
|
||||||
|
if (!('id' in mod)) return this.openInExplorer()
|
||||||
|
|
||||||
|
this.props.onClick(mod)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<span className="ModName">{mod.name}</span>
|
<span className="ModName">{mod.name}</span>
|
||||||
<span className="ModAuthor">{mod.submitter.name}</span>
|
<span className="ModAuthor">{mod.submitter.name}</span>
|
||||||
<div className="ModImage">
|
<div className="ModImage">
|
||||||
{this.state.hover && <img src={Download} className="ModTileDownload" alt="Download" />}
|
{this.state.hover &&
|
||||||
<img src={mod.images[0]} className={`${mod.nsfw ? 'nsfw' : ''} ${this.state.hover ? 'blur' : ''}`} />
|
(!this.props.path ? (
|
||||||
|
<img src={Download} className="ModTileDownload" alt="Download" />
|
||||||
|
) : (
|
||||||
|
<img src={Folder} className="ModTileOpen" alt="Open" />
|
||||||
|
))}
|
||||||
|
<img
|
||||||
|
src={mod.images[0]}
|
||||||
|
className={`${'id' in mod && mod.nsfw ? 'nsfw' : ''} ${this.state.hover ? 'blur' : ''}`}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ModInner">
|
<div className="ModInner">
|
||||||
<div className="likes">
|
<div className="likes">
|
||||||
|
|||||||
@@ -78,6 +78,16 @@ export interface ModData {
|
|||||||
type: string
|
type: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PartialModData {
|
||||||
|
name: string
|
||||||
|
images: string[]
|
||||||
|
submitter: {
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
likes: number
|
||||||
|
views: number
|
||||||
|
}
|
||||||
|
|
||||||
interface GamebananaDownloads {
|
interface GamebananaDownloads {
|
||||||
_bIsTrashed: boolean
|
_bIsTrashed: boolean
|
||||||
_bIsWithheld: boolean
|
_bIsWithheld: boolean
|
||||||
@@ -157,9 +167,11 @@ export async function getInstalledMods() {
|
|||||||
|
|
||||||
// These are returned as JSON strings, so we have to parse them
|
// These are returned as JSON strings, so we have to parse them
|
||||||
return Object.keys(mods).map((path) => {
|
return Object.keys(mods).map((path) => {
|
||||||
|
const info = JSON.parse(mods[path]) as ModData | PartialModData
|
||||||
|
|
||||||
return {
|
return {
|
||||||
path,
|
path,
|
||||||
info: JSON.parse(mods[path]),
|
info,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user