simple_native 0.0.11
simple_native: ^0.0.11 copied to clipboard
A comprehensive Flutter plugin for accessing native device features including Camera, Location, and Device Information.
example/lib/main.dart
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:simple_native/simple_native.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
String _locationInfo = 'Unknown';
String _deviceInfo = 'Unknown';
final _simpleNativePlugin = SimpleNative();
@override
void initState() {
super.initState();
initPlatformState();
_getLocation();
}
Future<void> _getLocation() async {
String locationInfo;
try {
final location = await _simpleNativePlugin.getCurrentLocation();
locationInfo = location?.toString() ?? 'Location not available';
} on PlatformException {
locationInfo = 'Failed to get location.';
}
if (!mounted) return;
setState(() {
_locationInfo = locationInfo;
});
}
Future<void> _getDeviceInfo() async {
String deviceInfo;
try {
final info = await _simpleNativePlugin.getDeviceInfo();
deviceInfo = info?.toString() ?? 'Device info not available';
} on PlatformException {
deviceInfo = 'Failed to get device info.';
}
if (!mounted) return;
setState(() {
_deviceInfo = deviceInfo;
});
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
// We also handle the message potentially returning null.
try {
platformVersion = await _simpleNativePlugin.getPlatformVersion() ?? 'Unknown platform version';
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Plugin example app')),
body: Builder(
builder: (context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Running on: $_platformVersion\n'),
Text('Location: $_locationInfo\n'),
Text('Device info: $_deviceInfo\n'),
ElevatedButton(onPressed: _getLocation, child: const Text('Get Location')),
ElevatedButton(onPressed: _getDeviceInfo, child: const Text('Get Device Info')),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) => const CameraPage()));
},
child: const Text('Open Camera'),
),
],
),
);
},
),
),
);
}
}
class CameraPage extends StatefulWidget {
const CameraPage({super.key});
@override
State<CameraPage> createState() => _CameraPageState();
}
class _CameraPageState extends State<CameraPage> {
String? _result;
SimpleCameraController? _controller;
final ValueNotifier<Uint8List?> _vnPreviewImage = ValueNotifier(null);
bool _onConvert = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Camera View')),
body: Stack(
children: [
SimpleCameraView(
cameraType: SimpleCameraType.stream,
cameraPosition: SimpleCameraPosition.back,
onCameraCreated: (controller) {
// controller.onImageStream((image) async {
// // if (_onConvert) return;
// // _onConvert = true;
// // print('Received image: ${image.width}x${image.height}');
// // print('Image format: ${image.format}');
//
// // Use the new toImage() method from SimpleCameraImage
// // _vnPreviewImage.value = image.toImage();
//
// // await Future.delayed(const Duration(milliseconds: 100)); // Reduced delay for smoother preview
// // _onConvert = false;
// });
_controller = controller;
},
onResult: (result) {
// setState(() {
// _result = result.toString();
// });
// if (result.type == SimpleCameraResultType.qr) {
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text('QR Code: ${result.value}'),
// action: SnackBarAction(
// label: 'Resume',
// onPressed: () {
// _controller?.resumeScanning();
// },
// ),
// ),
// );
// }
},
),
if (_result != null)
Positioned(
bottom: 100 + MediaQuery.viewPaddingOf(context).bottom,
left: 20,
right: 20,
child: Container(
padding: const EdgeInsets.all(8),
color: Colors.black54,
child: Text(_result!, style: const TextStyle(color: Colors.white)),
),
),
Positioned(
bottom: 30 + MediaQuery.viewPaddingOf(context).bottom,
left: 0,
right: 0,
child: Center(
child: FloatingActionButton(
onPressed: () async {
final path = await _controller?.takePicture();
if (path != null && context.mounted) {
showDialog(
context: context,
builder: (context) => Dialog.fullscreen(child: Image.file(File(path))),
);
} else {
print('Không chụp được ảnh');
}
},
child: const Icon(Icons.camera),
),
),
),
Positioned(
top: 20,
right: 20,
child: Column(
children: [
FloatingActionButton(
heroTag: "switch_camera",
mini: true,
onPressed: () {
_controller?.switchCamera();
},
child: const Icon(Icons.switch_camera),
),
const SizedBox(height: 10),
ValueListenableBuilder(
valueListenable: _vnPreviewImage,
builder: (context, value, child) => value == null
? const SizedBox.shrink()
: Container(
decoration: BoxDecoration(border: Border.all(color: Colors.white, width: 2)),
child: Image.memory(value, width: 100),
),
),
],
),
),
],
),
);
}
}