Skip to content

Latest commit

 

History

History
546 lines (519 loc) · 17.7 KB

001.3.CRUID_MAHASISWA_FLUTTERFIRE.md

File metadata and controls

546 lines (519 loc) · 17.7 KB

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.🥳

SEE NEXT TIME! 😏