feat: Add fetching package body
This commit is contained in:
parent
c991319463
commit
e458108923
12 changed files with 184 additions and 88 deletions
|
|
@ -67,6 +67,7 @@ macro_rules! collect_commands {
|
|||
get_provider_package_version,
|
||||
search_provider_packages,
|
||||
get_provider_authors,
|
||||
get_package_body,
|
||||
download_provider_package,
|
||||
// Cluster Packages
|
||||
get_cluster_package,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use onelauncher::cluster::content::package;
|
|||
use onelauncher::data::{Loader, ManagedPackage, ManagedUser, ManagedVersion, PackageType};
|
||||
use onelauncher::package::content::Providers;
|
||||
use onelauncher::package::import::{default_launcher_path, ImportType};
|
||||
use onelauncher::store::{Author, ClusterPath, Package, PackagePath, ProviderSearchResults};
|
||||
use onelauncher::store::{Author, ClusterPath, Package, PackageBody, PackagePath, ProviderSearchResults};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[specta::specta]
|
||||
|
|
@ -51,7 +51,7 @@ pub async fn get_all_provider_package_versions(
|
|||
loaders: Option<Vec<Loader>>,
|
||||
) -> Result<Vec<ManagedVersion>, String> {
|
||||
Ok(provider
|
||||
.get_all_versions(&project_id, game_versions, loaders)
|
||||
.get_all_versions(&project_id, game_versions, loaders, None, None) // TODO
|
||||
.await?)
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ pub async fn get_provider_package_versions(
|
|||
provider: Providers,
|
||||
versions: Vec<String>,
|
||||
) -> Result<Vec<ManagedVersion>, String> {
|
||||
Ok(provider.get_versions(versions).await?)
|
||||
Ok(provider.get_versions("", versions).await?) // TODO
|
||||
}
|
||||
|
||||
#[specta::specta]
|
||||
|
|
@ -70,7 +70,7 @@ pub async fn get_provider_package_version(
|
|||
provider: Providers,
|
||||
version: String,
|
||||
) -> Result<ManagedVersion, String> {
|
||||
Ok(provider.get_version(&version).await?)
|
||||
Ok(provider.get_version("", &version).await?) // TODO
|
||||
}
|
||||
|
||||
#[derive(specta::Type, serde::Deserialize, serde::Serialize)]
|
||||
|
|
@ -114,6 +114,15 @@ pub async fn get_provider_authors(
|
|||
Ok(provider.get_authors(&author).await?)
|
||||
}
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn get_package_body(
|
||||
provider: Providers,
|
||||
body: PackageBody
|
||||
) -> Result<String, String> {
|
||||
Ok(provider.get_package_body(&body).await?)
|
||||
}
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn download_provider_package(
|
||||
|
|
|
|||
|
|
@ -165,10 +165,12 @@ function PackageItem(props: SearchResult & { provider: Providers; row?: boolean
|
|||
{abbreviateNumber(props.downloads)}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<HeartIcon class="h-4 w-4" />
|
||||
{abbreviateNumber(props.follows)}
|
||||
</div>
|
||||
<Show when={props.follows > 0}>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<HeartIcon class="h-4 w-4" />
|
||||
{abbreviateNumber(props.follows)}
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { Cluster, ManagedPackage, ManagedUser, ManagedVersion, Providers } from '@onelauncher/client/bindings';
|
||||
import type { Cluster, ManagedPackage, ManagedVersion, Providers } from '@onelauncher/client/bindings';
|
||||
import { A, type Params, Route, useSearchParams } from '@solidjs/router';
|
||||
import { CalendarIcon, ChevronDownIcon, ClockRewindIcon, Download01Icon, File02Icon, HeartIcon, LinkExternal01Icon } from '@untitled-theme/icons-solid';
|
||||
import SteveHead from '~assets/images/steve.png';
|
||||
|
|
@ -15,7 +15,7 @@ import useCommand from '~ui/hooks/useCommand';
|
|||
import usePagination from '~ui/hooks/usePagination';
|
||||
import usePromptOpener from '~ui/hooks/usePromptOpener';
|
||||
import { abbreviateNumber, formatAsRelative } from '~utils';
|
||||
import { createContext, createEffect, createSignal, For, Match, on, type ParentProps, Show, Switch, useContext } from 'solid-js';
|
||||
import { type Accessor, createContext, createEffect, createSignal, For, Match, on, type ParentProps, type Resource, Show, Switch, useContext } from 'solid-js';
|
||||
import { getLicenseUrl, getPackageUrl, upperFirst } from '../../../utils';
|
||||
|
||||
interface BrowserModParams extends Params {
|
||||
|
|
@ -23,14 +23,25 @@ interface BrowserModParams extends Params {
|
|||
provider: Providers;
|
||||
}
|
||||
|
||||
const BrowserPackageContext = createContext<ManagedPackage | null>(null);
|
||||
interface BrowserPackageContextType {
|
||||
pkg: Accessor<ManagedPackage>;
|
||||
body: Resource<string>;
|
||||
};
|
||||
|
||||
const BrowserPackageContext = createContext<BrowserPackageContextType | null>(null);
|
||||
|
||||
const basePath = '/browser/package';
|
||||
|
||||
function BrowserPackageProvider(props: ParentProps & { pkg: ManagedPackage }) {
|
||||
const [body] = useCommand(() => bridge.commands.getPackageBody(props.pkg.provider, props.pkg.body));
|
||||
|
||||
const ctx: BrowserPackageContextType = {
|
||||
pkg: () => props.pkg,
|
||||
body,
|
||||
};
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line solid/reactivity -- Should be fine
|
||||
<BrowserPackageContext.Provider value={props.pkg}>
|
||||
<BrowserPackageContext.Provider value={ctx}>
|
||||
{props.children}
|
||||
</BrowserPackageContext.Provider>
|
||||
);
|
||||
|
|
@ -67,7 +78,6 @@ function NavLink(props: ParentProps & { href: string }) {
|
|||
function BrowserPackage(props: ParentProps) {
|
||||
const [params] = useSearchParams<BrowserModParams>();
|
||||
const [pkg] = useCommand(() => bridge.commands.getProviderPackage(params.provider!, params.id!));
|
||||
const [authors] = useCommand(pkg, () => bridge.commands.getProviderAuthors(pkg()!.provider, pkg()!.author));
|
||||
|
||||
const links = [
|
||||
['About', '/'],
|
||||
|
|
@ -81,7 +91,7 @@ function BrowserPackage(props: ParentProps) {
|
|||
<Show
|
||||
children={(
|
||||
<>
|
||||
<BrowserSidebar authors={authors()!} package={pkg()!} />
|
||||
<BrowserSidebar package={pkg()!} />
|
||||
|
||||
<div class="min-h-full flex flex-1 flex-col items-start gap-y-4 pb-8">
|
||||
<div class="flex flex-none flex-row gap-x-1 rounded-lg bg-component-bg p-1">
|
||||
|
|
@ -108,7 +118,7 @@ function BrowserPackage(props: ParentProps) {
|
|||
</div>
|
||||
</>
|
||||
)}
|
||||
when={pkg() !== undefined && authors() !== undefined}
|
||||
when={pkg() !== undefined}
|
||||
/>
|
||||
</div>
|
||||
</Spinner.Suspense>
|
||||
|
|
@ -123,7 +133,8 @@ BrowserPackage.Routes = BrowserPackageRoutes;
|
|||
|
||||
export default BrowserPackage;
|
||||
|
||||
function BrowserSidebar(props: { package: ManagedPackage; authors: ManagedUser[] }) {
|
||||
function BrowserSidebar(props: { package: ManagedPackage }) {
|
||||
const [authors] = useCommand(() => props.package, () => bridge.commands.getProviderAuthors(props.package.provider, props.package.author));
|
||||
const createdAt = () => new Date(props.package.created);
|
||||
const updatedAt = () => new Date(props.package.updated);
|
||||
const promptOpen = usePromptOpener();
|
||||
|
|
@ -158,10 +169,12 @@ function BrowserSidebar(props: { package: ManagedPackage; authors: ManagedUser[]
|
|||
{abbreviateNumber(props.package.downloads)}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<HeartIcon class="h-4 w-4" />
|
||||
{abbreviateNumber(props.package.followers)}
|
||||
</div>
|
||||
<Show when={props.package.followers > 0}>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<HeartIcon class="h-4 w-4" />
|
||||
{abbreviateNumber(props.package.followers)}
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -170,7 +183,7 @@ function BrowserSidebar(props: { package: ManagedPackage; authors: ManagedUser[]
|
|||
|
||||
<div class="flex flex-col gap-2 rounded-lg bg-component-bg p-3">
|
||||
<h4 class="text-fg-primary font-bold">Links</h4>
|
||||
<Link href={getPackageUrl(props.package.provider, props.package.id, props.package.package_type)} includeIcon>
|
||||
<Link href={getPackageUrl(props.package)} includeIcon>
|
||||
{props.package.provider}
|
||||
{' '}
|
||||
Page
|
||||
|
|
@ -179,14 +192,14 @@ function BrowserSidebar(props: { package: ManagedPackage; authors: ManagedUser[]
|
|||
|
||||
<div class="flex flex-col gap-2 rounded-lg bg-component-bg p-3">
|
||||
<h4 class="text-fg-primary font-bold">Authors</h4>
|
||||
<For each={props.authors}>
|
||||
<For each={authors()}>
|
||||
{author => (
|
||||
<>
|
||||
<div
|
||||
class="flex flex-row items-center gap-x-1 rounded-md p-1 active:bg-component-bg-pressed hover:bg-component-bg-hover"
|
||||
onClick={() => promptOpen(author.url)}
|
||||
>
|
||||
<img alt={`${author.username}'s avatar`} class="h-8 min-h-8 min-w-8 w-8 rounded-md" src={author.avatar_url || SteveHead} />
|
||||
<img alt={`${author.username}'s avatar`} class="h-8 min-h-8 min-w-8 w-8 rounded-[5px]" src={author.avatar_url || SteveHead} />
|
||||
<div class="flex flex-1 flex-col justify-center gap-y-1">
|
||||
<span>{author.username}</span>
|
||||
|
||||
|
|
@ -200,7 +213,7 @@ function BrowserSidebar(props: { package: ManagedPackage; authors: ManagedUser[]
|
|||
</div>
|
||||
<LinkExternal01Icon class="h-4 w-4" />
|
||||
</div>
|
||||
<Show when={author.is_organization_user === true && props.authors.length > 1}>
|
||||
<Show when={author.is_organization_user === true && ((authors()?.length || 0) > 1)}>
|
||||
<div class="h-px w-full bg-gray-05" />
|
||||
</Show>
|
||||
</>
|
||||
|
|
@ -346,7 +359,7 @@ function BrowserPackageBody() {
|
|||
|
||||
return (
|
||||
<div class="w-full flex-1 rounded-lg bg-component-bg p-4 px-6">
|
||||
<Markdown body={context?.body || ''} />
|
||||
<Markdown body={context?.body?.() || ''} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -371,7 +384,7 @@ function BrowserPackageVersions() {
|
|||
const MAX_ITEMS_PER_PAGE = 20;
|
||||
|
||||
const { page, Navigation } = usePagination({
|
||||
itemsCount: () => context?.versions.length || 0,
|
||||
itemsCount: () => context?.pkg().versions.length || 0,
|
||||
itemsPerPage: () => MAX_ITEMS_PER_PAGE,
|
||||
});
|
||||
|
||||
|
|
@ -379,7 +392,7 @@ function BrowserPackageVersions() {
|
|||
if (context === null)
|
||||
return [];
|
||||
|
||||
const newestToOldest = context.versions.toReversed();
|
||||
const newestToOldest = context.pkg().versions.toReversed();
|
||||
const start = (page - 1) * MAX_ITEMS_PER_PAGE;
|
||||
const end = start + MAX_ITEMS_PER_PAGE;
|
||||
|
||||
|
|
@ -392,7 +405,7 @@ function BrowserPackageVersions() {
|
|||
|
||||
const list = getVersionsForPage(page());
|
||||
|
||||
return await bridge.commands.getProviderPackageVersions(context.provider, list);
|
||||
return await bridge.commands.getProviderPackageVersions(context.pkg().provider, list);
|
||||
});
|
||||
|
||||
let container!: HTMLDivElement;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Cluster, ImportType, License, Loader, ManagedPackage, PackageType, Providers, VersionType } from '@onelauncher/client/bindings';
|
||||
import { DurationFormat } from '@formatjs/intl-durationformat';
|
||||
import { open } from '@tauri-apps/plugin-shell';
|
||||
import type { Cluster, ImportType, License, Loader, PackageType, Providers, VersionType } from '@onelauncher/client/bindings';
|
||||
|
||||
export function setAsyncTimeout(ms: number): Promise<void>;
|
||||
export function setAsyncTimeout(callback: () => void, ms: number): Promise<void>;
|
||||
|
|
@ -160,13 +160,23 @@ export function getLicenseUrl(licenseId: string | License | null | undefined): s
|
|||
return `https://spdx.org/licenses/${id}.html`;
|
||||
}
|
||||
|
||||
export function getPackageUrl(provider: Providers, id: string, package_type: PackageType = 'mod'): string {
|
||||
const mapping: Record<Providers, string> = {
|
||||
Modrinth: `https://modrinth.com/${package_type}/${id}`,
|
||||
Curseforge: `https://www.curseforge.com/minecraft/${package_type}/${id}`,
|
||||
export function getPackageUrl(pkg: ManagedPackage): string {
|
||||
const mapping: Record<Providers, () => string> = {
|
||||
Modrinth: () => `https://modrinth.com/${pkg.package_type}/${pkg.id}`,
|
||||
Curseforge: () => {
|
||||
const packageTypeMapping: Record<PackageType, string> = {
|
||||
mod: 'mc-mods',
|
||||
shaderpack: 'shaders',
|
||||
resourcepack: 'texture-packs',
|
||||
datapack: 'data-packs',
|
||||
modpack: 'modpacks',
|
||||
};
|
||||
|
||||
return `https://www.curseforge.com/minecraft/${packageTypeMapping[pkg.package_type]}/${pkg.main}`;
|
||||
},
|
||||
};
|
||||
|
||||
return mapping[provider];
|
||||
return mapping[pkg.provider]();
|
||||
}
|
||||
|
||||
export const LOADERS: Loader[] = ['vanilla', 'fabric', 'forge', 'neoforge', 'quilt'] as const;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ pub async fn find_managed_version(
|
|||
&package.id,
|
||||
game_version.as_ref().map(|v| vec![v.to_owned()]).clone(),
|
||||
loader.map(|l| vec![l]).clone(),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
|
|||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
use url::Url;
|
||||
|
||||
use crate::{data::{Loader, ManagedPackage, PackageType}, store::{ProviderSearchResults, SearchResult}, utils::http, Result, State};
|
||||
use crate::{data::{Loader, ManagedPackage, ManagedUser, ManagedVersion, PackageType}, store::{ProviderSearchResults, SearchResult}, utils::http, Result, State};
|
||||
|
||||
/// Mapping of Curseforge "classes" to their respective category ids
|
||||
#[derive(Debug, Default, Serialize_repr, Deserialize_repr)]
|
||||
|
|
@ -121,23 +121,33 @@ impl From<CurseforgePackage> for ManagedPackage {
|
|||
provider: super::Providers::Curseforge,
|
||||
package_type: package.package_type.into(),
|
||||
description: package.summary,
|
||||
body: "".to_string(), // TODO: Description is a new HTTP request
|
||||
main: todo!(),
|
||||
versions: todo!(),
|
||||
game_versions: todo!(),
|
||||
loaders: todo!(),
|
||||
icon_url: todo!(),
|
||||
created: todo!(),
|
||||
updated: todo!(),
|
||||
client: todo!(),
|
||||
server: todo!(),
|
||||
downloads: todo!(),
|
||||
followers: todo!(),
|
||||
categories: todo!(),
|
||||
optional_categories: todo!(),
|
||||
license: todo!(),
|
||||
author: todo!(),
|
||||
is_archived: todo!(),
|
||||
body: crate::store::PackageBody::Url(format!("/v1/mods/{}/description", package.id)),
|
||||
main: package.slug,
|
||||
versions: vec![],
|
||||
game_versions: vec![],
|
||||
loaders: vec![],
|
||||
icon_url: Some(package.logo.url),
|
||||
created: package.date_created,
|
||||
updated: package.date_modified,
|
||||
client: crate::store::PackageSide::Unknown,
|
||||
server: crate::store::PackageSide::Unknown,
|
||||
downloads: package.download_count,
|
||||
followers: package.rating.unwrap_or(0.0) as u32,
|
||||
categories: vec![], // TODO
|
||||
optional_categories: None,
|
||||
license: None,
|
||||
author: crate::store::Author::Users(
|
||||
package.authors.into_iter().map(|a| ManagedUser {
|
||||
id: a.id.to_string(),
|
||||
username: a.name,
|
||||
url: Some(a.url),
|
||||
is_organization_user: false,
|
||||
avatar_url: None,
|
||||
bio: None,
|
||||
role: None,
|
||||
}).collect()
|
||||
),
|
||||
is_archived: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -220,7 +230,7 @@ pub struct Screenshot {
|
|||
|
||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LatestFile {
|
||||
pub struct ModFile {
|
||||
pub id: u32,
|
||||
pub game_id: u32,
|
||||
pub mod_id: u32,
|
||||
|
|
@ -282,19 +292,7 @@ pub struct Module {
|
|||
|
||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LatestFilesIndex {
|
||||
pub game_version: String,
|
||||
pub file_id: u32,
|
||||
pub filename: String,
|
||||
pub release_type: u32,
|
||||
pub game_version_type_id: u32,
|
||||
#[serde(default)]
|
||||
pub mod_loader: CurseforgeLoader,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LatestEarlyAccessFilesIndex {
|
||||
pub struct ModFilesIndex {
|
||||
pub game_version: String,
|
||||
pub file_id: u32,
|
||||
pub filename: String,
|
||||
|
|
@ -423,4 +421,20 @@ pub async fn get(id: u32) -> Result<CurseforgePackage> {
|
|||
&fetch(format!("/v1/mods/{}", id).as_str())
|
||||
.await?,
|
||||
)?.data)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_package_body(url: String) -> Result<String> {
|
||||
Ok(serde_json::from_slice::<CFData<_>>(
|
||||
&fetch(&url).await?,
|
||||
)?.data)
|
||||
}
|
||||
|
||||
// pub async fn get_all_versions(
|
||||
// project_id: &str,
|
||||
// game_versions: Option<Vec<String>>,
|
||||
// loaders: Option<Vec<Loader>>,
|
||||
// page: Option<u32>,
|
||||
// page_size: Option<u16>,
|
||||
// ) -> Result<Vec<ManagedVersion>> {
|
||||
|
||||
// }
|
||||
|
|
@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::data::{Loader, ManagedPackage, ManagedUser, ManagedVersion, PackageType};
|
||||
use crate::package::content::modrinth::FacetBuilder;
|
||||
use crate::store::{Author, ProviderSearchResults};
|
||||
use crate::store::{Author, PackageBody, ProviderSearchResults};
|
||||
use crate::Result;
|
||||
|
||||
mod modrinth;
|
||||
|
|
@ -107,18 +107,29 @@ impl Providers {
|
|||
project_id: &str,
|
||||
game_versions: Option<Vec<String>>,
|
||||
loaders: Option<Vec<Loader>>,
|
||||
page: Option<u32>,
|
||||
page_size: Option<u16>,
|
||||
) -> Result<Vec<ManagedVersion>> {
|
||||
Ok(match self {
|
||||
Self::Modrinth => modrinth::get_all_versions(project_id, game_versions, loaders),
|
||||
Self::Curseforge => todo!(),
|
||||
}
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect())
|
||||
Ok(
|
||||
match self {
|
||||
Self::Modrinth => modrinth::get_all_versions(project_id, game_versions, loaders),
|
||||
// Self::Curseforge => curseforge::get_all_versions(
|
||||
// project_id,
|
||||
// game_versions.map(|list| list.first()),
|
||||
// loaders.map(|list| list.first()),
|
||||
// page,
|
||||
// page_size
|
||||
// ),
|
||||
Self::Curseforge => todo!(),
|
||||
}
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect()
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_versions(&self, versions: Vec<String>) -> Result<Vec<ManagedVersion>> {
|
||||
pub async fn get_versions(&self, pkg_id: &str, versions: Vec<String>) -> Result<Vec<ManagedVersion>> {
|
||||
Ok(match self {
|
||||
Self::Modrinth => modrinth::get_versions(versions),
|
||||
Self::Curseforge => todo!(),
|
||||
|
|
@ -129,7 +140,7 @@ impl Providers {
|
|||
.collect())
|
||||
}
|
||||
|
||||
pub async fn get_version(&self, version_id: &str) -> Result<ManagedVersion> {
|
||||
pub async fn get_version(&self, pkg_id: &str, version_id: &str) -> Result<ManagedVersion> {
|
||||
Ok(match self {
|
||||
Self::Modrinth => modrinth::get_version(version_id),
|
||||
Self::Curseforge => todo!(),
|
||||
|
|
@ -139,11 +150,27 @@ impl Providers {
|
|||
}
|
||||
|
||||
pub async fn get_authors(&self, author: &Author) -> Result<Vec<ManagedUser>> {
|
||||
match self {
|
||||
Self::Modrinth => modrinth::get_authors(author),
|
||||
Self::Curseforge => todo!(),
|
||||
}
|
||||
.await
|
||||
Ok(match author {
|
||||
Author::Team { .. } => {
|
||||
match self {
|
||||
Self::Modrinth => modrinth::get_authors(author).await?,
|
||||
_ => return Err(anyhow::anyhow!("{} does not support teams", self).into()),
|
||||
}
|
||||
},
|
||||
Author::Users(users) => users.to_owned()
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_package_body(&self, body: &PackageBody) -> Result<String> {
|
||||
Ok(match body {
|
||||
PackageBody::Url(url) => {
|
||||
match self {
|
||||
Self::Curseforge => curseforge::get_package_body(url.to_owned()).await?,
|
||||
_ => return Err(anyhow::anyhow!("{} does not support direct URLs", self).into()),
|
||||
}
|
||||
},
|
||||
PackageBody::Markdown(markdown) => markdown.to_owned()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ impl From<ModrinthPackage> for ManagedPackage {
|
|||
id: value.id,
|
||||
title: value.title,
|
||||
description: value.description,
|
||||
body: value.body,
|
||||
body: crate::store::PackageBody::Markdown(value.body),
|
||||
main: value.slug,
|
||||
versions: value.versions,
|
||||
game_versions: value.game_versions,
|
||||
|
|
@ -78,7 +78,7 @@ impl From<ModrinthPackage> for ManagedPackage {
|
|||
updated: value.updated,
|
||||
client: value.client_side,
|
||||
server: value.server_side,
|
||||
downloads: value.downloads,
|
||||
downloads: value.downloads as u64,
|
||||
followers: value.followers,
|
||||
categories: value.categories,
|
||||
optional_categories: Some(value.additional_categories),
|
||||
|
|
|
|||
|
|
@ -603,6 +603,13 @@ pub enum Author {
|
|||
Users(Vec<ManagedUser>),
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "specta", derive(specta::Type))]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub enum PackageBody {
|
||||
Url(String),
|
||||
Markdown(String),
|
||||
}
|
||||
|
||||
/// Universal metadata for any managed package from a Mod distribution platform.
|
||||
#[cfg_attr(feature = "specta", derive(specta::Type))]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
|
|
@ -613,7 +620,7 @@ pub struct ManagedPackage {
|
|||
pub package_type: PackageType,
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub body: String,
|
||||
pub body: PackageBody,
|
||||
pub main: String,
|
||||
pub versions: Vec<String>,
|
||||
pub game_versions: Vec<String>,
|
||||
|
|
@ -624,7 +631,7 @@ pub struct ManagedPackage {
|
|||
pub updated: DateTime<Utc>,
|
||||
pub client: PackageSide,
|
||||
pub server: PackageSide,
|
||||
pub downloads: u32,
|
||||
pub downloads: u64,
|
||||
pub followers: u32,
|
||||
pub categories: Vec<String>,
|
||||
pub optional_categories: Option<Vec<String>>,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
pub mod http;
|
||||
pub mod java;
|
||||
pub mod watcher;
|
||||
pub mod pagination;
|
||||
|
||||
#[cfg(feature = "tauri")]
|
||||
pub mod window;
|
||||
|
|
|
|||
10
packages/core/src/utils/pagination.rs
Normal file
10
packages/core/src/utils/pagination.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
pub fn get_page_offset(page: Option<u32>, page_size: Option<u16>) -> (u32, u16) {
|
||||
let page = page.unwrap_or(1);
|
||||
let page_size = page_size.unwrap_or(10);
|
||||
let offset = (page - 1) * page_size as u32;
|
||||
(offset, page_size)
|
||||
}
|
||||
|
||||
pub fn get_page_count(total: u32, page_size: u16) -> u32 {
|
||||
(total as f64 / page_size as f64).ceil() as u32
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue