The Garage SDKs, in the open

garage_auth, garage_entitlements, garage_iap and garage_ui, moved out of
Garage-Services and Metro-Map-Maker into one public repo. MIT, one readme,
docs under docs/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013F4NWNvYcdeSgqbWMT1VQ7
This commit is contained in:
ImBenji
2026-09-23 18:49:21 +01:00
co-authored by Claude Opus 5.5
commit b269201919
117 changed files with 26944 additions and 0 deletions
@@ -0,0 +1,50 @@
// ignore_for_file: avoid_web_libraries_in_flutter
import "dart:js_interop";
import "dart:js_interop_unsafe";
import "package:flutter/widgets.dart";
// EyeDropper is a chromium-only api at the time of writing (no firefox, no
// safari), hence the feature check rather than just assuming its there on web.
// https://developer.mozilla.org/en-US/docs/Web/API/EyeDropper
@JS("EyeDropper")
extension type _EyeDropper._(JSObject _) implements JSObject {
external _EyeDropper();
external JSPromise<_EyeDropperResult> open();
}
extension type _EyeDropperResult._(JSObject _) implements JSObject {
external String get sRGBHex;
}
Future<bool> nativeEyedropperAvailable() async =>
globalContext.has("EyeDropper");
Future<Color?> pickNativeScreenColor() async {
try {
final result = await _EyeDropper().open().toDart;
return _parseHex(result.sRGBHex);
} catch (error, stack) {
// cancelling with escape rejects the promise with an AbortError, so this
// path is completely normal - still worth a line in the console though.
debugPrint("eyedropper: web pick ended without a colour: $error\n$stack");
return null;
}
}
Color? _parseHex(String value) {
final hex = value.replaceAll("#", "");
if (hex.length != 6) {
debugPrint("eyedropper: unexpected sRGBHex \"$value\"");
return null;
}
final parsed = int.tryParse(hex, radix: 16);
if (parsed == null) {
debugPrint("eyedropper: could not parse sRGBHex \"$value\"");
return null;
}
return Color(0xFF000000 | parsed);
}