fix(dtmm): Fix change detection for mod info
This commit is contained in:
parent
3252e66a3f
commit
ba9c190a96
8 changed files with 47 additions and 41 deletions
|
@ -6,6 +6,7 @@
|
|||
|
||||
- dtmt: split `build` into `build` and `package`
|
||||
- dtmt: implement deploying built bundles
|
||||
- dtmm: indicate when a deployment is necessary
|
||||
|
||||
== 2023-03-01
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
use std::io::{Cursor, ErrorKind, Read};
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use color_eyre::eyre::{self, Context};
|
||||
use color_eyre::{Help, Result};
|
||||
|
@ -107,7 +108,7 @@ pub(crate) async fn import_mod(state: State, info: FileInfo) -> Result<ModInfo>
|
|||
|
||||
let packages = files
|
||||
.into_iter()
|
||||
.map(|(name, files)| PackageInfo::new(name, files.into_iter().collect()))
|
||||
.map(|(name, files)| Arc::new(PackageInfo::new(name, files.into_iter().collect())))
|
||||
.collect();
|
||||
let info = ModInfo::new(mod_cfg, packages);
|
||||
|
||||
|
@ -171,14 +172,14 @@ async fn read_mod_dir_entry(res: Result<DirEntry>) -> Result<ModInfo> {
|
|||
|
||||
let packages = files
|
||||
.into_iter()
|
||||
.map(|(name, files)| PackageInfo::new(name, files.into_iter().collect()))
|
||||
.map(|(name, files)| Arc::new(PackageInfo::new(name, files.into_iter().collect())))
|
||||
.collect();
|
||||
let info = ModInfo::new(cfg, packages);
|
||||
Ok(info)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(mod_order))]
|
||||
pub(crate) fn load_mods<'a, P, S>(mod_dir: P, mod_order: S) -> Result<Vector<ModInfo>>
|
||||
pub(crate) fn load_mods<'a, P, S>(mod_dir: P, mod_order: S) -> Result<Vector<Arc<ModInfo>>>
|
||||
where
|
||||
S: Iterator<Item = &'a LoadOrderEntry>,
|
||||
P: AsRef<Path> + std::fmt::Debug,
|
||||
|
@ -214,7 +215,7 @@ where
|
|||
.filter_map(|entry| {
|
||||
if let Some(mut info) = mods.remove(&entry.id) {
|
||||
info.enabled = entry.enabled;
|
||||
Some(info)
|
||||
Some(Arc::new(info))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ async fn handle_action(
|
|||
.await
|
||||
.submit_command(
|
||||
ACTION_FINISH_ADD_MOD,
|
||||
SingleUse::new(mod_info),
|
||||
SingleUse::new(Arc::new(mod_info)),
|
||||
Target::Auto,
|
||||
)
|
||||
.expect("failed to send command");
|
||||
|
|
|
@ -17,7 +17,7 @@ impl Default for View {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Data, Debug)]
|
||||
#[derive(Clone, Data, Debug, PartialEq)]
|
||||
pub struct PackageInfo {
|
||||
pub name: String,
|
||||
pub files: Vector<String>,
|
||||
|
@ -29,14 +29,14 @@ impl PackageInfo {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) struct ModResourceInfo {
|
||||
pub init: PathBuf,
|
||||
pub data: Option<PathBuf>,
|
||||
pub localization: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Data, Debug, Lens)]
|
||||
#[derive(Clone, Data, Debug, Lens, PartialEq)]
|
||||
pub(crate) struct ModInfo {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
|
@ -44,14 +44,14 @@ pub(crate) struct ModInfo {
|
|||
pub enabled: bool,
|
||||
#[lens(ignore)]
|
||||
#[data(ignore)]
|
||||
pub packages: Vector<PackageInfo>,
|
||||
pub packages: Vector<Arc<PackageInfo>>,
|
||||
#[lens(ignore)]
|
||||
#[data(ignore)]
|
||||
pub resources: ModResourceInfo,
|
||||
}
|
||||
|
||||
impl ModInfo {
|
||||
pub fn new(cfg: ModConfig, packages: Vector<PackageInfo>) -> Self {
|
||||
pub fn new(cfg: ModConfig, packages: Vector<Arc<PackageInfo>>) -> Self {
|
||||
Self {
|
||||
id: cfg.id,
|
||||
name: cfg.name,
|
||||
|
@ -67,16 +67,10 @@ impl ModInfo {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq for ModInfo {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.name.eq(&other.name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Data, Lens)]
|
||||
pub(crate) struct State {
|
||||
pub current_view: View,
|
||||
pub mods: Vector<ModInfo>,
|
||||
pub mods: Vector<Arc<ModInfo>>,
|
||||
pub selected_mod_index: Option<usize>,
|
||||
pub dirty: bool,
|
||||
pub is_deployment_in_progress: bool,
|
||||
|
@ -123,8 +117,8 @@ impl State {
|
|||
self.selected_mod_index = Some(index);
|
||||
}
|
||||
|
||||
pub fn add_mod(&mut self, info: ModInfo) {
|
||||
if let Some(pos) = self.mods.index_of(&info) {
|
||||
pub fn add_mod(&mut self, info: Arc<ModInfo>) {
|
||||
if let Some(pos) = self.mods.iter().position(|i| i.id == info.id) {
|
||||
self.mods.set(pos, info);
|
||||
self.selected_mod_index = Some(pos);
|
||||
} else {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use druid::{
|
||||
AppDelegate, Command, DelegateCtx, Env, FileInfo, Handled, Selector, SingleUse, Target,
|
||||
};
|
||||
|
@ -9,9 +11,9 @@ pub(crate) const ACTION_SELECT_MOD: Selector<usize> = Selector::new("dtmm.action
|
|||
pub(crate) const ACTION_SELECTED_MOD_UP: Selector = Selector::new("dtmm.action.selected-mod-up");
|
||||
pub(crate) const ACTION_SELECTED_MOD_DOWN: Selector =
|
||||
Selector::new("dtmm.action.selected-mod-down");
|
||||
pub(crate) const ACTION_START_DELETE_SELECTED_MOD: Selector<SingleUse<ModInfo>> =
|
||||
pub(crate) const ACTION_START_DELETE_SELECTED_MOD: Selector<SingleUse<Arc<ModInfo>>> =
|
||||
Selector::new("dtmm.action.srart-delete-selected-mod");
|
||||
pub(crate) const ACTION_FINISH_DELETE_SELECTED_MOD: Selector<SingleUse<ModInfo>> =
|
||||
pub(crate) const ACTION_FINISH_DELETE_SELECTED_MOD: Selector<SingleUse<Arc<ModInfo>>> =
|
||||
Selector::new("dtmm.action.finish-delete-selected-mod");
|
||||
|
||||
pub(crate) const ACTION_START_DEPLOY: Selector = Selector::new("dtmm.action.start-deploy");
|
||||
|
@ -23,7 +25,7 @@ pub(crate) const ACTION_FINISH_RESET_DEPLOYMENT: Selector =
|
|||
Selector::new("dtmm.action.finish-reset-deployment");
|
||||
|
||||
pub(crate) const ACTION_ADD_MOD: Selector<FileInfo> = Selector::new("dtmm.action.add-mod");
|
||||
pub(crate) const ACTION_FINISH_ADD_MOD: Selector<SingleUse<ModInfo>> =
|
||||
pub(crate) const ACTION_FINISH_ADD_MOD: Selector<SingleUse<Arc<ModInfo>>> =
|
||||
Selector::new("dtmm.action.finish-add-mod");
|
||||
|
||||
pub(crate) const ACTION_LOG: Selector<SingleUse<String>> = Selector::new("dtmm.action.log");
|
||||
|
@ -39,7 +41,7 @@ pub(crate) enum AsyncAction {
|
|||
DeployMods(State),
|
||||
ResetDeployment(State),
|
||||
AddMod((State, FileInfo)),
|
||||
DeleteMod((State, ModInfo)),
|
||||
DeleteMod((State, Arc<ModInfo>)),
|
||||
SaveSettings(State),
|
||||
}
|
||||
|
||||
|
@ -168,7 +170,6 @@ impl AppDelegate<State> for Delegate {
|
|||
};
|
||||
|
||||
state.mods.remove(index);
|
||||
// ctx.submit_command(ACTION_START_SAVE_SETTINGS);
|
||||
|
||||
Handled::Yes
|
||||
}
|
||||
|
@ -191,7 +192,6 @@ impl AppDelegate<State> for Delegate {
|
|||
.expect("command type matched but didn't contain the expected value");
|
||||
if let Some(info) = info.take() {
|
||||
state.add_mod(info);
|
||||
// ctx.submit_command(ACTION_START_SAVE_SETTINGS);
|
||||
}
|
||||
Handled::Yes
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use druid::im::Vector;
|
||||
use druid::{Data, Lens};
|
||||
|
||||
|
@ -5,9 +7,9 @@ use super::{ModInfo, State};
|
|||
|
||||
pub(crate) struct SelectedModLens;
|
||||
|
||||
impl Lens<State, Option<ModInfo>> for SelectedModLens {
|
||||
impl Lens<State, Option<Arc<ModInfo>>> for SelectedModLens {
|
||||
#[tracing::instrument(name = "SelectedModLens::with", skip_all)]
|
||||
fn with<V, F: FnOnce(&Option<ModInfo>) -> V>(&self, data: &State, f: F) -> V {
|
||||
fn with<V, F: FnOnce(&Option<Arc<ModInfo>>) -> V>(&self, data: &State, f: F) -> V {
|
||||
let info = data
|
||||
.selected_mod_index
|
||||
.and_then(|i| data.mods.get(i).cloned());
|
||||
|
@ -16,16 +18,16 @@ impl Lens<State, Option<ModInfo>> for SelectedModLens {
|
|||
}
|
||||
|
||||
#[tracing::instrument(name = "SelectedModLens::with_mut", skip_all)]
|
||||
fn with_mut<V, F: FnOnce(&mut Option<ModInfo>) -> V>(&self, data: &mut State, f: F) -> V {
|
||||
fn with_mut<V, F: FnOnce(&mut Option<Arc<ModInfo>>) -> V>(&self, data: &mut State, f: F) -> V {
|
||||
match data.selected_mod_index {
|
||||
Some(i) => {
|
||||
let mut info = data.mods.get_mut(i).cloned();
|
||||
let ret = f(&mut info);
|
||||
|
||||
if let Some(info) = info {
|
||||
if let Some(new) = info {
|
||||
// TODO: Figure out a way to check for equality and
|
||||
// only update when needed
|
||||
data.mods.set(i, info);
|
||||
data.mods.set(i, new);
|
||||
} else {
|
||||
data.selected_mod_index = None;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use druid::im::Vector;
|
||||
use druid::lens;
|
||||
use druid::widget::{
|
||||
|
@ -82,9 +84,11 @@ fn build_top_bar() -> impl Widget<State> {
|
|||
|
||||
fn build_mod_list() -> impl Widget<State> {
|
||||
let list = List::new(|| {
|
||||
let checkbox =
|
||||
Checkbox::new("").lens(lens!((usize, ModInfo, bool), 1).then(ModInfo::enabled));
|
||||
let name = Label::raw().lens(lens!((usize, ModInfo, bool), 1).then(ModInfo::name));
|
||||
let checkbox = Checkbox::new("")
|
||||
.lens(lens!((usize, Arc<ModInfo>, bool), 1).then(ModInfo::enabled.in_arc()));
|
||||
|
||||
let name =
|
||||
Label::raw().lens(lens!((usize, Arc<ModInfo>, bool), 1).then(ModInfo::name.in_arc()));
|
||||
|
||||
Flex::row()
|
||||
.must_fill_main_axis(true)
|
||||
|
@ -114,8 +118,10 @@ fn build_mod_list() -> impl Widget<State> {
|
|||
.collect::<Vector<_>>()
|
||||
},
|
||||
|state, infos| {
|
||||
infos.into_iter().for_each(|(i, info, _)| {
|
||||
state.mods.set(i, info);
|
||||
infos.into_iter().for_each(|(i, new, _)| {
|
||||
if state.mods.get(i).cloned() != Some(new.clone()) {
|
||||
state.mods.set(i, new);
|
||||
}
|
||||
});
|
||||
},
|
||||
));
|
||||
|
@ -147,12 +153,12 @@ fn build_mod_details_buttons() -> impl Widget<State> {
|
|||
.on_click(|_ctx, enabled: &mut bool, _env| {
|
||||
*enabled = !(*enabled);
|
||||
})
|
||||
.lens(ModInfo::enabled)
|
||||
.lens(ModInfo::enabled.in_arc())
|
||||
},
|
||||
// TODO: Gray out
|
||||
|| Button::new("Enable Mod"),
|
||||
)
|
||||
.disabled_if(|info: &Option<ModInfo>, _env: &druid::Env| info.is_none())
|
||||
.disabled_if(|info: &Option<Arc<ModInfo>>, _env: &druid::Env| info.is_none())
|
||||
.lens(State::selected_mod);
|
||||
|
||||
let button_add_mod = Button::new("Add Mod").on_click(|ctx, _state: &mut State, _env| {
|
||||
|
@ -167,14 +173,14 @@ fn build_mod_details_buttons() -> impl Widget<State> {
|
|||
});
|
||||
|
||||
let button_delete_mod = Button::new("Delete Mod")
|
||||
.on_click(|ctx, data: &mut Option<ModInfo>, _env| {
|
||||
.on_click(|ctx, data: &mut Option<Arc<ModInfo>>, _env| {
|
||||
if let Some(info) = data {
|
||||
ctx.submit_command(
|
||||
ACTION_START_DELETE_SELECTED_MOD.with(SingleUse::new(info.clone())),
|
||||
);
|
||||
}
|
||||
})
|
||||
.disabled_if(|info: &Option<ModInfo>, _env: &druid::Env| info.is_none())
|
||||
.disabled_if(|info: &Option<Arc<ModInfo>>, _env: &druid::Env| info.is_none())
|
||||
.lens(State::selected_mod);
|
||||
|
||||
Flex::column()
|
||||
|
@ -208,10 +214,10 @@ fn build_mod_details_info() -> impl Widget<State> {
|
|||
// Force the label to take up the entire details' pane width,
|
||||
// so that we can center-align it.
|
||||
.expand_width()
|
||||
.lens(ModInfo::name);
|
||||
.lens(ModInfo::name.in_arc());
|
||||
let description = Label::raw()
|
||||
.with_line_break_mode(LineBreaking::WordWrap)
|
||||
.lens(ModInfo::description);
|
||||
.lens(ModInfo::description.in_arc());
|
||||
|
||||
Flex::column()
|
||||
.cross_axis_alignment(CrossAxisAlignment::Start)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::io::ErrorKind;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use clap::{parser::ValueSource, ArgMatches};
|
||||
|
@ -38,6 +39,7 @@ impl<'a> From<&'a State> for ConfigSerialize<'a> {
|
|||
mod_order: state
|
||||
.mods
|
||||
.iter()
|
||||
.map(Arc::as_ref)
|
||||
.map(LoadOrderEntrySerialize::from)
|
||||
.collect(),
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue