TIFNGANJUK_E41212218/classifragise/lib/pages/camera_page.dart

339 lines
12 KiB
Dart

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:camera/camera.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:intl/intl.dart';
import 'package:image_cropper/image_cropper.dart';
import 'result_page.dart';
class CameraPage extends StatefulWidget {
const CameraPage({super.key});
@override
_CameraPageState createState() => _CameraPageState();
}
class _CameraPageState extends State<CameraPage> {
CameraController? _controller;
late List<CameraDescription> _cameras;
bool _isCameraInitialized = false;
bool _isUploading = false;
@override
void initState() {
super.initState();
_initializeCamera();
}
Future<void> _initializeCamera() async {
_cameras = await availableCameras();
_controller = CameraController(_cameras[0], ResolutionPreset.medium);
await _controller!.initialize();
if (!mounted) return;
setState(() {
_isCameraInitialized = true;
});
}
Future<void> _captureImage() async {
if (!_controller!.value.isInitialized) return;
final XFile imageFile = await _controller!.takePicture();
File? croppedImage = await _cropImage(File(imageFile.path));
if (croppedImage != null) {
final String date =
DateFormat('dd-MM-yyyy HH:mm:ss').format(DateTime.now());
_uploadImage(croppedImage, date);
} else {
print("❌ Cropping dibatalkan.");
}
}
Future<File?> _cropImage(File imageFile) async {
try {
final CroppedFile? croppedFile = await ImageCropper().cropImage(
sourcePath: imageFile.path,
compressFormat: ImageCompressFormat.jpg,
compressQuality: 80,
aspectRatioPresets: [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
],
uiSettings: [
AndroidUiSettings(
toolbarTitle: 'Crop Gambar',
toolbarColor: const Color(0xFF891A2D),
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false,
),
IOSUiSettings(title: 'Crop Gambar'),
],
);
return croppedFile != null ? File(croppedFile.path) : null;
} catch (e) {
print("❌ Error saat cropping gambar: $e");
return null;
}
}
Future<void> _uploadImage(File image, String date) async {
setState(() {
_isUploading = true;
});
var request = http.MultipartRequest(
'POST', Uri.parse('http://172.20.10.10:5000/predict'));
request.files.add(await http.MultipartFile.fromPath('file', image.path));
var response = await request.send();
if (response.statusCode == 200) {
var responseData = await response.stream.bytesToString();
var result = json.decode(responseData);
String prediction = result['prediction'];
setState(() {
_isUploading = false;
});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResultPage(
image: image,
date: date,
prediction: prediction,
),
),
);
} else {
setState(() {
_isUploading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Terjadi kesalahan. Coba lagi.")),
);
}
}
@override
void dispose() {
_controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFF891A2D), Color(0xFF891A2D)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
),
title: Text(
"Ambil Gambar",
style: GoogleFonts.poppins(
color: Colors.white,
// fontWeight: FontWeight.w600,
fontSize: 20,
),
),
centerTitle: true,
iconTheme: const IconThemeData(color: Colors.white),
),
body: Stack(
children: [
Column(
children: [
Expanded(
child: Stack(
children: [
// Tampilan Kamera
_isCameraInitialized
? CameraPreview(_controller!)
: const Center(child: CircularProgressIndicator()),
// Bingkai Panduan untuk Membantu Pengguna
// Center(
// child: Container(
// width: 300,
// height: 300,
// decoration: BoxDecoration(
// border: Border.all(
// color: Colors.white.withOpacity(0.7),
// width: 2,
// style: BorderStyle.solid,
// ),
// borderRadius: BorderRadius.circular(15),
// ),
// child: Center(
// child: Text(
// "Letakkan stroberi di sini",
// style: GoogleFonts.poppins(
// color: Colors.white.withOpacity(0.8),
// fontSize: 14,
// ),
// ),
// ),
// ),
// ),
// Petunjuk Penggunaan dan Tombol
Align(
alignment: Alignment.bottomCenter,
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(20),
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
spreadRadius: 5,
),
],
),
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Petunjuk Penggunaan dalam Kartu
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
color: Colors.grey[100],
child: Padding(
padding: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
const Icon(
Icons.info_outline,
color: Color(0xFF891A2D),
size: 24,
),
const SizedBox(width: 8),
Text(
"Petunjuk Penggunaan",
style: GoogleFonts.poppins(
fontSize: 18,
fontWeight: FontWeight.bold,
color: const Color(0xFF891A2D),
),
),
],
),
const SizedBox(height: 10),
Text(
"Arahkan kamera ke buah stroberi tanpa tangkai dalam pencahayaan yang baik untuk mendapatkan hasil terbaik",
textAlign: TextAlign.center,
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.black87,
height: 1.6,
),
),
],
),
),
),
const SizedBox(height: 20),
// Tombol Ambil Gambar dengan Animasi
TweenAnimationBuilder(
tween: Tween<double>(begin: 1.0, end: 1.0),
duration: const Duration(milliseconds: 200),
builder: (context, scale, child) {
return Transform.scale(
scale: scale,
child: child,
);
},
child: ElevatedButton.icon(
onPressed: _isUploading ? null : _captureImage,
icon: const Icon(
Icons.camera_alt,
size: 28,
color: Colors.white,
),
label: Text(
"Ambil Gambar",
style: GoogleFonts.poppins(
fontSize: 16,
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF891A2D),
padding: const EdgeInsets.symmetric(
vertical: 15, horizontal: 30),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
elevation: 5,
),
),
),
],
),
),
),
],
),
),
],
),
// Indikator Loading
if (_isUploading)
Container(
color: Colors.black.withOpacity(0.6),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(
color: Color(0xFF891A2D),
strokeWidth: 5,
),
const SizedBox(height: 15),
Text(
"Mengunggah Gambar...",
style: GoogleFonts.poppins(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
],
),
);
}
}