Skip to content

Latest commit

 

History

History
460 lines (419 loc) · 14.1 KB

001.2.CRUID_MAHASISWA_FLUTTERFIRE.md

File metadata and controls

460 lines (419 loc) · 14.1 KB

MEMBUAT SISTEM CRUID DI FLUTTER DAN FIREBASE

01. 🗂️ Membuat file dan folder terstruktur dan rapi.

01.1. 🧹 MEMANAJEMEN FOLDER & FILE SUPAYA RAPI & TERSTRUKTUR

📂lib/
    ├─🎯main.dart                // File utama aplikasi
    ├─📂views/                   // Folder untuk tampilan (UI)
    │   ├─📋mahasiswa_list.dart   // Daftar mahasiswa
    │   ├─➕mahasiswa_add.dart    // Menambah mahasiswa
    │   ├─👀mahasiswa_detail.dart // Detail mahasiswa
    │   ├─✏️mahasiswa_edit.dart   // Edit mahasiswa
    ├─📂models/                  // Folder untuk model data
    │   ├─📦mahasiswa_model.dart  // Struktur data mahasiswa
    ├─📂services/                // Folder untuk logika bisnis
    │   ├─🛠️mahasiswa_service.dart // Layanan Firestore

02. 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 StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'CRUD Mahasiswa',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MahasiswaListView(),
    );
  }
}

03. NGODING TIPIS-TIPIS DI 🛠️ /lib/services/mahasiswa_service.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import '../models/mahasiswa_model.dart';

class MahasiswaService {
  final CollectionReference mahasiswaCollection =
      FirebaseFirestore.instance.collection('mahasiswa');

  // Fetch all mahasiswa
  Future<List<Mahasiswa>> fetchMahasiswa() async {
    QuerySnapshot snapshot = await mahasiswaCollection.get();
    return snapshot.docs
        .map((doc) => Mahasiswa.fromFirestore(
              doc.data() as Map<String, dynamic>,
              doc.id,
            ))
        .toList();
  }

  // Add new mahasiswa
  Future<void> addMahasiswa(Mahasiswa mahasiswa) async {
    await mahasiswaCollection.add(mahasiswa.toMap());
  }

  // Update mahasiswa
  Future<void> updateMahasiswa(String id, Mahasiswa mahasiswa) async {
    await mahasiswaCollection.doc(id).update(mahasiswa.toMap());
  }

  // Delete mahasiswa
  Future<void> deleteMahasiswa(String id) async {
    await mahasiswaCollection.doc(id).delete();
  }
}

04. NGODING TIPIS-TIPIS DI 📦 /lib/models/mahasiswa_model.dart

class Mahasiswa {
  final String id;
  final String nama;
  final String nim;
  final String prodi;
  final String jurusan;

  Mahasiswa({
    required this.id,
    required this.nama,
    required this.nim,
    required this.prodi,
    required this.jurusan,
  });

  // Convert Firestore document to Mahasiswa object
  factory Mahasiswa.fromFirestore(Map<String, dynamic> data, String id) {
    return Mahasiswa(
      id: id,
      nama: data['nama'] ?? '',
      nim: data['nim'] ?? '',
      prodi: data['prodi'] ?? '',
      jurusan: data['jurusan'] ?? '',
    );
  }

  // Convert Mahasiswa object to Firestore document
  Map<String, dynamic> toMap() {
    return {
      'nama': nama,
      'nim': nim,
      'prodi': prodi,
      'jurusan': jurusan,
    };
  }
}

05.1.NAH SEKARANG MASUK KE VIEW 👁️👁️

05.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 {
  const MahasiswaListView({super.key});

  @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 Mahasiswa'),
        actions: [
          IconButton(
            icon: const Icon(Icons.add),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (context) => const MahasiswaAddView()),
              ).then((_) => setState(() {})); // Refresh after adding
            },
          ),
        ],
      ),
      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(
            itemCount: mahasiswaList.length,
            itemBuilder: (context, index) {
              final mahasiswa = mahasiswaList[index];
              return ListTile(
                title: Text(mahasiswa.nama),
                subtitle: Text('NIM: ${mahasiswa.nim}'),
                onTap: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) =>
                          MahasiswaDetailView(mahasiswa: mahasiswa),
                    ),
                  );
                },
              );
            },
          );
        },
      ),
    );
  }
}

05.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 Mahasiswa')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            children: [
              TextFormField(
                controller: _namaController,
                decoration: const InputDecoration(labelText: 'Nama'),
                validator: (value) =>
                    value!.isEmpty ? 'Nama tidak boleh kosong' : null,
              ),
              TextFormField(
                controller: _nimController,
                decoration: const InputDecoration(labelText: 'NIM'),
                validator: (value) =>
                    value!.isEmpty ? 'NIM tidak boleh kosong' : null,
              ),
              TextFormField(
                controller: _prodiController,
                decoration: const InputDecoration(labelText: 'Prodi'),
              ),
              TextFormField(
                controller: _jurusanController,
                decoration: const InputDecoration(labelText: 'Jurusan'),
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: _saveMahasiswa,
                child: const Text('Simpan'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

05.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),
        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: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Nama: ${mahasiswa.nama}',
                style: const TextStyle(fontSize: 18)),
            const SizedBox(height: 10),
            Text('NIM: ${mahasiswa.nim}', style: const TextStyle(fontSize: 18)),
            const SizedBox(height: 10),
            Text('Prodi: ${mahasiswa.prodi}',
                style: const TextStyle(fontSize: 18)),
            const SizedBox(height: 10),
            Text('Jurusan: ${mahasiswa.jurusan}',
                style: const TextStyle(fontSize: 18)),
          ],
        ),
      ),
    );
  }
}

05.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 Mahasiswa')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            children: [
              TextFormField(
                controller: _namaController,
                decoration: const InputDecoration(labelText: 'Nama'),
                validator: (value) =>
                    value!.isEmpty ? 'Nama tidak boleh kosong' : null,
              ),
              TextFormField(
                controller: _nimController,
                decoration: const InputDecoration(labelText: 'NIM'),
                validator: (value) =>
                    value!.isEmpty ? 'NIM tidak boleh kosong' : null,
              ),
              TextFormField(
                controller: _prodiController,
                decoration: const InputDecoration(labelText: 'Prodi'),
              ),
              TextFormField(
                controller: _jurusanController,
                decoration: const InputDecoration(labelText: 'Jurusan'),
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: _updateMahasiswa,
                child: const Text('Perbarui'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}