simple_native 0.0.8
simple_native: ^0.0.8 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))),
);
}
},
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),
),
),
],
),
),
],
),
);
}
}