Skip to content

Commit

Permalink
Add support for manifest notes
Browse files Browse the repository at this point in the history
  • Loading branch information
mtkennerly committed Jul 20, 2024
1 parent 8d6ea77 commit 750056e
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 27 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
* GUI: When left open,
Ludusavi will automatically check for manifest updates once every 24 hours.
Previously, this check only occurred when the app started.
* Manifests may now include a `notes` field.
If a game has notes and is found during a backup scan,
then the backup screen will show an info icon next to the game,
and you can click the icon to display the notes.
The primary manifest does not (yet) contain any notes,
so this mainly applies to secondary manifest authors.
* Fixed:
* CLI: Some commands would fail with relative path arguments.
* Changed:
Expand Down
1 change: 1 addition & 0 deletions src/gui/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,7 @@ impl Application for App {
Message::Restore(phase) => self.handle_restore(phase),
Message::ValidateBackups(phase) => self.handle_validation(phase),
Message::CancelOperation => self.cancel_operation(),
Message::ShowGameNotes { game, notes } => self.show_modal(Modal::GameNotes { game, notes }),
Message::EditedBackupTarget(text) => {
self.text_histories.backup_target.push(&text);
self.config.backup.path.reset(text);
Expand Down
9 changes: 9 additions & 0 deletions src/gui/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{
},
lang::TRANSLATOR,
prelude::{Finality, SyncDirection},
resource::manifest,
};

fn template(content: Text, action: Option<Message>, style: Option<style::Button>) -> Element {
Expand Down Expand Up @@ -467,3 +468,11 @@ pub fn validate_backups<'a>(ongoing: &Operation) -> Element<'a> {
matches!(ongoing, Operation::ValidateBackups { .. }).then_some(style::Button::Negative),
)
}

pub fn show_game_notes<'a>(game: String, notes: Vec<manifest::Note>) -> Element<'a> {
template(
Icon::Info.text_narrow(),
Some(Message::ShowGameNotes { game, notes }),
Some(style::Button::Bare),
)
}
6 changes: 5 additions & 1 deletion src/gui/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
BackupFormat, CloudFilter, CustomGameKind, RedirectKind, Root, SecondaryManifestConfigKind, SortKey, Theme,
ZipCompression,
},
manifest::{Manifest, ManifestUpdate, Store},
manifest::{self, Manifest, ManifestUpdate, Store},
},
scan::{
game_filter,
Expand Down Expand Up @@ -240,6 +240,10 @@ pub enum Message {
subject: ScrollSubject,
position: iced::widget::scrollable::AbsoluteOffset,
},
ShowGameNotes {
game: String,
notes: Vec<manifest::Note>,
},
EditedBackupComment {
game: String,
comment: String,
Expand Down
5 changes: 5 additions & 0 deletions src/gui/game_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,11 @@ impl GameListEntry {
.style(style::Container::Tooltip)
})
})
.push_maybe({
(!self.scan_info.notes.is_empty()).then(|| {
button::show_game_notes(self.scan_info.game_name.clone(), self.scan_info.notes.clone())
})
})
.push_maybe({
self.scan_info
.backup
Expand Down
8 changes: 7 additions & 1 deletion src/gui/icon.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use iced::alignment;
use iced::{alignment, Length};

use crate::gui::{
font,
Expand All @@ -20,6 +20,7 @@ pub enum Icon {
FastForward,
Filter,
FolderOpen,
Info,
KeyboardArrowDown,
KeyboardArrowRight,
Language,
Expand Down Expand Up @@ -56,6 +57,7 @@ impl Icon {
Self::FastForward => '\u{E01F}',
Self::Filter => '\u{ef4f}',
Self::FolderOpen => '\u{E2C8}',
Self::Info => '\u{e88e}',
Self::KeyboardArrowDown => '\u{E313}',
Self::KeyboardArrowRight => '\u{E315}',
Self::Language => '\u{E894}',
Expand Down Expand Up @@ -87,6 +89,10 @@ impl Icon {
.line_height(1.0)
}

pub fn text_narrow(self) -> Text<'static> {
self.text().width(Length::Shrink)
}

pub fn text_small(self) -> Text<'static> {
text(self.as_char().to_string())
.font(font::ICONS)
Expand Down
55 changes: 44 additions & 11 deletions src/gui/modal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ use crate::{
badge::Badge,
button,
common::{BackupPhase, Message, RestorePhase, ScrollSubject, UndoSubject},
icon::Icon,
shortcuts::TextHistories,
style,
widget::{pick_list, text, Column, Container, Element, IcedParentExt, Row, Space},
},
lang::TRANSLATOR,
prelude::{Error, Finality, SyncDirection},
resource::config::{Config, Root},
resource::{
config::{Config, Root},
manifest,
},
};

const CHANGES_PER_PAGE: usize = 500;
Expand Down Expand Up @@ -148,13 +152,19 @@ pub enum Modal {
ConfigureWebDavRemote {
provider: WebDavProvider,
},
GameNotes {
game: String,
notes: Vec<manifest::Note>,
},
}

impl Modal {
pub fn variant(&self) -> ModalVariant {
match self {
Self::Exiting | Self::UpdatingManifest => ModalVariant::Loading,
Self::Error { .. } | Self::Errors { .. } | Self::NoMissingRoots => ModalVariant::Info,
Self::Error { .. } | Self::Errors { .. } | Self::NoMissingRoots | Self::GameNotes { .. } => {
ModalVariant::Info
}
Self::ConfirmBackup { .. }
| Self::ConfirmRestore { .. }
| Self::ConfirmAddMissingRoots(..)
Expand Down Expand Up @@ -221,14 +231,17 @@ impl Modal {
Self::ConfigureFtpRemote { .. } => RemoteChoice::Ftp.to_string(),
Self::ConfigureSmbRemote { .. } => RemoteChoice::Smb.to_string(),
Self::ConfigureWebDavRemote { .. } => RemoteChoice::WebDav.to_string(),
Self::GameNotes { game, .. } => game.clone(),
}
}

pub fn message(&self, histories: &TextHistories) -> Option<Message> {
match self {
Self::Error { .. } | Self::Errors { .. } | Self::NoMissingRoots | Self::BackupValidation { .. } => {
Some(Message::CloseModal)
}
Self::Error { .. }
| Self::Errors { .. }
| Self::NoMissingRoots
| Self::BackupValidation { .. }
| Self::GameNotes { .. } => Some(Message::CloseModal),
Self::Exiting => None,
Self::ConfirmBackup { games } => Some(Message::Backup(BackupPhase::Start {
preview: false,
Expand Down Expand Up @@ -350,7 +363,8 @@ impl Modal {
| Self::AppUpdate { .. }
| Self::ConfigureFtpRemote { .. }
| Self::ConfigureSmbRemote { .. }
| Self::ConfigureWebDavRemote { .. } => vec![],
| Self::ConfigureWebDavRemote { .. }
| Self::GameNotes { .. } => vec![],
}
}

Expand Down Expand Up @@ -437,6 +451,20 @@ impl Modal {
ModalField::WebDavProvider,
));
}
Self::GameNotes { notes, .. } => {
col = notes.iter().fold(col, |parent, note| {
parent.push(
Row::new()
.push(Container::new(Icon::Info.text_narrow()).padding([2, 10, 0, 5]))
.push(
Column::new()
.spacing(5)
.push(text(&note.message).size(16))
.push_maybe(note.source.as_ref().map(|source| text(source).size(12))),
),
)
});
}
}

col
Expand All @@ -460,7 +488,8 @@ impl Modal {
| Self::UpdatingManifest
| Self::ConfigureFtpRemote { .. }
| Self::ConfigureSmbRemote { .. }
| Self::ConfigureWebDavRemote { .. } => (),
| Self::ConfigureWebDavRemote { .. }
| Self::GameNotes { .. } => (),
}
}

Expand Down Expand Up @@ -497,7 +526,8 @@ impl Modal {
| Self::UpdatingManifest
| Self::ConfigureFtpRemote { .. }
| Self::ConfigureSmbRemote { .. }
| Self::ConfigureWebDavRemote { .. } => (),
| Self::ConfigureWebDavRemote { .. }
| Self::GameNotes { .. } => (),
}
}

Expand All @@ -518,7 +548,8 @@ impl Modal {
| Self::UpdatingManifest
| Self::ConfigureFtpRemote { .. }
| Self::ConfigureSmbRemote { .. }
| Self::ConfigureWebDavRemote { .. } => (),
| Self::ConfigureWebDavRemote { .. }
| Self::GameNotes { .. } => (),
}
}

Expand All @@ -537,7 +568,8 @@ impl Modal {
| Self::UpdatingManifest
| Self::ConfigureFtpRemote { .. }
| Self::ConfigureSmbRemote { .. }
| Self::ConfigureWebDavRemote { .. } => false,
| Self::ConfigureWebDavRemote { .. }
| Self::GameNotes { .. } => false,
}
}

Expand All @@ -556,7 +588,8 @@ impl Modal {
| Self::UpdatingManifest
| Self::ConfigureFtpRemote { .. }
| Self::ConfigureSmbRemote { .. }
| Self::ConfigureWebDavRemote { .. } => 2,
| Self::ConfigureWebDavRemote { .. }
| Self::GameNotes { .. } => 2,
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/gui/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ pub enum Button {
NavButtonActive,
NavButtonInactive,
Badge,
Bare,
}
impl button::StyleSheet for Theme {
type Style = Button;
Expand All @@ -165,6 +166,7 @@ impl button::StyleSheet for Theme {
Self::Style::NavButtonActive => Some(self.navigation.alpha(0.9).into()),
Self::Style::NavButtonInactive => None,
Self::Style::Badge => None,
Self::Style::Bare => None,
},
border: Border {
color: match style {
Expand Down Expand Up @@ -193,7 +195,7 @@ impl button::StyleSheet for Theme {
text_color: match style {
Self::Style::GameListEntryTitleDisabled => self.text_skipped.alpha(0.8),
Self::Style::GameListEntryTitleUnscanned => self.text.alpha(0.8),
Self::Style::NavButtonInactive => self.text,
Self::Style::NavButtonInactive | Self::Style::Bare => self.text,
_ => self.text_button.alpha(0.8),
},
shadow: Shadow::default(),
Expand Down Expand Up @@ -225,6 +227,7 @@ impl button::StyleSheet for Theme {
text_color: match style {
Self::Style::GameListEntryTitleDisabled => self.text_skipped,
Self::Style::GameListEntryTitleUnscanned | Self::Style::NavButtonInactive => self.text,
Self::Style::Bare => self.text.alpha(0.9),
_ => self.text_button,
},
shadow_offset: match style {
Expand Down
16 changes: 12 additions & 4 deletions src/resource/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
path::CommonPath,
prelude::{app_dir, Error, StrictPath, AVAILABLE_PARALELLISM},
resource::{
manifest::{CloudMetadata, Manifest, Store},
manifest::{self, CloudMetadata, Manifest, Store},
ResourceFile, SaveableResourceFile,
},
scan::registry_compat::RegistryItem,
Expand Down Expand Up @@ -92,7 +92,7 @@ impl ManifestConfig {
.collect()
}

pub fn load_secondary_manifests(&self) -> Vec<(StrictPath, Manifest)> {
pub fn load_secondary_manifests(&self) -> Vec<manifest::Secondary> {
self.secondary
.iter()
.filter_map(|x| match x {
Expand All @@ -105,7 +105,11 @@ impl ManifestConfig {
if let Err(e) = &manifest {
log::error!("Cannot load secondary manifest: {:?} | {}", &path, e);
}
Some((path.clone(), manifest.ok()?))
Some(manifest::Secondary {
id: path.render(),
path: path.clone(),
data: manifest.ok()?,
})
}
SecondaryManifestConfig::Remote { url, enable } => {
if !enable {
Expand All @@ -117,7 +121,11 @@ impl ManifestConfig {
if let Err(e) = &manifest {
log::error!("Cannot load manifest: {:?} | {}", &path, e);
}
Some((path.clone(), manifest.ok()?))
Some(manifest::Secondary {
id: url.to_string(),
path: path.clone(),
data: manifest.ok()?,
})
}
})
.collect()
Expand Down
Loading

2 comments on commit 750056e

@nicolasnobelis
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a lot of changes !
Thanks a lot 🥲

@mtkennerly
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, no worries :)

Please sign in to comment.