import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:image_picker/image_picker.dart'; class TambahEdukasiBumilPage extends StatefulWidget { const TambahEdukasiBumilPage({super.key}); @override State createState() => _TambahEdukasiBumilPageState(); } class _TambahEdukasiBumilPageState extends State { final _formKey = GlobalKey(); final TextEditingController _judulController = TextEditingController(); // Menggunakan TextEditingController biasa untuk deskripsi final TextEditingController _deskripsiController = TextEditingController(); bool isSubmitting = false; File? selectedImage; Uint8List? webImage; final picker = ImagePicker(); final String urlTambah = "http://ta.myhost.id/E31230549/mposyandu_api/edukasi_ibu_hamil/tambah_edukasi_ibu_hamil.php"; Future pickImage() async { final picked = await picker.pickImage( source: ImageSource.gallery, imageQuality: 80, ); if (picked == null) return; if (kIsWeb) { webImage = await picked.readAsBytes(); } else { selectedImage = File(picked.path); } setState(() {}); } Future _simpanData() async { if (!_formKey.currentState!.validate()) return; if (selectedImage == null && webImage == null) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Silakan pilih gambar terlebih dahulu")), ); return; } setState(() => isSubmitting = true); try { var request = http.MultipartRequest("POST", Uri.parse(urlTambah)); request.fields["judul"] = _judulController.text; // Mengirim deskripsi sebagai teks biasa (mendukung enter/newline) request.fields["deskripsi"] = _deskripsiController.text; if (selectedImage != null) { request.files.add( await http.MultipartFile.fromPath("gambar", selectedImage!.path)); } if (webImage != null) { request.files.add(http.MultipartFile.fromBytes("gambar", webImage!, filename: "upload.jpg")); } var response = await request.send(); var res = await http.Response.fromStream(response); var data = jsonDecode(res.body); if (data["status"] == "success") { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Edukasi berhasil ditambahkan")), ); Navigator.pop(context); } } catch (e) { ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text("Error: $e"))); } finally { if (mounted) setState(() => isSubmitting = false); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF5F5F5), appBar: AppBar( title: const Text(""), backgroundColor: Colors.blue, elevation: 0, centerTitle: true, iconTheme: const IconThemeData(color: Colors.white), ), body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Center( child: Container( constraints: const BoxConstraints(maxWidth: 900), child: Card( elevation: 3, color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), child: Padding( padding: const EdgeInsets.all(25), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Text( "Tambah Edukasi Ibu Hamil", style: GoogleFonts.poppins( fontSize: 18, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 10), const Divider(), const SizedBox(height: 20), _buildImageSection(), const SizedBox(height: 30), _buildLabel("Judul Edukasi"), _buildTextField( _judulController, "Contoh: Perawatan ibu hamil", 1), const SizedBox(height: 25), _buildLabel("Deskripsi (Gunakan Enter untuk baris baru)"), // Field deskripsi yang mendukung ENTER _buildTextField(_deskripsiController, "Tulis isi edukasi di sini...", 10), const SizedBox(height: 35), _buildSubmitButton(), ], ), ), ), ), ), ), ), ); } // Widget TextField Universal (bisa satu baris atau banyak baris) Widget _buildTextField( TextEditingController controller, String hint, int maxLines) { return TextFormField( controller: controller, maxLines: maxLines, // Jika > 1, maka fungsi ENTER aktif secara otomatis keyboardType: maxLines > 1 ? TextInputType.multiline : TextInputType.text, style: GoogleFonts.poppins(fontSize: 14), decoration: InputDecoration( hintText: hint, filled: true, fillColor: Colors.white, contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 12), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: Colors.grey.shade300), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: Colors.grey.shade300), ), ), validator: (value) => value == null || value.isEmpty ? "Wajib diisi" : null, ); } // ... (Widget _buildImageSection, _buildSubmitButton, _buildLabel tetap sama) // [Kode _buildImageSection dll disingkat karena sama dengan aslinya] Widget _buildImageSection() { return Center( child: Column( children: [ _buildLabel("Gambar Edukasi"), InkWell( onTap: pickImage, child: Container( height: 200, width: 350, decoration: BoxDecoration( color: Colors.grey[50], borderRadius: BorderRadius.circular(10), border: Border.all(color: Colors.grey.shade300), ), child: selectedImage != null || webImage != null ? ClipRRect( borderRadius: BorderRadius.circular(10), child: kIsWeb ? Image.memory(webImage!, fit: BoxFit.cover) : Image.file(selectedImage!, fit: BoxFit.cover), ) : Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.add_a_photo, size: 40, color: Colors.blue), const SizedBox(height: 8), Text( "Klik untuk pilih gambar", style: GoogleFonts.poppins( fontSize: 12, color: Colors.grey), ), ], ), ), ), ], ), ); } Widget _buildSubmitButton() { return SizedBox( width: double.infinity, height: 50, child: ElevatedButton( onPressed: isSubmitting ? null : _simpanData, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), child: isSubmitting ? const CircularProgressIndicator(color: Colors.white) : Text( "Simpan Edukasi", style: GoogleFonts.poppins( fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ); } Widget _buildLabel(String text) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: Text( text, style: GoogleFonts.poppins( fontSize: 13, fontWeight: FontWeight.bold, color: Colors.black87, ), ), ); } }