meta_wearables_dat 0.1.2
meta_wearables_dat: ^0.1.2 copied to clipboard
Flutter plugin for Meta Wearables Device Access Toolkit (DAT), enabling registration, device state, camera streaming, and photo capture for Meta AI glasses.
import 'dart:async';
import 'dart:typed_data';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:meta_wearables_dat/meta_wearables_dat.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final wearables = Wearables.instance;
bool initialized = false;
RegistrationState? regState;
List<String> devices = const [];
String cameraPermission = 'Unknown';
String streamState = '—';
Uint8List? latestFrame;
String? lastError;
CapturedPhoto? lastPhoto;
StreamSubscription? _regSub;
StreamSubscription? _devSub;
StreamSubscription? _streamStateSub;
StreamSubscription? _frameSub;
@override
void initState() {
super.initState();
_regSub = wearables.registrationStateStream.listen(
(s) => setState(() => regState = s),
onError: (e) => setState(() => lastError = '$e'),
);
_devSub = wearables.devicesStream.listen(
(d) => setState(() => devices = d),
onError: (e) => setState(() => lastError = '$e'),
);
_streamStateSub = wearables.streamStateStream.listen(
(s) => setState(() => streamState = s),
);
_frameSub = wearables.videoFramesStream.listen(
(bytes) => setState(() => latestFrame = bytes),
);
}
@override
void dispose() {
_regSub?.cancel();
_devSub?.cancel();
_streamStateSub?.cancel();
_frameSub?.cancel();
super.dispose();
}
Future<void> _run(Future<void> Function() fn) async {
setState(() => lastError = null);
try {
await fn();
} on PlatformException catch (e) {
setState(() {
lastError =
'PlatformException: ${e.code} ${e.message} (${e.details})';
});
} catch (e) {
setState(() => lastError = '$e');
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Meta Wearables DAT – Test')),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_section('Status'),
_kv('Initialized', initialized.toString()),
_kv(
'Registration',
regState == null
? '—'
: '${regState!.state}${regState!.error != null ? ' (${regState!.error})' : ''}',
),
_kv('Devices', devices.join(', ')),
_kv('Camera permission', cameraPermission),
_kv('Stream state', streamState),
if (lastError != null) ...[
const SizedBox(height: 8),
Text(lastError!, style: const TextStyle(color: Colors.red)),
],
const Divider(),
_section('Core'),
ElevatedButton(
onPressed: () => _run(() async {
initialized = await wearables.initialize();
setState(() {});
}),
child: const Text('Initialize'),
),
ElevatedButton(
onPressed: () => _run(wearables.startRegistration),
child: const Text('Start Registration'),
),
ElevatedButton(
onPressed: () => _run(wearables.startUnregistration),
child: const Text('Start Unregistration'),
),
const Divider(),
_section('Camera permission'),
ElevatedButton(
onPressed: () => _run(() async {
cameraPermission =
await wearables.checkCameraPermission();
setState(() {});
}),
child: const Text('Check Camera Permission'),
),
ElevatedButton(
onPressed: () => _run(() async {
cameraPermission =
await wearables.requestCameraPermission();
setState(() {});
}),
child: const Text('Request Camera Permission'),
),
const Divider(),
_section('Streaming'),
ElevatedButton(
onPressed: () => _run(() async {
await wearables.startStream();
}),
child: const Text('Start Stream'),
),
ElevatedButton(
onPressed: () => _run(wearables.stopStream),
child: const Text('Stop Stream'),
),
const SizedBox(height: 8),
_framePreview(),
const Divider(),
_section('Photo'),
ElevatedButton(
onPressed: () => _run(() async {
lastPhoto = await wearables.capturePhoto();
setState(() {});
}),
child: const Text('Capture Photo'),
),
ElevatedButton(
onPressed: lastPhoto == null
? null
: () => _run(wearables.shareLastPhoto),
child: const Text('Share Last Photo'),
),
if (lastPhoto != null) ...[
const SizedBox(height: 8),
Text('Captured: ${lastPhoto!.mimeType}'),
Text(lastPhoto!.path),
const SizedBox(height: 8),
Image.file(File(lastPhoto!.path), height: 200),
],
],
),
),
),
),
);
}
Widget _framePreview() {
if (latestFrame == null) {
return const Text('No video frames yet');
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Live preview:'),
const SizedBox(height: 4),
Image.memory(
latestFrame!,
gaplessPlayback: true,
height: 200,
fit: BoxFit.contain,
),
],
);
}
Widget _section(String title) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Text(
title,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
);
}
Widget _kv(String k, String v) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
children: [
SizedBox(
width: 150,
child: Text(k, style: const TextStyle(fontWeight: FontWeight.w600)),
),
Expanded(child: Text(v)),
],
),
);
}
}