Media: a shaped corner follows the pointer up and down; the fitted crop is told once

With an aspect, a corner drag sizes the crop by whichever side the pointer
moved further, so a drag straight up or down resizes it too. The upload
tells the host the fitted crop once per file, whether the host keeps it or
not; a host that dropped it had set off a loop of reports. The annotator's
Escape stops only when it lets a chosen mark go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-09-26 16:38:22 -04:00
1 parent 7d86c804d7
commit cb28c0e305
5 files changed
+124 -26

No files matched your search

+13 -4
View File
@@ -17,6 +17,13 @@ use crate::{
type OnPath = Rc<dyn Fn(PathBuf, &mut Window, &mut App)>;
/// What the upload has said about a file: its fitted crop to the host, its failure to the log.
#[derive(Default)]
struct Told {
fitted: bool,
failed: bool,
}
/// A picture to send: a drop zone until one is chosen, then the picture to crop, its name, Replace and Remove. Only pictures are taken; the picture's shape comes from the file. The host keeps the file and its crop; with none yet, the upload reports the largest centered box of its aspect once the picture opens.
#[derive(IntoElement)]
pub struct ImageUpload {
@@ -80,10 +87,10 @@ impl RenderOnce for ImageUpload {
};
let decoded =
window.use_asset::<ImageAssetLoader>(&Resource::Path(path.clone().into()), cx);
let failed = window.use_keyed_state(
let told = window.use_keyed_state(
(self.id.clone(), path.to_string_lossy().into_owned()),
cx,
|_, _| false,
|_, _| Told::default(),
);
let name = path
.file_name()
@@ -102,15 +109,17 @@ impl RenderOnce for ImageUpload {
_ => None,
};
if let (Some((_, fitted)), None, Some(on_crop)) = (opened, self.crop, self.on_crop.clone())
&& !told.read(cx).fitted
{
log::info!("image upload: {name} opened, crop fitted to {fitted:?}");
told.update(cx, |told, _| told.fitted = true);
window.defer(cx, move |window, cx| on_crop(fitted, window, cx));
}
if let Some(Err(error)) = &decoded
&& !*failed.read(cx)
&& !told.read(cx).failed
{
log::error!("image upload: {name} can't be opened: {error}");
failed.update(cx, |failed, _| *failed = true);
told.update(cx, |told, _| told.failed = true);
}
let theme = cx.theme();
let colors = theme.colors.clone();