Aplikasi Web dan Android “Catatan Harian” dengan Rest API

Kali ini kita akan belajar menghubungkan aplikasi flutter dengan API CodeIgniter. Sebelum lanjut kita harus sudah mencoba panduan “Membuat Aplikasi Android Sampai Rilis di Play Store” terlebih dahulu. Pastikan aplikasi sudah bisa dijalankan. Sebelumnya Aplikasi Catatan Harian menggunakan Shared Preferences / local storage untuk mengolah data. Kali ini kita akan mengupdate aplikasi dengan Rest API.

Daftar Rest API yang akan digunakan:

  • GET : https://demo.belajaraplikasi.com/backend-ci/daftarcatatan
  • POST : https://demo.belajaraplikasi.com/backend-ci/tambahcatatan
  • POST : https://demo.belajaraplikasi.com/backend-ci/ubahcatatan
  • GET : https://demo.belajaraplikasi.com/backend-ci/hapuscatatan
Kita juga bisa build website / PWA dengan flutter 🙂 coba di sini => https://demo.belajaraplikasi.com/flutterweb/

Buka project flutter (Aplikasi Catatan Harian) yang sudah dibuat.

Pertama kita tambahkan library / dependencies “http: ^0.12.2”  di pubspec.yaml terlebih dahulu. Lalu ketik perintah di terminal : flutter pub get.

Buat file baru dengan nama “endpoint.dart“. Untuk menyimpan daftar API yang digunakan. Ketikkan code seperti berikut:

const BASE_URL = 'https://demo.belajaraplikasi.com/backend-ci';
const DAFTAR_CATATAN = BASE_URL + '/daftarcatatan';
const TAMBAH_CATATAN = BASE_URL + '/tambahcatatan';
const UBAH_CATATAN = BASE_URL + '/ubahcatatan';
const HAPUS_CATATAN = BASE_URL + '/hapuscatatan';

Selanjutnya kita membuat Model untuk menampung respon API. Buat file baru dengan nama “data.dart“. Ketikkan code seperti berikut:

class ListCatatan {
  final int id;
  final String judul;
  final String tanggal;
  final String catatan;

  ListCatatan({this.id, this.judul, this.tanggal, this.catatan});

  factory ListCatatan.fromJson(<String, dynamic> json) {
    return ListCatatan(
      id: json['id'],
      tanggal: json['tanggal'],
      judul: json['judul'],
      catatan: json['catatan'],
    );
  }
}

Hapus “function_olah_data.dart” dan buat file baru dengan nama “bantuan.dart“. Ketikkan code seperti berikut :

import 'package:intl/intl.dart';
import 'package:intl/date_symbol_data_local.dart';

String formatDateFromString(String date) {
  initializeDateFormatting();
  DateTime dateFormat = DateFormat("yyyy-MM-dd hh:mm:ss").parse(date);
  return DateFormat('EEEE, dd MMMM yyyy hh:mm:ss', 'id_ID').format(dateFormat);
}

String formatDateFromDateTime(DateTime date) {
  initializeDateFormatting();
  return DateFormat('EEEE, dd MMMM yyyy hh:mm:ss', 'id_ID').format(date);
}

String formatDateYMDFromDateTime(DateTime date) {
  initializeDateFormatting();
  return DateFormat('yyyy-MM-dd hh:mm:ss', 'id_ID').format(date);
}

Di dalam folder Daftar, ubah file “daftar.dart” menjadi seperti berikut:

import 'dart:convert';
import 'package:catatan_harian/endpoint.dart';
import 'package:http/http.dart' as http;
import 'package:catatan_harian/catatan/catatan.dart';
import 'package:catatan_harian/daftar/loading.dart';
import 'package:flutter/material.dart';
import 'daftar_konten.dart';
import 'daftar_kosong.dart';
import '../data.dart';

class Daftar extends StatefulWidget {
  @override
  _DaftarState createState() => _DaftarState();
}

class _DaftarState extends State<Daftar> {
  void tambahCatatan() async {
    final result = await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => Catatan(
          tanggal: '',
          judul: '',
          catatan: '',
        ),
      ),
    );
    if (result != null) {
      setState(() {
        futureCatatan = fetchDaftarCatatan();
      });
    }
  }

  void ubahCatatan(int id, String tanggal, String judul, String catatan) async {
    final result = await Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) =&amp;gt; Catatan(
          id: id,
          tanggal: tanggal,
          judul: judul,
          catatan: catatan,
        ),
      ),
    );
    if (result != null) {
      setState(() {
        futureCatatan = fetchDaftarCatatan();
      });
    }
  }

  Future<void> hapusCatatan(int id) async {
    final response = await http.get('$HAPUS_CATATAN?id=$id');
    if (response.statusCode == 200) {
    } else {
      throw Exception('Gagal Menghapus Catatan');
    }
    setState(() {
      Navigator.pop(context);
      futureCatatan = fetchDaftarCatatan();
    });
  }

  Future<List<ListCatatan>> fetchDaftarCatatan() async {
    final response = await http.get('$DAFTAR_CATATAN');
    if (response.statusCode == 200) {
      if (response.body != 'false') {
        Map<String, dynamic> json = jsonDecode(response.body);
        List<ListCatatan> produkList = [];
        for (final item in json['data']) {
          produkList.add(ListCatatan.fromJson(item));
        }
        return produkList;
      } else {
        return null;
      }
    } else {
      throw Exception('Gagal Menampilkan Daftar Catatan');
    }
  }

  Future<List<ListCatatan>> futureCatatan;

  @override
  void initState() {
    super.initState();
    futureCatatan = fetchDaftarCatatan();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<ListCatatan>>(
      future: futureCatatan,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          if (snapshot.hasData) {
            return DaftarKonten(
              snapshot: snapshot,
              ubahCatatan: ubahCatatan,
              hapusCatatan: hapusCatatan,
              tambahCatatan: tambahCatatan,
            );
          } else {
            return DaftarKosong(tambahCatatan: tambahCatatan);
          }
        }
        return Loading();
      },
    );
  }
}

Selanjutnya masih di dalam folder Daftar, ubah juga file “daftar_kontent.dart” menjadi seperti berikut:

import 'package:catatan_harian/daftar/daftar_catatan.dart';
import 'package:catatan_harian/data.dart';
import 'package:flutter/material.dart';

class DaftarKonten extends StatelessWidget {
  DaftarKonten({
    @required this.snapshot,
    @required this.hapusCatatan,
    @required this.ubahCatatan,
    @required this.tambahCatatan,
  });
  final AsyncSnapshot<List<ListCatatan>> snapshot;
  final Function(int) hapusCatatan;
  final Function(int, String, String, String) ubahCatatan;
  final Function tambahCatatan;

  Future dialogHapus(BuildContext context, String judul, int id) {
    return showDialog(
      context: context,
      builder: (_) => AlertDialog(
        title: Text(
          'Yakin "$judul" akan dihapus?',
          style: TextStyle(fontSize: 12),
        ),
        content: InkWell(
          onTap: () => hapusCatatan(id),
          child: Container(
            padding: const EdgeInsets.all(8),
            decoration: BoxDecoration(
              color: Color(0xFF1761a0),
              borderRadius: BorderRadius.circular(6),
            ),
            child: Text(
              'Hapus',
              style: TextStyle(
                fontSize: 14,
                color: Colors.white,
              ),
              textAlign: TextAlign.center,
            ),
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Catatan Harian'),
        backgroundColor: Color(0xFF1761a0),
      ),
      body: SafeArea(
        child: Container(
          child: ListView.builder(
            physics: const ClampingScrollPhysics(),
            itemCount: snapshot.data.length,
            itemBuilder: (context, index) {
              return Padding(
                padding: const EdgeInsets.symmetric(horizontal: 10),
                child: InkWell(
                  onLongPress: () => dialogHapus(
                    context,
                    snapshot.data[index].judul,
                    snapshot.data[index].id,
                  ),
                  onTap: () => ubahCatatan(
                    snapshot.data[index].id,
                    snapshot.data[index].tanggal,
                    snapshot.data[index].judul,
                    snapshot.data[index].catatan,
                  ),
                  child: Column(
                    children: <Widget>[
                      DaftarCatatan(
                        tanggal: snapshot.data[index].tanggal,
                        judul: snapshot.data[index].judul,
                        catatan: snapshot.data[index].catatan,
                      ),
                      Divider(height: 1),
                    ],
                  ),
                ),
              );
            },
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        backgroundColor: Color(0xFF1761a0),
        onPressed: tambahCatatan,
        child: Icon(Icons.add),
      ),
    );
  }
}

Lalu masih dalam folder yang sama, ubah juga file “daftar_catatan.dart” menjadi seperti berikut:

import 'package:flutter/material.dart';
import 'package:share/share.dart';

class DaftarCatatan extends StatelessWidget {
  DaftarCatatan({
    @required this.tanggal,
    @required this.judul,
    @required this.catatan,
  });
  final String tanggal;
  final String judul;
  final String catatan;

  void bagikanCatatan() {
    Share.share( '$tanggal\n$judul\n$catatan');
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      children: <Widget>[
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              SizedBox(height: 10),
              Text(
                '$tanggal',
                style: TextStyle(color: Colors.grey, fontSize: 10),
              ),
              SizedBox(height: 3),
              Text(
                '$judul',
                style: TextStyle(
                  color: Colors.grey[800],
                  fontWeight: FontWeight.bold,
                  fontSize: 16,
                ),
              ),
              SizedBox(height: 5),
              Text(
                '$catatan',
                style: TextStyle(color: Colors.grey[700], fontSize: 14),
                overflow: TextOverflow.ellipsis,
                maxLines: 1,
              ),
              SizedBox(height: 10),
            ],
          ),
        ),
        InkWell(
          onTap: () => bagikanCatatan(),
          child: Icon(
            Icons.share,
            color: Colors.grey[350],
            size: 18,
          ),
        ),
        Padding(
          padding: const EdgeInsets.only(left: 12),
          child: Icon(
            Icons.arrow_forward_ios,
            color: Colors.grey[350],
            size: 18,
          ),
        ),
      ],
    );
  }
}

Pindah ke folder catatan,  ubah file “catatan.dart” menjadi seperti berikut:

import 'dart:convert';
import 'package:catatan_harian/bantuan.dart';
import 'package:catatan_harian/catatan/isi_catatan.dart';
import 'package:catatan_harian/catatan/judul_catatan.dart';
import 'package:catatan_harian/catatan/simpan_catatan.dart';
import 'package:catatan_harian/catatan/tanggal_catatan.dart';
import 'package:catatan_harian/endpoint.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:http/http.dart' as http;

class Catatan extends StatefulWidget {
  Catatan({
    this.id,
    @required this.tanggal,
    @required this.judul,
    @required this.catatan,
  });
  final int id;
  final String tanggal;
  final String judul;
  final String catatan;

  @override
  _CatatanState createState() =>
      _CatatanState(id: id, tanggal: tanggal, judul: judul, catatan: catatan);
}

class _CatatanState extends State<Catatan> {
  _CatatanState({
    this.id,
    @required this.tanggal,
    @required this.judul,
    @required this.catatan,
  });

  int id;
  String tanggal;
  String judul;
  String catatan;

  TextEditingController judulController = TextEditingController();
  TextEditingController catatanController = TextEditingController();

  Future<void> onPressedSimpan() async {
    if (id != null) {
      judul = judulController.text;
      catatan = catatanController.text;

      final response = await http.post(
        Uri.parse('$UBAH_CATATAN'),
        headers: <String, String>{
          'Content-Type': 'application/json; charset=UTF-8',
        },
        body: jsonEncode(<String, String>{
          'id': id.toString(),
          'tanggal': tanggal,
          'judul': judul,
          'catatan': catatan
        }),
      );

      if (response.statusCode == 200) {
        Navigator.pop(context, 'berhasil');
      } else {
        throw Exception('Gagal untuk mengubah catatan');
      }
    } else {
      String judul = judulController.text;
      String catatan = catatanController.text;

      final response = await http.post(
        Uri.parse('$TAMBAH_CATATAN'),
        headers: <String, String>{
          'Content-Type': 'application/json; charset=UTF-8',
        },
        body: jsonEncode(<String, String>{
          'tanggal': formatDateYMDFromDateTime(DateTime.now()),
          'judul': judul,
          'catatan': catatan
        }),
      );

      if (response.statusCode == 200) {
        Navigator.pop(context, 'berhasil');
      } else {
        throw Exception('Gagal untuk menyimpan catatan');
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    const locale = 'id';
    initializeDateFormatting(locale).then((_) {
      DateFormat.Hm(locale);
    });

    if (id != null) {
      judulController.text = judul;
      catatanController.text = catatan;
    }

    return Scaffold(
      appBar: AppBar(
        title: Text(id == null ? 'Tambah Catatan' : 'Ubah Catatan'),
        backgroundColor: Color(0xFF1761a0),
      ),
      body: Builder(
        builder: (context) => SafeArea(
          child: Container(
            child: Stack(
              children: <Widget>[
                ListView(
                  physics: const ClampingScrollPhysics(),
                  children: <Widget>[
                    Column(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: <Widget>[
                        SizedBox(height: 10),
                        TanggalCatatan(
                          id: id,
                          tanggal: tanggal,
                        ),
                        JudulCatatan(judulController: judulController),
                        Divider(height: 1),
                        IsiCatatan(catatanController: catatanController),
                      ],
                    ),
                    SizedBox(height: 45),
                  ],
                ),
                SimpanCatatan(onPressedSimpan: onPressedSimpan),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Masih dalam folder catatan, ubah juga file “tanggal_catatan.dart” menjadi seperti berikut:

import 'dart:convert';
import 'package:catatan_harian/bantuan.dart';
import 'package:catatan_harian/catatan/isi_catatan.dart';
import 'package:catatan_harian/catatan/judul_catatan.dart';
import 'package:catatan_harian/catatan/simpan_catatan.dart';
import 'package:catatan_harian/catatan/tanggal_catatan.dart';
import 'package:catatan_harian/endpoint.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:http/http.dart' as http;

class Catatan extends StatefulWidget {
  Catatan({
    this.id,
    @required this.tanggal,
    @required this.judul,
    @required this.catatan,
  });
  final int id;
  final String tanggal;
  final String judul;
  final String catatan;

  @override
  _CatatanState createState() =>
      _CatatanState(id: id, tanggal: tanggal, judul: judul, catatan: catatan);
}

class _CatatanState extends State<Catatan> {
  _CatatanState({
    this.id,
    @required this.tanggal,
    @required this.judul,
    @required this.catatan,
  });

  int id;
  String tanggal;
  String judul;
  String catatan;

  TextEditingController judulController = TextEditingController();
  TextEditingController catatanController = TextEditingController();

  Future<void> onPressedSimpan() async {
    if (id != null) {
      judul = judulController.text;
      catatan = catatanController.text;

      final response = await http.post(
        Uri.parse('$UBAH_CATATAN'),
        headers: <String, String>{
          'Content-Type': 'application/json; charset=UTF-8',
        },
        body: jsonEncode(<String, String>{
          'id': id.toString(),
          'tanggal': tanggal,
          'judul': judul,
          'catatan': catatan
        }),
      );

      if (response.statusCode == 200) {
        Navigator.pop(context, 'berhasil');
      } else {
        throw Exception('Gagal untuk mengubah catatan');
      }
    } else {
      String judul = judulController.text;
      String catatan = catatanController.text;

      final response = await http.post(
        Uri.parse('$TAMBAH_CATATAN'),
        headers: <String, String>{
          'Content-Type': 'application/json; charset=UTF-8',
        },
        body: jsonEncode(<String, String>{
          'tanggal': formatDateYMDFromDateTime(DateTime.now()),
          'judul': judul,
          'catatan': catatan
        }),
      );

      if (response.statusCode == 200) {
        Navigator.pop(context, 'berhasil');
      } else {
        throw Exception('Gagal untuk menyimpan catatan');
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    const locale = 'id';
    initializeDateFormatting(locale).then((_) {
      DateFormat.Hm(locale);
    });

    if (id != null) {
      judulController.text = judul;
      catatanController.text = catatan;
    }

    return Scaffold(
      appBar: AppBar(
        title: Text(id == null ? 'Tambah Catatan' : 'Ubah Catatan'),
        backgroundColor: Color(0xFF1761a0),
      ),
      body: Builder(
        builder: (context) => SafeArea(
          child: Container(
            child: Stack(
              children: <Widget>[
                ListView(
                  physics: const ClampingScrollPhysics(),
                  children: <Widget>[
                    Column(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: <Widget>[
                        SizedBox(height: 10),
                        TanggalCatatan(
                          id: id,
                          tanggal: tanggal,
                        ),
                        JudulCatatan(judulController: judulController),
                        Divider(height: 1),
                        IsiCatatan(catatanController: catatanController),
                      ],
                    ),
                    SizedBox(height: 45),
                  ],
                ),
                SimpanCatatan(onPressedSimpan: onPressedSimpan),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Run flutter project. Selesai.
Source Code Lengkap : https://github.com/handoyoapp/catatan_harian

Selamat mencoba.
Happy Coding 🙂

3 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *