mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-14 17:32:00 +01:00
feat(gui,fuse,core): share photos, copy image, thumbnail strip in the viewer
- Share… in the grid's photo menu and the viewer's ⋮ menu opens the Share dialog by uid. The daemon accepts a uid from the Photos timeline for sharing (resolve_shareable), since the photos volume is in no mount. Photos in an album someone else shared are not offered. - Copy Image (Ctrl+C) puts the shown still on the clipboard. The viewer has its own toast overlay, so this and Save a Copy confirm over it instead of behind it. - A thumbnail strip along the viewer's bottom edge, on the gallery model, marks the shown photo and jumps on click. Several pictures can now wait for one thumbnail, so the strip and the grid tile don't steal it from each other. - PhotoItem carries place_id (serde default); the line under the viewer's title reads "Berlin · 12 of 340".
This commit is contained in:
1 parent
5f0b15fe70
commit
41212efdf3
24 files changed
+3307
-2780
No files matched your search
@@ -1792,6 +1792,11 @@ pub struct PhotoItem {
|
||||
/// the JPEG it shows is not the whole of what is stored.
|
||||
#[serde(default)]
|
||||
pub has_raw: bool,
|
||||
/// GeoNames id of the town the photo was taken in, when its location is
|
||||
/// known; [`crate::places::city`] names it. Older daemons omit it, and
|
||||
/// album entries do not carry it.
|
||||
#[serde(default)]
|
||||
pub place_id: Option<u32>,
|
||||
}
|
||||
|
||||
/// A daemon too old to classify a timeline entry is assumed to have served a
|
||||
|
||||
@@ -186,6 +186,8 @@ impl Db {
|
||||
// made, and it shows exactly what they put in it.
|
||||
group_size: 1,
|
||||
has_raw: false,
|
||||
// Album rows carry no location.
|
||||
place_id: None,
|
||||
})
|
||||
})?
|
||||
.collect::<rusqlite::Result<_>>()?;
|
||||
@@ -247,6 +249,8 @@ impl Db {
|
||||
// made, and it shows exactly what they put in it.
|
||||
group_size: 1,
|
||||
has_raw: false,
|
||||
// Album rows carry no location.
|
||||
place_id: None,
|
||||
})
|
||||
})?
|
||||
.collect::<rusqlite::Result<_>>()?;
|
||||
|
||||
@@ -40,6 +40,8 @@ pub struct StoredPhoto {
|
||||
/// Whether any member of the group is a camera raw file. The grid badges
|
||||
/// that, because the JPEG it shows is not the whole of what is stored.
|
||||
pub has_raw: bool,
|
||||
/// The town the photo was taken in, once its location has been read.
|
||||
pub place_id: Option<u32>,
|
||||
}
|
||||
|
||||
/// A town photos were taken in: its GeoNames id (see [`crate::places`]), how
|
||||
@@ -256,7 +258,7 @@ fn group_photos(entries: &[Grouped]) -> Vec<String> {
|
||||
/// own group: the column is `NULL` until the next refresh computes it, and a
|
||||
/// `NULL` would otherwise match nothing and drop the photo off the page.
|
||||
const PHOTO_SELECT: &str = "SELECT p.uid, p.capture_time, p.name, p.ratio, p.thumb_state, \
|
||||
p.kind, p.favorite, g.n, g.raw \
|
||||
p.kind, p.favorite, g.n, g.raw, p.place_id \
|
||||
FROM photos p JOIN (SELECT COALESCE(group_key, uid) AS k, COUNT(*) AS n, \
|
||||
MAX(kind = 2) AS raw FROM photos GROUP BY k) g ON g.k = COALESCE(p.group_key, p.uid)";
|
||||
|
||||
@@ -272,6 +274,7 @@ fn stored_photo(r: &rusqlite::Row<'_>) -> rusqlite::Result<StoredPhoto> {
|
||||
favorite: r.get::<_, i64>(6)? != 0,
|
||||
group_size: r.get::<_, i64>(7)?.max(1) as usize,
|
||||
has_raw: r.get::<_, i64>(8)? != 0,
|
||||
place_id: r.get(9)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -363,6 +363,23 @@ fn place_photos_carry_their_own_location() {
|
||||
);
|
||||
}
|
||||
|
||||
/// A timeline photo names the town it was taken in, so the viewer can show it;
|
||||
/// one without a location names none.
|
||||
#[test]
|
||||
fn timeline_photos_name_their_town() {
|
||||
let db = Db::open_in_memory().unwrap();
|
||||
db.photos_replace(&[
|
||||
located("b", 500, "IMG_5.JPG", BERLIN),
|
||||
TimelineRow::new("n", 400),
|
||||
])
|
||||
.unwrap();
|
||||
let berlin = db.photo_places().unwrap()[0].id;
|
||||
let mut photos = db.photos_by_uid(&["b".into(), "n".into()]).unwrap();
|
||||
photos.sort_by(|a, b| a.uid.cmp(&b.uid));
|
||||
let towns: Vec<Option<u32>> = photos.iter().map(|photo| photo.place_id).collect();
|
||||
assert_eq!(towns, [Some(berlin), None]);
|
||||
}
|
||||
|
||||
/// A refresh that skips an already-resolved photo keeps where it was taken; one
|
||||
/// that reads the node again takes what the node now says.
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user