Код: Выделить всё
--------------
NSCameraUsageDescription
Camera access is needed to capture your photo for attendance submission.
NSLocationWhenInUseUsageDescription
This app uses your location to get current latitude and longitude to mark attendance accurately when the app is open.
----------------
Код: Выделить всё
void initState() {
super.initState();
// Important for iOS: wait for first frame before asking permissions
WidgetsBinding.instance.addPostFrameCallback((_) async {
await _checkGpsAndPermissions();
});
}
Future _initializeCamera() async {
try {
final cameras = await availableCameras();
if (cameras.isEmpty) {
debugPrint("No cameras found.");
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("No camera available on this device.")),
);
return;
}
final frontCamera = cameras.firstWhere(
(c) => c.lensDirection == CameraLensDirection.front,
orElse: () => cameras.first,
);
_cameraController = CameraController(frontCamera, ResolutionPreset.medium, enableAudio: false);
await _cameraController!.initialize();
if (mounted) setState(() => _isCameraInitialized = true);
debugPrint("Camera initialized successfully.");
} catch (e) {
debugPrint("Camera init error: $e");
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Camera failed to start: $e")),
);
}
}
}
Future _captureAndUpload() async {
if (_cameraController == null || !_cameraController!.value.isInitialized) return;
try {
setState(() => _isLoading = true);
final XFile rawImage = await _cameraController!.takePicture();
final File compressed = await _compressImage(File(rawImage.path));
final prefs = await SharedPreferences.getInstance();
final userId = prefs.getString("user_id") ?? "";
final token = prefs.getString("auth_token") ?? "";
final response = await _uploadImage(
file: compressed,
appUserCode: userId,
userId: userId,
token: "Bearer $token",
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
if (data["result"].toString() == "true") {
controller.attendanceMarking(
currentLat ?? "0.00",
currentLong ?? "0.00",
data["data"]![0]!["File_Info"].toString(),
Platform.isIOS ? "IOS DEVICE" : "ANDROID DEVICE",
);
Get.back();
Get.snackbar("Attendance Marked", "Successfully");
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Upload failed: ${data["Message"]}")),
);
}
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Server error: ${response.statusCode}")),
);
}
if (compressed.existsSync()) await compressed.delete();
} catch (e) {
debugPrint("Capture/upload error: $e");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Upload failed: $e")),
);
} finally {
setState(() => _isLoading = false);
}
}
Future _checkGpsAndPermissions() async {
final serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
_showGpsDialog();
return;
}
await _checkAllPermissions();
}
Future _checkAllPermissions() async {
try {
// Camera
var cameraStatus = await Permission.camera.status;
if (!cameraStatus.isGranted) cameraStatus = await Permission.camera.request();
if (!cameraStatus.isGranted) {
_showPermissionDialog("Camera access is required to take your attendance photo.");
return;
}
// Location (while-in-use only)
var locationPermission = await Geolocator.checkPermission();
if (locationPermission == LocationPermission.denied ||
locationPermission == LocationPermission.deniedForever) {
locationPermission = await Geolocator.requestPermission();
}
await Future.delayed(const Duration(milliseconds: 500));
if (locationPermission != LocationPermission.whileInUse &&
locationPermission != LocationPermission.always) {
_showPermissionDialog("Location access is required to record your attendance location.");
return;
}
await _getLocation();
await _initializeCamera();
} catch (e) {
debugPrint("Permission error: $e");
_showPermissionDialog("Permissions are needed to continue.");
}
}
void _showPermissionDialog(String message) {
if (!mounted) return;
showDialog(
context: context,
builder: (_) => AlertDialog(
title: const Text("Permission Required"),
content: Text(message),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
openAppSettings();
},
child: const Text("Open Settings"),
),
],
),
);
}
void _showGpsDialog() {
if (!mounted) return;
showDialog(
context: context,
builder: (_) => AlertDialog(
title: const Text("Enable GPS"),
content: const Text("Please enable GPS to continue."),
actions: [
TextButton(
onPressed: () async {
Navigator.pop(context);
await Geolocator.openLocationSettings();
},
child: const Text("OK"),
),
],
),
);
}
Future _getLocation() async {
try {
final pos = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
setState(() {
currentLat = pos.latitude.toString();
currentLong = pos.longitude.toString();
});
debugPrint("Latitude: $currentLat, Longitude: $currentLong");
} catch (e) {
debugPrint("Location error: $e");
}
}
Код: Выделить всё
camera: ^0.11.0+2 # For live camera capture (Android & iOS)
geolocator: ^10.1.0 # for location
permission_handler: ^11.3.0 # for runtime permission requests
Подробнее здесь: https://stackoverflow.com/questions/798 ... ios-device