UPDATE BAGIAN VIEW JADI CLEAN DAN ADA MODE MALAM/HARI 😱
serta juga menguser friendlykan UI nya dari yang ngantuk banget jadi wow GG ❤️🔥
.
1.1. NGODING TIPIS-TIPIS DI ⛑️
/lib/main.dart
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'views/mahasiswa_list.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ThemeMode _themeMode = ThemeMode.dark; // Default theme
void toggleTheme() {
setState(() {
_themeMode =
_themeMode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'CRUD Mahasiswa',
theme: ThemeData(
primarySwatch: Colors.purple,
scaffoldBackgroundColor: const Color(0xFFE1BEE7), // Ungu muda terang
textTheme: const TextTheme(
bodyMedium: TextStyle(
fontFamily: 'Roboto',
fontSize: 16,
color: Colors.black, // Teks hitam
),
),
),
darkTheme: ThemeData(
brightness: Brightness.dark,
primarySwatch: Colors.purple,
scaffoldBackgroundColor: const Color(0xFF4A148C), // Ungu gelap pekat
textTheme: const TextTheme(
bodyMedium: TextStyle(
fontFamily: 'Roboto',
fontSize: 16,
color: Colors.white, // Teks putih
),
),
),
themeMode: _themeMode,
home: MahasiswaListView(onThemeToggle: toggleTheme),
);
}
}
1.2. NGODING TIPIS-TIPIS DI 📋
/lib/view/mahasiswa_list.dart
import 'package:flutter/material.dart';
import '../models/mahasiswa_model.dart';
import '../services/mahasiswa_service.dart';
import 'mahasiswa_add.dart';
import 'mahasiswa_detail.dart';
class MahasiswaListView extends StatefulWidget {
final VoidCallback onThemeToggle; // Tambahkan callback untuk mengganti tema
const MahasiswaListView({super.key, required this.onThemeToggle});
@override
State<MahasiswaListView> createState() => _MahasiswaListViewState();
}
class _MahasiswaListViewState extends State<MahasiswaListView> {
final MahasiswaService _service = MahasiswaService();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'📝DATA 👨🏻🎓 & 👩🏻🎓 🏫',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
actions: [
IconButton(
icon: const Icon(Icons.brightness_6),
onPressed:
widget.onThemeToggle, // Panggil fungsi untuk mengganti tema
),
],
),
body: FutureBuilder<List<Mahasiswa>>(
future: _service.fetchMahasiswa(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
final mahasiswaList = snapshot.data ?? [];
if (mahasiswaList.isEmpty) {
return const Center(child: Text('Belum ada data mahasiswa.'));
}
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemCount: mahasiswaList.length,
itemBuilder: (context, index) {
final mahasiswa = mahasiswaList[index];
return Card(
margin: const EdgeInsets.only(bottom: 12.0),
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: ListTile(
contentPadding: const EdgeInsets.all(16.0),
title: Text(
mahasiswa.nama,
style: const TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text('NIM: ${mahasiswa.nim}'),
trailing: const Icon(Icons.chevron_right),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
MahasiswaDetailView(mahasiswa: mahasiswa),
),
);
},
),
);
},
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const MahasiswaAddView()),
).then((_) => setState(() {})); // Refresh after adding
},
child: const Icon(Icons.add),
),
);
}
}
1.3. NGODING TIPIS-TIPIS DI ➕
/lib/view/mahasiswa_add.dart
import 'package:flutter/material.dart';
import '../models/mahasiswa_model.dart';
import '../services/mahasiswa_service.dart';
class MahasiswaAddView extends StatefulWidget {
const MahasiswaAddView({super.key});
@override
State<MahasiswaAddView> createState() => _MahasiswaAddViewState();
}
class _MahasiswaAddViewState extends State<MahasiswaAddView> {
final _formKey = GlobalKey<FormState>();
final MahasiswaService _service = MahasiswaService();
final _namaController = TextEditingController();
final _nimController = TextEditingController();
final _prodiController = TextEditingController();
final _jurusanController = TextEditingController();
void _saveMahasiswa() {
if (_formKey.currentState!.validate()) {
final newMahasiswa = Mahasiswa(
id: '',
nama: _namaController.text,
nim: _nimController.text,
prodi: _prodiController.text,
jurusan: _jurusanController.text,
);
_service.addMahasiswa(newMahasiswa).then((_) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Data berhasil ditambahkan.')));
Navigator.pop(context);
}).catchError((error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Gagal menyimpan data: $error')),
);
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('📝TAMBAH DATA 👨🏻🎓 & 👩🏻🎓',
style: TextStyle(
fontWeight: FontWeight.bold,
)),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _namaController,
decoration: InputDecoration(
labelText: 'Nama',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
),
validator: (value) =>
value!.isEmpty ? 'Nama tidak boleh kosong' : null,
),
SizedBox(height: 20),
TextFormField(
controller: _nimController,
decoration: InputDecoration(
labelText: 'NIM',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
),
validator: (value) =>
value!.isEmpty ? 'NIM tidak boleh kosong' : null,
),
SizedBox(height: 20),
TextFormField(
controller: _prodiController,
decoration: InputDecoration(
labelText: 'Prodi',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
),
),
SizedBox(height: 20),
TextFormField(
controller: _jurusanController,
decoration: InputDecoration(
labelText: 'Jurusan',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _saveMahasiswa,
child: const Text('Simpan'),
),
],
),
),
),
);
}
}
1.4. NGODING TIPIS-TIPIS DI 👀
/lib/view/mahasiswa_detail.dart
import 'package:flutter/material.dart';
import '../models/mahasiswa_model.dart';
import 'mahasiswa_edit.dart';
import '../services/mahasiswa_service.dart';
class MahasiswaDetailView extends StatelessWidget {
final Mahasiswa mahasiswa;
const MahasiswaDetailView({super.key, required this.mahasiswa});
@override
Widget build(BuildContext context) {
final MahasiswaService _service = MahasiswaService();
return Scaffold(
appBar: AppBar(
title: Text(
mahasiswa.nama,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
actions: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MahasiswaEditView(mahasiswa: mahasiswa),
),
).then((_) => Navigator.pop(context)); // Refresh on back
},
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
_service.deleteMahasiswa(mahasiswa.id).then((_) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Data berhasil dihapus.')),
);
Navigator.pop(context);
}).catchError((error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Gagal menghapus data: $error')),
);
});
},
),
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
elevation: 5,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CircleAvatar(
radius: 50,
backgroundColor: Theme.of(context).primaryColor,
child: const Icon(
Icons.person,
size: 50,
color: Colors.white,
),
),
const SizedBox(height: 16),
Text(
mahasiswa.nama,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
'NIM: ${mahasiswa.nim}',
style: const TextStyle(fontSize: 16),
),
],
),
),
),
const SizedBox(height: 16),
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
elevation: 3,
child: ListTile(
leading: const Icon(Icons.school, color: Colors.purple),
title: const Text('Prodi'),
subtitle: Text(mahasiswa.prodi),
),
),
const SizedBox(height: 8),
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
elevation: 3,
child: ListTile(
leading: const Icon(Icons.account_balance, color: Colors.teal),
title: const Text('Jurusan'),
subtitle: Text(mahasiswa.jurusan),
),
),
],
),
),
);
}
}
1.5. NGODING TIPIS-TIPIS DI ✏️
/lib/view/mahasiswa_edit.dart
import 'package:flutter/material.dart';
import '../models/mahasiswa_model.dart';
import '../services/mahasiswa_service.dart';
class MahasiswaEditView extends StatefulWidget {
final Mahasiswa mahasiswa;
const MahasiswaEditView({super.key, required this.mahasiswa});
@override
State<MahasiswaEditView> createState() => _MahasiswaEditViewState();
}
class _MahasiswaEditViewState extends State<MahasiswaEditView> {
final _formKey = GlobalKey<FormState>();
final _namaController = TextEditingController();
final _nimController = TextEditingController();
final _prodiController = TextEditingController();
final _jurusanController = TextEditingController();
final MahasiswaService _service = MahasiswaService();
@override
void initState() {
super.initState();
_namaController.text = widget.mahasiswa.nama;
_nimController.text = widget.mahasiswa.nim;
_prodiController.text = widget.mahasiswa.prodi;
_jurusanController.text = widget.mahasiswa.jurusan;
}
void _updateMahasiswa() {
if (_formKey.currentState!.validate()) {
final updatedMahasiswa = Mahasiswa(
id: widget.mahasiswa.id,
nama: _namaController.text,
nim: _nimController.text,
prodi: _prodiController.text,
jurusan: _jurusanController.text,
);
_service.updateMahasiswa(widget.mahasiswa.id, updatedMahasiswa).then((_) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Data berhasil diperbarui.')),
);
Navigator.pop(context);
}).catchError((error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Gagal memperbarui data: $error')),
);
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('📝EDIT DATA 👨🏻🎓 & 👩🏻🎓',
style: TextStyle(
fontWeight: FontWeight.bold,
)),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _namaController,
decoration: InputDecoration(
labelText: 'Nama',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
),
validator: (value) =>
value!.isEmpty ? 'Nama tidak boleh kosong' : null,
),
SizedBox(height: 20),
TextFormField(
controller: _nimController,
decoration: InputDecoration(
labelText: 'NIM',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
),
validator: (value) =>
value!.isEmpty ? 'NIM tidak boleh kosong' : null,
),
SizedBox(height: 20),
TextFormField(
controller: _prodiController,
decoration: InputDecoration(
labelText: 'Prodi',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
),
),
SizedBox(height: 20),
TextFormField(
controller: _jurusanController,
decoration: InputDecoration(
labelText: 'Jurusan',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 8.0),
),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _updateMahasiswa,
child: const Text('Perbarui'),
),
],
),
),
),
);
}
}
DAN YAP USAI SUDAH SERIES INI.🥳