Photos
The photo library
requestAccess() works only in the app: a widget cannot show a permission sheet. iOS also offers limited access, where the user picks which photos an app can see. status reports it separately and reads simply return fewer assets. image() takes a maxSize because a widget is killed above roughly 30MB, and a full-size photo decodes to more than that.
Properties
statusString"authorized", "limited", "denied", "restricted" or "notDetermined".
isAuthorizedBooleanTrue for authorized and for limited.
Methods
Photos.requestAccess()StringShows the permission sheet. App only.
returns The status afterwards.
Photos.albums()[Any]Albums holding at least one item. Smart albums such as Favourites and Screenshots come first.
returns One { id, title, count } per album. Pass id to latest() or random().
Photos.latest(options)[Any]The newest assets first.
- options Any required
- count Number
How many. Defaults to 10.
- album String
An album id from albums(). Left out, the whole library.
- type String
"image" (default), "video" or "any".
- count Number
returns Each asset is { id, width, height, type, isFavorite, createdAt, latitude?, longitude? }.
Photos.random(options)AnyOne asset at random, or null if there are none.
- options Any required
- album String
An album id to pick from.
- type String
"image" (default), "video" or "any".
- album String
returns One asset, shaped as in latest(), or null when nothing matches.
Photos.image(asset, options)AnyLoads the pixels. Downloads from iCloud if the asset is not on the device.
- asset Any required
An asset from latest() or random(), or just its id.
- options Any required
- maxSize Number
Longest edge in pixels. Default 1024.
- maxSize Number
returns An image, ready for an Image node or for Vision.
Examples
A random photo, every hour
if (!Photos.isAuthorized) {
Script.setWidget(new Widget({ child: Text("Grant photo access in the app") }));
} else {
var pick = Photos.random();
Script.setWidget(new Widget({
refreshInterval: Duration.hours(1),
child: Image.from(Photos.image(pick, { maxSize: 600 }), { fit: BoxFit.cover }),
}));
}