designhubz 0.0.4 designhubz: ^0.0.4 copied to clipboard
DesignHubz TryOn Flutter Package
import 'package:designhubz/designhubz.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(
const MaterialApp(home: DesignHubzDemo()),
);
}
class DesignHubzDemo extends StatefulWidget {
const DesignHubzDemo({super.key});
@override
State<DesignHubzDemo> createState() => _DesignHubzDemoState();
}
class _DesignHubzDemoState extends State<DesignHubzDemo> {
/// Once the [TryOnWidget] is ready, it will provide the [TryOnController]
/// through its [onTryOnReady] callback, you can use this controller to set
/// userId, load product, switch context, take snapshot and fetch recommendations
late TryOnController _tryOnController;
/// In this example, [TryOnWidget] will not be shown until camera
/// permission is granted
bool isCameraPermissionGranted = false;
/// In this example, we are using a dummy user id and product id,
/// make sure to use your own user id and product id
String userId = "1234";
String productId = "000241-2906";
final List<String> statusUpdates = [];
/// [TryOnWidget] have many callbacks for different statuses like [onUpdateTrackingStatus]
/// and [onUserUpdateInfo] which we are showing above the [TryOnWidget] in this example
void addStatusUpdate(String status) {
setState(() {
statusUpdates.insert(0, status);
});
}
@override
void initState() {
_checkForCameraPermission();
super.initState();
}
/// before starting the [TryOnWidget] try-on mode, make sure to check for camera permission
/// and request for permission if not granted using [permission_handler](https://pub.dev/packages/permission_handler)
/// or any other such package package
_checkForCameraPermission() async {
final status = await Permission.camera.status;
if (status.isGranted) {
setState(() {
isCameraPermissionGranted = true;
});
} else {
final result = await Permission.camera.request();
setState(() {
isCameraPermissionGranted = result.isGranted;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Try-On Example'),
),
body: Stack(
children: [
Builder(builder: (context) {
if (!isCameraPermissionGranted) {
return const Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text(
'Camera Permission is required to use Try-On',
style: TextStyle(fontSize: 20),
),
),
);
}
return SafeArea(
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black, width: 3),
),
child: TryOnWidget(
/// make sure to provided your own organization id
organizationId: "23049412",
/// all these callbacks provide different statuses updates
/// In this example, we are showing it in UI through [buildStatusUpdatesWidget()]
onUpdateTrackingStatus: (trackingStatus) {
addStatusUpdate("Tracking Status: $trackingStatus");
},
onUpdateTryOnStatus: (tryOnStatus) {
addStatusUpdate("TryOn Status: $tryOnStatus");
},
onUpdateUserInfo: (userInfo) {
addStatusUpdate("User Info: $userInfo");
},
onError: (error) {
addStatusUpdate("Error: $error");
},
/// [onTryOnReady] will be called once the [TryOnWidget] is ready
onTryOnReady: (controller) {
/// save the controller for later use, see buttons in bottom of
/// the page for its usage
_tryOnController = controller;
},
),
),
);
}),
/// show the status updates in bottom of the page
Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
height: MediaQuery.of(context).size.height / 5,
child: buildStatusUpdatesWidget(),
),
),
// uncomment to show memory overlay
// buildMemoryOverlay(),
],
),
bottomNavigationBar: SafeArea(
child: Container(
padding: const EdgeInsets.all(8.0),
height: 60,
child: ListView(
scrollDirection: Axis.horizontal,
/// buttons to call different methods of [TryOnController]
children: [
buildSetUserIdWidgetButton(),
buildLoadProductButton(),
buildSwitchModeButton(),
buildRecommendationButton(),
buildTakeSnapshotButton(),
],
),
),
),
);
}
/// Sets the identifier that can pair with your user stats.
/// show a [SnackBar] to indicate success or failure
Widget buildSetUserIdWidgetButton() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: ElevatedButton(
onPressed: () async {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
initialValue: userId,
onChanged: (value) async {
userId = value;
},
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
try {
await _tryOnController.setUserId(userId);
if (mounted) {
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("User ID Set Successfully"),
),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Error:$e")));
}
},
child: const Text('Set User Id')),
],
));
});
},
child: const Text('Set User Id'),
),
);
}
/// load the product defined by [productId]
/// show a [SnackBar] to indicate loaded product detail or failure
Widget buildLoadProductButton() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: ElevatedButton(
onPressed: () async {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
initialValue: productId,
onChanged: (value) async {
productId = value;
},
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () async {
try {
final loadedProduct =
await _tryOnController.loadProduct(productId);
if (mounted) {
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
"Product Loaded Successfully $loadedProduct")),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Error:$e")));
}
},
child: const Text('Load Product')),
],
));
});
},
child: const Text('Load Product'),
),
);
}
/// Change the displayed mode from 3D to Eyewear Tryon
/// show a [SnackBar] to indicate switched mode or failure
Widget buildSwitchModeButton() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: ElevatedButton(
onPressed: () async {
try {
final switchedMode = await _tryOnController.switchMode();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Mode Switched $switchedMode"),
),
);
}
} catch (e) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Error:$e")));
}
},
child: const Text('Switch Mode'),
),
);
}
/// Get recommendations related to product
/// this widget show recommendations in a [Dialog]
Widget buildRecommendationButton() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: ElevatedButton(
onPressed: () async {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: FutureBuilder(
future: _tryOnController.fetchRecommendations(3),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.hasError) {
return Text("Error:${snapshot.error}");
}
final recommendations = snapshot.data;
if (recommendations == null ||
recommendations.isEmpty) {
return const Text("No Recommendations");
}
return Column(
mainAxisSize: MainAxisSize.min,
children: recommendations
.map((e) => Text(e.toString()))
.toList(),
);
} else {
return const Text(
"Loading...",
textAlign: TextAlign.center,
);
}
},
),
);
});
},
child: const Text('Recommendations'),
),
);
}
/// Take a snapshot of what is currently displayed in [TryOnWidget]
/// show a [Dialog] to show the captured image
Widget buildTakeSnapshotButton() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: ElevatedButton(
onPressed: () async {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: FutureBuilder(
future: _tryOnController.takeSnapshot(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.hasError) {
return Text("Error:${snapshot.error}");
}
final image = snapshot.data;
if (image == null) {
return const Text("No image captured");
}
/// after getting the snapshot, you can show it in the UI
/// through [Image.memory] like here, or upload it somewhere
return Image.memory(image);
} else {
return const Text(
"Loading...",
textAlign: TextAlign.center,
);
}
},
),
);
});
},
child: const Text('Take Snapshot'),
),
);
}
/// show status updates in a [ListView] from [TryOnWidget] callbacks
Widget buildStatusUpdatesWidget() {
return Container(
color: Colors.black.withOpacity(0.2),
child: ListView(
children: statusUpdates
.map(
(e) => Text(
e,
style: const TextStyle(color: Colors.white),
),
)
.toList(),
),
);
}
/// (Android only) show available memory and if device is low on
/// memory. Useful to evaluate TryOn on low-end devices
/// **not** a requirement to use [TryOnWidget]
Widget buildMemoryOverlay() {
return Align(
alignment: Alignment.topRight,
child: StreamBuilder(
stream: Stream.periodic(const Duration(seconds: 1)),
builder: (context, snapshot) {
return FutureBuilder(
future: TryonHelpers.getAndroidMemoryInfo(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final memInfo = snapshot.data;
if (memInfo == null) return Container();
return Container(
color: Colors.white.withOpacity(0.5),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Available Memory: ${memInfo.availableMemoryInMB} MB\nIs Low On Memory: ${memInfo.isLowOnMemory}",
),
),
);
} else {
return Container();
}
},
);
},
),
);
}
}