prompt for different mc versions when installing modpacks
This commit is contained in:
parent
efbde53326
commit
538a0da24d
9 changed files with 377 additions and 39 deletions
|
|
@ -28,6 +28,7 @@ pub use active_cluster::{
|
|||
};
|
||||
|
||||
pub use actions::{Actions, NotificationBuilder, PumpSignal, modpack_job_running};
|
||||
pub use queries::ALL_VERSIONS;
|
||||
pub(crate) use queries::use_folder_watch;
|
||||
pub use queries::{
|
||||
AddOfflineAccountKeys, AvailableBundlesQuery, BROWSE_PAGE_SIZE, BeginMicrosoftLoginMutation,
|
||||
|
|
@ -64,9 +65,9 @@ pub use queries::{
|
|||
use_global_analytics, use_java_majors, use_java_runtimes, use_leftovers, use_loader_versions,
|
||||
use_local_image, use_log_action, use_log_content, use_migratable_routes, use_migration,
|
||||
use_named_profiles, use_onboarding_bundles, use_package_categories, use_package_meta_batch,
|
||||
use_package_project, use_package_search, use_package_updates, use_package_versions,
|
||||
use_package_versions_when, use_player_profile, use_player_skin, use_provider_versions,
|
||||
use_refresh_account, use_refresh_all_accounts, use_remove_account, use_screenshot_action,
|
||||
use_package_project, use_package_search, use_package_updates, use_package_versions_when,
|
||||
use_player_profile, use_player_skin, use_provider_versions, use_refresh_account,
|
||||
use_refresh_all_accounts, use_remove_account, use_screenshot_action,
|
||||
use_screenshot_folder_watch, use_set_default_account, use_storage_action, use_storage_report,
|
||||
use_terms, use_upload_log, use_version_art, use_version_art_gallery, use_version_loaders,
|
||||
use_version_metadata, use_versions, version_list, versions_metadata, versions_total,
|
||||
|
|
|
|||
|
|
@ -79,11 +79,12 @@ pub use mutations::{
|
|||
invalidate_profile_queries, use_cluster_mutation,
|
||||
};
|
||||
pub use package_updates::{package_updates, stale_hashes, use_package_updates};
|
||||
pub use packages::ALL_VERSIONS;
|
||||
pub use packages::{
|
||||
BROWSE_PAGE_SIZE, VERSIONS_PAGE_SIZE, category_list, content_type_for_slug, package_meta_batch,
|
||||
project_detail, search_items, search_pending, search_total, use_package_categories,
|
||||
use_package_meta_batch, use_package_project, use_package_search, use_package_versions,
|
||||
use_package_versions_when, version_list, versions_total,
|
||||
use_package_meta_batch, use_package_project, use_package_search, use_package_versions_when,
|
||||
version_list, versions_total,
|
||||
};
|
||||
pub use player_profile::use_player_profile;
|
||||
pub use screenshots::{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use oneclient_core::LauncherError;
|
|||
|
||||
pub const BROWSE_PAGE_SIZE: usize = DEFAULT_PAGE_SIZE;
|
||||
pub const VERSIONS_PAGE_SIZE: usize = 20;
|
||||
pub const ALL_VERSIONS: usize = usize::MAX;
|
||||
|
||||
const VERSIONS_STALE: Duration = Duration::from_secs(5 * 60);
|
||||
|
||||
|
|
@ -209,6 +210,7 @@ pub struct PackageVersionsKeys {
|
|||
pub game_version: Option<String>,
|
||||
pub loader: Option<GameLoader>,
|
||||
pub page: usize,
|
||||
pub page_size: usize,
|
||||
}
|
||||
|
||||
impl QueryCapability for PackageVersionsQuery {
|
||||
|
|
@ -228,8 +230,8 @@ impl QueryCapability for PackageVersionsQuery {
|
|||
&keys.project_id,
|
||||
keys.game_version.as_deref(),
|
||||
keys.loader,
|
||||
keys.page * VERSIONS_PAGE_SIZE,
|
||||
VERSIONS_PAGE_SIZE,
|
||||
keys.page.saturating_mul(keys.page_size),
|
||||
keys.page_size,
|
||||
&state.services.content(),
|
||||
)
|
||||
.await?)
|
||||
|
|
@ -238,16 +240,6 @@ impl QueryCapability for PackageVersionsQuery {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn use_package_versions(
|
||||
provider: ProviderId,
|
||||
project_id: String,
|
||||
game_version: Option<String>,
|
||||
loader: Option<GameLoader>,
|
||||
page: usize,
|
||||
) -> UseQuery<PackageVersionsQuery> {
|
||||
use_package_versions_when(true, provider, project_id, game_version, loader, page)
|
||||
}
|
||||
|
||||
pub fn use_package_versions_when(
|
||||
enabled: bool,
|
||||
provider: ProviderId,
|
||||
|
|
@ -255,6 +247,7 @@ pub fn use_package_versions_when(
|
|||
game_version: Option<String>,
|
||||
loader: Option<GameLoader>,
|
||||
page: usize,
|
||||
page_size: usize,
|
||||
) -> UseQuery<PackageVersionsQuery> {
|
||||
let keys = enabled.then_some(PackageVersionsKeys {
|
||||
provider,
|
||||
|
|
@ -262,6 +255,7 @@ pub fn use_package_versions_when(
|
|||
game_version,
|
||||
loader,
|
||||
page,
|
||||
page_size,
|
||||
});
|
||||
|
||||
use_query(Query::new(keys, PackageVersionsQuery).stale_time(VERSIONS_STALE))
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ use oneclient_core::clusters::ModpackSource;
|
|||
|
||||
use crate::components::{Button, Icon, IconType};
|
||||
use crate::hooks::{
|
||||
content_type_for_slug, use_browser_compat, use_cluster, use_dispatch, use_installs_snapshot,
|
||||
use_package_versions_when, version_list,
|
||||
ALL_VERSIONS, VERSIONS_PAGE_SIZE, content_type_for_slug, use_browser_compat, use_cluster,
|
||||
use_dispatch, use_installs_snapshot, use_package_versions_when, version_list,
|
||||
};
|
||||
use crate::routes::Route;
|
||||
use crate::theme::colors;
|
||||
|
|
@ -367,10 +367,17 @@ impl Component for InstallButton {
|
|||
game_version,
|
||||
loader,
|
||||
0,
|
||||
if is_modpack {
|
||||
ALL_VERSIONS
|
||||
} else {
|
||||
VERSIONS_PAGE_SIZE
|
||||
},
|
||||
));
|
||||
let latest = preferred_version(&versions, self.content_type).map(|v| v.version_id.clone());
|
||||
let is_datapack = self.content_type == ContentType::DataPack;
|
||||
let mut world_prompt = use_state(|| None::<String>);
|
||||
let mut modpack_prompt = use_state(|| false);
|
||||
let mut choices = use_state(Vec::new);
|
||||
|
||||
// Nothing to start twice while an install is running or before versions arrive
|
||||
let (installing, waiting) =
|
||||
|
|
@ -418,11 +425,17 @@ impl Component for InstallButton {
|
|||
if is_datapack {
|
||||
world_prompt.set(Some(version_id));
|
||||
} else if is_modpack {
|
||||
dispatch.install_modpack(ModpackSource::Provider {
|
||||
provider,
|
||||
project_id: project_id.clone(),
|
||||
version_id,
|
||||
});
|
||||
let picks = minecraft_choices(&versions);
|
||||
if picks.len() > 1 {
|
||||
choices.set(picks);
|
||||
modpack_prompt.set(true);
|
||||
} else {
|
||||
dispatch.install_modpack(ModpackSource::Provider {
|
||||
provider,
|
||||
project_id: project_id.clone(),
|
||||
version_id,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
dispatch.install_package(
|
||||
cluster_id,
|
||||
|
|
@ -455,9 +468,15 @@ impl Component for InstallButton {
|
|||
.maybe_child(world_prompt.read().is_some().then_some(WorldInstallPrompt {
|
||||
cluster_id,
|
||||
provider,
|
||||
project_id,
|
||||
project_id: project_id.clone(),
|
||||
pending: world_prompt,
|
||||
}))
|
||||
.maybe_child(modpack_prompt.read().then(|| ModpackVersionPrompt {
|
||||
provider,
|
||||
project_id,
|
||||
choices: choices.read().clone(),
|
||||
open: modpack_prompt,
|
||||
}))
|
||||
.into_element()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ use crate::ui::grid_columns_for_width;
|
|||
use crate::view::app::cluster::supports_datapacks;
|
||||
|
||||
use super::{
|
||||
InstallSource, Installed, PackageBanner, Thumbnail, WorldInstallPrompt, installed_map,
|
||||
preferred_version,
|
||||
InstallSource, Installed, ModpackVersionPrompt, PackageBanner, Thumbnail, WorldInstallPrompt,
|
||||
installed_map, minecraft_choices, preferred_version,
|
||||
};
|
||||
use crate::utils::{abbreviate_number, sort_clusters_for_home};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ mod package;
|
|||
pub use index::Browser;
|
||||
pub(crate) use index::{browsable_type, encode_package_id};
|
||||
|
||||
mod modpack_prompt;
|
||||
mod world_prompt;
|
||||
use modpack_prompt::{ModpackVersionPrompt, minecraft_choices};
|
||||
use world_prompt::WorldInstallPrompt;
|
||||
|
||||
/// Projects shipping both a mod and a data pack tag the mod files with a loader
|
||||
|
|
|
|||
276
packages/oneclient_app/src/view/app/browser/modpack_prompt.rs
Normal file
276
packages/oneclient_app/src/view/app/browser/modpack_prompt.rs
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use freya::prelude::*;
|
||||
use oneclient_common::version::parse_mc_version;
|
||||
use oneclient_content::packages::ProviderId;
|
||||
use oneclient_content::packages::types::{ReleaseType, VersionSummary};
|
||||
use oneclient_core::clusters::ModpackSource;
|
||||
|
||||
use crate::components::{Button, Icon, IconType, ScrollArea};
|
||||
use crate::hooks::use_dispatch;
|
||||
use crate::theme::colors;
|
||||
use crate::ui::border_all_color;
|
||||
use crate::view::app::cluster::dialog;
|
||||
|
||||
const ROW_H: f32 = 44.;
|
||||
const ROW_GAP: f32 = 6.;
|
||||
const VISIBLE_ROWS: usize = 5;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub(crate) struct MinecraftChoice {
|
||||
mc: String,
|
||||
version_id: String,
|
||||
detail: String,
|
||||
}
|
||||
|
||||
pub(crate) fn minecraft_choices(versions: &[VersionSummary]) -> Vec<MinecraftChoice> {
|
||||
let mut seen = HashSet::new();
|
||||
let mut order: Vec<_> = versions
|
||||
.iter()
|
||||
.flat_map(|v| &v.game_versions)
|
||||
.filter(|mc| seen.insert(mc.as_str()))
|
||||
.filter(|mc| mc.bytes().all(|b| b.is_ascii_digit() || b == b'.'))
|
||||
.filter_map(|mc| parse_mc_version(mc).map(|p| (mc.clone(), (p.major, p.minor, p.patch))))
|
||||
.collect();
|
||||
order.sort_by(|a, b| b.1.cmp(&a.1));
|
||||
|
||||
let mut choices: Vec<MinecraftChoice> = Vec::new();
|
||||
for (mc, _) in order {
|
||||
let for_mc: Vec<_> = versions
|
||||
.iter()
|
||||
.filter(|v| v.game_versions.contains(&mc))
|
||||
.collect();
|
||||
let mut loader_sets: Vec<&Vec<_>> = Vec::new();
|
||||
for v in &for_mc {
|
||||
if !loader_sets.contains(&&v.loaders) {
|
||||
loader_sets.push(&v.loaders);
|
||||
}
|
||||
}
|
||||
for loaders in loader_sets {
|
||||
let same = || for_mc.iter().filter(|v| &v.loaders == loaders);
|
||||
let Some(pick) = same()
|
||||
.find(|v| matches!(v.release_type, ReleaseType::Release))
|
||||
.or_else(|| same().next())
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
push_choice(&mut choices, &mc, pick);
|
||||
}
|
||||
}
|
||||
choices
|
||||
}
|
||||
|
||||
fn push_choice(choices: &mut Vec<MinecraftChoice>, mc: &str, pick: &VersionSummary) {
|
||||
if let Some(existing) = choices.iter_mut().find(|c| c.version_id == pick.version_id) {
|
||||
existing.mc.push_str(" / ");
|
||||
existing.mc.push_str(mc);
|
||||
return;
|
||||
}
|
||||
let mut detail = vec![pick.version_number.clone()];
|
||||
detail.extend(pick.loaders.iter().map(|l| l.to_string()));
|
||||
match pick.release_type {
|
||||
ReleaseType::Release => {}
|
||||
ReleaseType::Beta => detail.push("Beta".to_string()),
|
||||
ReleaseType::Alpha => detail.push("Alpha".to_string()),
|
||||
}
|
||||
detail.push(pick.published.format("%Y-%m-%d").to_string());
|
||||
choices.push(MinecraftChoice {
|
||||
mc: mc.to_string(),
|
||||
version_id: pick.version_id.clone(),
|
||||
detail: detail.join(" · "),
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub(crate) struct ModpackVersionPrompt {
|
||||
pub provider: ProviderId,
|
||||
pub project_id: String,
|
||||
pub choices: Vec<MinecraftChoice>,
|
||||
pub open: State<bool>,
|
||||
}
|
||||
|
||||
impl Component for ModpackVersionPrompt {
|
||||
fn render(&self) -> impl IntoElement {
|
||||
let provider = self.provider;
|
||||
let project_id = self.project_id.clone();
|
||||
let mut open = self.open;
|
||||
let dispatch = use_dispatch();
|
||||
let mut selected = use_state(|| 0usize);
|
||||
let current = (*selected.read()).min(self.choices.len().saturating_sub(1));
|
||||
|
||||
let rows: Vec<Element> = self
|
||||
.choices
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, choice)| {
|
||||
choice_row(choice, i == current, move || selected.set(i)).into_element()
|
||||
})
|
||||
.collect();
|
||||
let shown = self.choices.len().min(VISIBLE_ROWS) as f32;
|
||||
let list_h = shown * ROW_H + (shown - 1.).max(0.) * ROW_GAP;
|
||||
let control = ScrollArea::new()
|
||||
.width(Size::fill())
|
||||
.height(Size::px(list_h))
|
||||
.spacing(ROW_GAP)
|
||||
.children(rows)
|
||||
.into_element();
|
||||
|
||||
let version_id = self.choices.get(current).map(|c| c.version_id.clone());
|
||||
let install = move |_| {
|
||||
let Some(version_id) = version_id.clone() else {
|
||||
return;
|
||||
};
|
||||
dispatch.install_modpack(ModpackSource::Provider {
|
||||
provider,
|
||||
project_id: project_id.clone(),
|
||||
version_id,
|
||||
});
|
||||
open.set(false);
|
||||
};
|
||||
|
||||
dialog(
|
||||
"Which Minecraft version?".to_string(),
|
||||
"This modpack is made for several Minecraft versions. Pick the one to install."
|
||||
.to_string(),
|
||||
Some(control),
|
||||
move || open.set(false),
|
||||
[
|
||||
Button::new()
|
||||
.secondary()
|
||||
.on_press(move |_| open.set(false))
|
||||
.text("Cancel")
|
||||
.into_element(),
|
||||
Button::new()
|
||||
.primary()
|
||||
.on_press(install)
|
||||
.child(Icon::new(IconType::Download01).size(14.))
|
||||
.text("Install")
|
||||
.into_element(),
|
||||
],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn choice_row(
|
||||
choice: &MinecraftChoice,
|
||||
active: bool,
|
||||
mut on_select: impl FnMut() + 'static,
|
||||
) -> impl IntoElement {
|
||||
let ring = if active {
|
||||
colors::brand()
|
||||
} else {
|
||||
colors::component_border()
|
||||
};
|
||||
let radio = rect()
|
||||
.width(Size::px(16.))
|
||||
.height(Size::px(16.))
|
||||
.center()
|
||||
.corner_radius(CornerRadius::new_all(8.))
|
||||
.border(border_all_color(1.5, ring))
|
||||
.maybe_child(active.then(|| {
|
||||
rect()
|
||||
.width(Size::px(8.))
|
||||
.height(Size::px(8.))
|
||||
.corner_radius(CornerRadius::new_all(4.))
|
||||
.background(colors::brand())
|
||||
}));
|
||||
|
||||
rect()
|
||||
.horizontal()
|
||||
.width(Size::fill())
|
||||
.height(Size::px(ROW_H))
|
||||
.cross_align(Alignment::Center)
|
||||
.content(Content::Flex)
|
||||
.spacing(10.)
|
||||
.padding(Gaps::new_symmetric(0., 12.))
|
||||
.corner_radius(CornerRadius::new_all(8.))
|
||||
.background(colors::component_bg())
|
||||
.border(border_all_color(1., ring))
|
||||
.on_press(move |_| on_select())
|
||||
.child(radio)
|
||||
.child(
|
||||
rect()
|
||||
.vertical()
|
||||
.width(Size::flex(1.))
|
||||
.spacing(2.)
|
||||
.child(
|
||||
label()
|
||||
.text(format!("Minecraft {}", choice.mc))
|
||||
.font_size(13.)
|
||||
.font_weight(FontWeight::SEMI_BOLD)
|
||||
.max_lines(1)
|
||||
.color(colors::fg_primary()),
|
||||
)
|
||||
.child(
|
||||
label()
|
||||
.text(choice.detail.clone())
|
||||
.font_size(11.)
|
||||
.max_lines(1)
|
||||
.color(colors::fg_secondary()),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn version(id: &str, mc: &[&str], release_type: ReleaseType) -> VersionSummary {
|
||||
VersionSummary {
|
||||
version_id: id.to_string(),
|
||||
game_versions: mc.iter().map(|s| s.to_string()).collect(),
|
||||
project_id: String::new(),
|
||||
name: String::new(),
|
||||
version_number: String::new(),
|
||||
published: Default::default(),
|
||||
release_type,
|
||||
loaders: Vec::new(),
|
||||
downloads: 0,
|
||||
file_size: 0,
|
||||
dependencies: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_choice_per_minecraft_version_preferring_releases() {
|
||||
let versions = [
|
||||
version("b3", &["26.3"], ReleaseType::Beta),
|
||||
version("r3", &["26.3"], ReleaseType::Release),
|
||||
version("b2", &["26.2"], ReleaseType::Beta),
|
||||
version(
|
||||
"r1",
|
||||
&["1.21.11", "Fabric", "26.1", "1.21.5-rc1", "Client"],
|
||||
ReleaseType::Release,
|
||||
),
|
||||
];
|
||||
let picks: Vec<(String, String)> = minecraft_choices(&versions)
|
||||
.into_iter()
|
||||
.map(|c| (c.mc, c.version_id))
|
||||
.collect();
|
||||
let expect = [("26.3", "r3"), ("26.2", "b2"), ("26.1 / 1.21.11", "r1")];
|
||||
assert_eq!(
|
||||
picks,
|
||||
expect.map(|(a, b)| (a.to_string(), b.to_string())).to_vec()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_choice_per_loader_on_the_same_minecraft_version() {
|
||||
use oneclient_common::domain::GameLoader;
|
||||
let with = |id, loader, release_type| VersionSummary {
|
||||
loaders: vec![loader],
|
||||
..version(id, &["1.21.1"], release_type)
|
||||
};
|
||||
let versions = [
|
||||
with("fabric-new", GameLoader::Fabric, ReleaseType::Release),
|
||||
with("forge-beta", GameLoader::Forge, ReleaseType::Beta),
|
||||
with("fabric-old", GameLoader::Fabric, ReleaseType::Release),
|
||||
with("forge-rel", GameLoader::Forge, ReleaseType::Release),
|
||||
];
|
||||
let ids: Vec<String> = minecraft_choices(&versions)
|
||||
.into_iter()
|
||||
.map(|c| c.version_id)
|
||||
.collect();
|
||||
assert_eq!(ids, ["fabric-new", "forge-rel"]);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,17 +8,19 @@ use oneclient_core::clusters::ModpackSource;
|
|||
use crate::components::{ScrollArea, use_shared_delete};
|
||||
use crate::hooks::use_cluster;
|
||||
use crate::hooks::{
|
||||
bundles_with_status_items, cluster_content_items, content_type_for_slug, package_meta_batch,
|
||||
project_detail, use_browser_compat, use_bundles_with_status, use_cluster_content,
|
||||
use_dispatch, use_installs_snapshot, use_link_confirm, use_package_meta_batch,
|
||||
use_package_project, use_package_versions, version_list, versions_total,
|
||||
ALL_VERSIONS, VERSIONS_PAGE_SIZE, bundles_with_status_items, cluster_content_items,
|
||||
content_type_for_slug, package_meta_batch, project_detail, use_browser_compat,
|
||||
use_bundles_with_status, use_cluster_content, use_dispatch, use_installs_snapshot,
|
||||
use_link_confirm, use_package_meta_batch, use_package_project, use_package_versions_when,
|
||||
version_list, versions_total,
|
||||
};
|
||||
use crate::theme::colors;
|
||||
use crate::ui::border_all_color;
|
||||
|
||||
use super::{
|
||||
Installed, InstalledVersion, PackageBanner, Thumbnail, WorldInstallPrompt, activity_badge,
|
||||
installed_badge, installed_map, preferred_version,
|
||||
Installed, InstalledVersion, ModpackVersionPrompt, PackageBanner, Thumbnail,
|
||||
WorldInstallPrompt, activity_badge, installed_badge, installed_map, minecraft_choices,
|
||||
preferred_version,
|
||||
};
|
||||
use crate::utils::abbreviate_number;
|
||||
|
||||
|
|
@ -40,9 +42,17 @@ struct Installer {
|
|||
provider: ProviderId,
|
||||
world_prompt: Option<State<Option<String>>>,
|
||||
modpack: bool,
|
||||
modpack_prompt: Option<State<bool>>,
|
||||
}
|
||||
|
||||
impl Installer {
|
||||
fn install_latest(&self, project_id: String, version_id: String) {
|
||||
match self.modpack_prompt {
|
||||
Some(mut prompt) => prompt.set(true),
|
||||
None => self.install(project_id, version_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn install(&self, project_id: String, version_id: String) {
|
||||
if self.modpack {
|
||||
self.dispatch.install_modpack(ModpackSource::Provider {
|
||||
|
|
@ -148,13 +158,15 @@ impl Component for BrowserPackage {
|
|||
let dispatch = use_dispatch();
|
||||
let confirm = use_link_confirm();
|
||||
let world_prompt = use_state(|| None::<String>);
|
||||
let modpack_prompt = use_state(|| false);
|
||||
let is_datapack = content_type == ContentType::DataPack;
|
||||
let installer = Installer {
|
||||
let mut installer = Installer {
|
||||
dispatch: dispatch.clone(),
|
||||
cluster_id,
|
||||
provider,
|
||||
world_prompt: is_datapack.then_some(world_prompt),
|
||||
modpack: content_type == ContentType::Modpack,
|
||||
modpack_prompt: None,
|
||||
};
|
||||
|
||||
let cluster = use_cluster(cluster_id);
|
||||
|
|
@ -178,13 +190,25 @@ impl Component for BrowserPackage {
|
|||
}
|
||||
|
||||
let project_query = use_package_project(provider, project_id.clone());
|
||||
let versions_query = use_package_versions(
|
||||
let is_modpack = content_type == ContentType::Modpack;
|
||||
let versions_query = use_package_versions_when(
|
||||
!is_modpack,
|
||||
provider,
|
||||
project_id.clone(),
|
||||
game_version,
|
||||
loader,
|
||||
*versions_page.read(),
|
||||
VERSIONS_PAGE_SIZE,
|
||||
);
|
||||
let all_versions = version_list(&use_package_versions_when(
|
||||
is_modpack,
|
||||
provider,
|
||||
project_id.clone(),
|
||||
None,
|
||||
None,
|
||||
0,
|
||||
ALL_VERSIONS,
|
||||
));
|
||||
|
||||
let (installing, waiting) = use_installs_snapshot().package_busy(
|
||||
content_type == ContentType::Modpack,
|
||||
|
|
@ -216,8 +240,20 @@ impl Component for BrowserPackage {
|
|||
}
|
||||
});
|
||||
|
||||
let versions = version_list(&versions_query);
|
||||
let total_versions = versions_total(&versions_query);
|
||||
let (versions, total_versions) = if is_modpack {
|
||||
let page = all_versions
|
||||
.iter()
|
||||
.skip(versions_page.read().saturating_mul(VERSIONS_PAGE_SIZE))
|
||||
.take(VERSIONS_PAGE_SIZE)
|
||||
.cloned()
|
||||
.collect();
|
||||
(page, all_versions.len())
|
||||
} else {
|
||||
(
|
||||
version_list(&versions_query),
|
||||
versions_total(&versions_query),
|
||||
)
|
||||
};
|
||||
let dependency_ids: Vec<String> = versions
|
||||
.iter()
|
||||
.flat_map(|v| &v.dependencies)
|
||||
|
|
@ -229,8 +265,11 @@ impl Component for BrowserPackage {
|
|||
.into_iter()
|
||||
.map(|(id, meta)| (id, meta.name))
|
||||
.collect();
|
||||
let latest_source = if is_modpack { &all_versions } else { &versions };
|
||||
let latest_version =
|
||||
preferred_version(&versions, content_type).map(|v| v.version_id.clone());
|
||||
preferred_version(latest_source, content_type).map(|v| v.version_id.clone());
|
||||
let choices = minecraft_choices(&all_versions);
|
||||
installer.modpack_prompt = (choices.len() > 1).then_some(modpack_prompt);
|
||||
|
||||
let gallery = project
|
||||
.as_ref()
|
||||
|
|
@ -303,6 +342,12 @@ impl Component for BrowserPackage {
|
|||
project_id: project_id.clone(),
|
||||
pending: world_prompt,
|
||||
}))
|
||||
.maybe_child(modpack_prompt.read().then(|| ModpackVersionPrompt {
|
||||
provider,
|
||||
project_id: project_id.clone(),
|
||||
choices,
|
||||
open: modpack_prompt,
|
||||
}))
|
||||
.into_element()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ pub(super) fn sidebar(
|
|||
.enabled(can_install)
|
||||
.on_press(move |_| {
|
||||
if let Some(version_id) = latest_version.clone() {
|
||||
installer.install(project_id.clone(), version_id);
|
||||
installer.install_latest(project_id.clone(), version_id);
|
||||
}
|
||||
})
|
||||
.child(Icon::new(IconType::Download01).size(14.))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue