Skip to content

Commit eeaf920

Browse files
committed
misc: disable CTRL+O hotkey in A/B mode
misc: improve corrupt image logging
1 parent 322c1d4 commit eeaf920

File tree

1 file changed

+75
-43
lines changed

1 file changed

+75
-43
lines changed

refract/src/app.rs

Lines changed: 75 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ impl App {
345345
else { Task::done(Message::NextImage) }
346346
}
347347

348+
#[expect(clippy::too_many_lines, reason = "There's a lot to update. Haha.")]
348349
/// # Update.
349350
///
350351
/// This method serves as the entrypoint for the application's
@@ -406,7 +407,7 @@ impl App {
406407
self.flags &= ! OTHER_BSIDE;
407408
self.current = None;
408409
while let Some(src) = self.paths.pop_first() {
409-
if let Some(mut current) = CurrentImage::new(src, self.flags) {
410+
if let Some(mut current) = CurrentImage::new(src.clone(), self.flags) {
410411
// Add an entry for it.
411412
cli_log(&current.src, None);
412413
self.done.push(ImageResults {
@@ -423,6 +424,13 @@ impl App {
423424
return self.update_switch_encoder__();
424425
}
425426
}
427+
// Decode error?
428+
else {
429+
cli_log_sad(&src);
430+
if self.paths.is_empty() {
431+
return Task::done(Message::Error(MessageError::NoImages));
432+
}
433+
}
426434
}
427435

428436
// If we're here, there are no more images. If --exit-auto,
@@ -548,16 +556,8 @@ impl App {
548556
/// This method sets up listeners for the program's keyboard shortcuts,
549557
/// bubbling up `Message`s as needed.
550558
pub(super) fn subscription(&self) -> Subscription<Message> {
551-
let whenever = iced::keyboard::on_key_press(subscribe_whenever);
552-
553-
// Some actions are only applicable in A/B contexts.
554-
if self.has_candidate() {
555-
Subscription::batch(vec![
556-
whenever,
557-
iced::keyboard::on_key_press(subscribe_ab),
558-
])
559-
}
560-
else { whenever }
559+
if self.has_candidate() { iced::keyboard::on_key_press(subscribe_ab) }
560+
else { iced::keyboard::on_key_press(subscribe_home) }
561561
}
562562

563563
/// # View.
@@ -697,7 +697,6 @@ impl App {
697697
.width(Fill)
698698
}
699699

700-
#[expect(clippy::too_many_lines, reason = "There's lots to do!")]
701700
/// # View: Activity Log.
702701
///
703702
/// This returns a table containing detailed information about each of the
@@ -738,8 +737,7 @@ impl App {
738737
// The rows, interspersed with dividers for each new source.
739738
let mut last_dir = OsStr::new("");
740739
for ActivityTableRow { src, kind, quality, len, ratio, time } in &table.0 {
741-
let Some(dir) = src.parent().map(Path::as_os_str) else { continue; };
742-
let Some(file) = src.file_name() else { continue; };
740+
let Some((dir, file)) = split_path(src) else { continue; };
743741
let is_src = matches!(kind, ImageKind::Png | ImageKind::Jpeg);
744742
let skipped = is_src && time.is_some();
745743
let color =
@@ -1246,16 +1244,12 @@ impl App {
12461244

12471245
column!(
12481246
// Path.
1249-
rich_text!(
1250-
span(format!(
1251-
"{}/",
1252-
current.src.parent().map_or(Cow::Borrowed(""), Path::to_string_lossy)
1253-
))
1254-
.color(NiceColors::GREY),
1255-
span(
1256-
current.src.file_name().map_or(Cow::Borrowed(""), |o| o.to_string_lossy()).into_owned()
1257-
)
1258-
.color(fg),
1247+
split_path(&current.src).map_or_else(
1248+
Rich::new,
1249+
|(dir, name)| rich_text!(
1250+
span(format!("{}/", dir.to_string_lossy())).color(NiceColors::GREY),
1251+
span(name.to_string_lossy().into_owned()).color(fg),
1252+
),
12591253
),
12601254

12611255
// Formats.
@@ -1994,12 +1988,14 @@ impl ImageResultWrapper {
19941988

19951989
// Update the path if they picked one.
19961990
if let Some(dst) = dst {
1997-
self.dst = crate::with_ng_extension(dst.path().to_path_buf(), self.kind);
1991+
let dst = dst.path().to_path_buf();
1992+
if dst.parent().is_some_and(Path::is_dir) && dst.file_name().is_some() {
1993+
self.dst = crate::with_ng_extension(dst, self.kind);
1994+
}
1995+
else { self.best = None; }
19981996
}
19991997
// Or nuke the result.
2000-
else {
2001-
let _res = self.best.take();
2002-
}
1998+
else { self.best = None; }
20031999

20042000
// Return for saving.
20052001
Message::SaveImage(self)
@@ -2167,13 +2163,12 @@ impl Default for WidgetCache {
21672163
///
21682164
/// Print a quick timestamped message to STDERR in case anybody's watching.
21692165
fn cli_log(src: &Path, quality: Option<Quality>) {
2170-
let Some(dir) = src.parent() else { return; };
2171-
let Some(name) = src.file_name() else { return; };
2166+
let Some((dir, name)) = split_path(src) else { return; };
21722167
let now = FmtUtc2k::now_local();
21732168
let mut out = format!(
21742169
"\x1b[2m[\x1b[0;34m{}\x1b[0;2m] {}/\x1b[0m{} \x1b[2m(",
21752170
now.time(),
2176-
dir.display(),
2171+
dir.to_string_lossy(),
21772172
name.to_string_lossy(),
21782173
);
21792174

@@ -2193,14 +2188,13 @@ fn cli_log(src: &Path, quality: Option<Quality>) {
21932188
///
21942189
/// Print a quick timestamped summary of a failed conversion to STDERR.
21952190
fn cli_log_sad(src: &Path) {
2196-
let Some(dir) = src.parent() else { return; };
2197-
let Some(name) = src.file_name() else { return; };
2191+
let Some((dir, name)) = split_path(src) else { return; };
21982192
let now = FmtUtc2k::now_local();
21992193

22002194
eprintln!(
22012195
"\x1b[2m[\x1b[0;34m{}\x1b[0;2m]\x1b[91m {}/\x1b[0;91m{}\x1b[0m",
22022196
now.time(),
2203-
dir.display(),
2197+
dir.to_string_lossy(),
22042198
name.to_string_lossy(),
22052199
);
22062200
}
@@ -2217,11 +2211,21 @@ fn cli_log_error(src: MessageError) {
22172211
);
22182212
}
22192213

2220-
/// # General Subscriptions.
2214+
/// # Split Path.
22212215
///
2222-
/// This callback for `on_key_press` binds listeners for the night mode
2223-
/// and file dialogue titles, which can be triggered at any time.
2224-
fn subscribe_whenever(key: Key, modifiers: Modifiers) -> Option<Message> {
2216+
/// Split the `parent` and `file_name`, returning `None` if either fail for
2217+
/// whatever reason.
2218+
fn split_path(src: &Path) -> Option<(&OsStr, &OsStr)> {
2219+
let dir = src.parent()?;
2220+
let name = src.file_name()?;
2221+
Some((dir.as_os_str(), name))
2222+
}
2223+
2224+
/// # Home Subscriptions.
2225+
///
2226+
/// This callback for `on_key_press` binds listeners for events available on
2227+
/// the home screen.
2228+
fn subscribe_home(key: Key, modifiers: Modifiers) -> Option<Message> {
22252229
// These require CTRL and not ALT.
22262230
if modifiers.command() && ! modifiers.alt() {
22272231
if let Key::Character(c) = key {
@@ -2235,15 +2239,23 @@ fn subscribe_whenever(key: Key, modifiers: Modifiers) -> Option<Message> {
22352239

22362240
/// # A/B Subscriptions.
22372241
///
2238-
/// This callback for `on_key_press` binds listeners for A/B-related
2239-
/// feedback, applicable only when a candidate image is available, though we
2240-
/// can't actually guarantee that's when they'll be triggered.
2242+
/// This callback for `on_key_press` binds listeners for events available on
2243+
/// the A/B screen.
22412244
fn subscribe_ab(key: Key, modifiers: Modifiers) -> Option<Message> {
2242-
// No modifiers required or expected.
2243-
if modifiers.command() || modifiers.alt() { None }
2245+
// Nothing needs ALT.
2246+
if modifiers.alt() { None }
2247+
// CTRL+N toggles Night Mode.
2248+
else if modifiers.command() {
2249+
if let Key::Character(c) = key {
2250+
if c == "n" { return Some(Message::ToggleFlag(OTHER_NIGHT)); }
2251+
}
2252+
None
2253+
}
22442254
else {
22452255
match key {
2256+
// Toggle A/B.
22462257
Key::Named(Named::Space) => Some(Message::ToggleFlag(OTHER_BSIDE)),
2258+
// Feedback.
22472259
Key::Character(c) =>
22482260
if c == "d" { Some(Message::Feedback(false)) }
22492261
else if c == "k" { Some(Message::Feedback(true)) }
@@ -2252,3 +2264,23 @@ fn subscribe_ab(key: Key, modifiers: Modifiers) -> Option<Message> {
22522264
}
22532265
}
22542266
}
2267+
2268+
2269+
2270+
#[cfg(test)]
2271+
mod test {
2272+
use super::*;
2273+
2274+
#[test]
2275+
fn t_flags() {
2276+
// Make sure the flags are actually unique.
2277+
let all = [
2278+
FMT_AVIF, FMT_JXL, FMT_WEBP,
2279+
MODE_LOSSLESS, MODE_LOSSY, MODE_LOSSY_YCBCR,
2280+
OTHER_BSIDE, OTHER_EXIT_AUTO, OTHER_NIGHT, OTHER_SAVE_AUTO,
2281+
SWITCHED_ENCODER,
2282+
];
2283+
let set = all.iter().copied().collect::<BTreeSet<u16>>();
2284+
assert_eq!(all.len(), set.len());
2285+
}
2286+
}

0 commit comments

Comments
 (0)