TIFNGANJUK_E41212218/classifragise/lib/pages/pilih_gambar_page.dart

293 lines
10 KiB
Dart

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:image_picker/image_picker.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'; // Import ResultPage
class SelectImagePage extends StatefulWidget {
const SelectImagePage({super.key});
@override
State<SelectImagePage> createState() => _SelectImagePageState();
}
class _SelectImagePageState extends State<SelectImagePage> {
File? _selectedImage;
bool _isUploading = false;
final String apiUrl = "http://172.20.10.10:5000/predict";
Future<void> _pickImage() async {
final pickedFile =
await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
File? croppedImage = await _cropImage(File(pickedFile.path));
if (croppedImage != null) {
setState(() {
_selectedImage = croppedImage;
_isUploading = true;
});
_uploadImage(croppedImage);
}
} else {
print("❌ Gambar tidak dipilih.");
}
}
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) async {
try {
var request = http.MultipartRequest('POST', Uri.parse(apiUrl));
request.files.add(await http.MultipartFile.fromPath('file', image.path));
var response = await request.send();
print("📡 Status Code: ${response.statusCode}");
if (response.statusCode == 200) {
var responseData = await response.stream.bytesToString();
var result = json.decode(responseData);
print("✅ Response dari API: $responseData");
setState(() =>
_isUploading = false); // Sembunyikan loading setelah upload selesai
// Navigasi ke ResultPage dengan hasil prediksi & gambar yang sudah di-crop
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResultPage(
image: image, // Kirim gambar ke ResultPage
prediction: result['prediction'] ?? "-",
date: DateFormat('dd MMM yyyy, HH:mm').format(DateTime.now()),
),
),
);
} else {
print("❌ Error Response: ${await response.stream.bytesToString()}");
setState(() => _isUploading = false);
}
} catch (e) {
print("⚠️ Exception: $e");
setState(() => _isUploading = false);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white, // Latar belakang putih
appBar: AppBar(
backgroundColor: const Color(0xFF891A2D),
title: Text(
"Pilih Gambar",
style: GoogleFonts.poppins(color: Colors.white),
),
centerTitle: true,
iconTheme: const IconThemeData(color: Colors.white),
),
body: SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Area Gambar dengan Efek Kartu
Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
width: double.infinity,
height: 280,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.grey[200],
),
child: _selectedImage != null
? ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.file(
_selectedImage!,
width: double.infinity,
height: 280,
fit: BoxFit.cover,
),
)
: const Center(
child: Icon(
Icons.image_outlined,
size: 100,
color: Colors.black26,
),
),
),
),
const SizedBox(height: 20),
// Tampilkan Loading dengan Animasi
if (_isUploading)
Column(
children: [
const CircularProgressIndicator(
color: const Color(0xFF891A2D),
strokeWidth: 5,
),
const SizedBox(height: 15),
Text(
"Mengunggah Gambar...",
style: GoogleFonts.poppins(
fontSize: 16,
color: const Color.fromARGB(255, 0, 0, 0),
fontWeight: FontWeight.w500,
),
),
],
),
const SizedBox(height: 25),
// Petunjuk Penggunaan dalam Kartu
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
color: Colors.grey[
100], // Warna latar belakang seperti StrawberryInfoPage
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), // Warna merah tema
size: 24,
),
const SizedBox(width: 8),
Text(
"Petunjuk Penggunaan",
style: GoogleFonts.poppins(
fontSize: 18,
fontWeight: FontWeight.bold,
color:
const Color(0xFF891A2D), // Warna merah tema
),
),
],
),
const SizedBox(height: 10),
Text(
"• Klik tombol 'Pilih dari Galeri' untuk memilih gambar.\n"
"• Crop gambar pada bagian buah stroberi, hilangkan tangkainya, lalu tekan 'Simpan'.\n"
"• Tunggu proses upload hingga selesai.\n"
"• Hasil prediksi akan ditampilkan di halaman berikutnya.",
textAlign: TextAlign.left,
style: GoogleFonts.poppins(
fontSize: 14,
color: Colors.black87,
height: 1.6,
),
),
],
),
),
),
const SizedBox(height: 30),
// Tombol Pilih 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(
onPressed: _pickImage,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF891A2D),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
padding: const EdgeInsets.symmetric(
vertical: 15, horizontal: 40),
elevation: 5,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.photo_library,
color: Colors.white,
size: 24,
),
const SizedBox(width: 10),
Text(
"Pilih dari Galeri",
style: GoogleFonts.poppins(
fontSize: 16,
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
],
),
),
),
),
);
}
}