Modul Mobileprogramming 2pdf 1678806914
Modul Mobileprogramming 2pdf 1678806914
MOBILE Programming II
1
Daftar Isi
Aplikasi Mobile dengan Flutter ....................................................................................................................... 5
Menyiapkan perangkat ............................................................................................................................... 5
Install Git................................................................................................................................................. 5
Install JDK................................................................................................................................................ 5
Install Android Studio ........................................................................................................................... 10
Install Flutter......................................................................................................................................... 15
Konfigurasi Android Studio dengan Flutter ........................................................................................... 21
Membuat dan menjalankan projek........................................................................................................... 22
Membuat dan menjalankan projek dengan VSCode dan Handphone Android ........................................ 29
Install VSCode sebagai alternatif editor ................................................................................................ 29
Membuat projek flutter dengan VSCode .............................................................................................. 30
Menjalankan aplikasi dengan Handphone Android .............................................................................. 33
Struktur Folder Flutter .............................................................................................................................. 40
Membuat Hello World .............................................................................................................................. 41
Membuat Widget Column ........................................................................................................................ 47
Membuat Widget Row.............................................................................................................................. 48
StatelessWidget dan StatefullWidget ....................................................................................................... 50
Membuat Form......................................................................................................................................... 51
Pemisahan Widget Kedalam fungsi-fungsi................................................................................................ 56
Membuat Detail Produk ........................................................................................................................... 57
Membuat fungsi tombol simpan dan menampilkan data pada Detail Produk.......................................... 58
Membuat ListView Produk ....................................................................................................................... 62
Membuat Route (Pindah Halaman) .......................................................................................................... 64
Pemisahan Widget ke dalam Class StatelessWidget ................................................................................. 66
Menampilkan Detail Produk saat ListView diklik ...................................................................................... 68
Membuat projek flutter yang terhubung dengan API................................................................................... 72
Apa itu API ................................................................................................................................................ 72
Arsitektur API............................................................................................................................................ 73
Membuat projek Toko API (Restful API) ....................................................................................................... 73
Installasi Apache, MySql dan PHP (XAMPP) .............................................................................................. 73
Install Postman ......................................................................................................................................... 78
API SPEC.................................................................................................................................................... 79
Pembuatan Database ............................................................................................................................... 82
2
Installasi CodeIgniter 4 sebagai Restful API .............................................................................................. 84
Membuat hasil response .......................................................................................................................... 86
Registrasi .................................................................................................................................................. 87
Membuat model Registrasi................................................................................................................... 87
Membuat controller Registrasi ............................................................................................................. 87
Menambah route Registrasi ................................................................................................................. 88
Login ......................................................................................................................................................... 90
Membuat model Member .................................................................................................................... 90
Membuat model Login ......................................................................................................................... 90
Membuat controller Login .................................................................................................................... 91
Menambahkan route Login .................................................................................................................. 92
Mencoba Rest....................................................................................................................................... 93
CRUD Produk ............................................................................................................................................ 93
Membuat model Produk....................................................................................................................... 93
Membuat controller produk ................................................................................................................. 93
Mencoba Rest....................................................................................................................................... 97
Membuat projek flutter tokokita .................................................................................................................. 98
Membuat Model....................................................................................................................................... 99
Login ................................................................................................................................................... 100
Registrasi ............................................................................................................................................ 101
Produk ................................................................................................................................................ 101
Membuat Halaman ................................................................................................................................. 101
Registrasi ............................................................................................................................................ 102
Login ................................................................................................................................................... 106
Form Produk ....................................................................................................................................... 110
Detail Produk ...................................................................................................................................... 114
Tampil List Produk .............................................................................................................................. 118
Membuat Helper Modul ......................................................................................................................... 123
Menambahkan depedencies............................................................................................................... 123
Membuat Class Token ........................................................................................................................ 123
Http request ....................................................................................................................................... 125
Membuat Bloc ........................................................................................................................................ 128
Registrasi ............................................................................................................................................ 129
Login ................................................................................................................................................... 130
Logout................................................................................................................................................. 130
3
Produk ................................................................................................................................................ 130
Menyatukan Fungsionalitas ........................................................................................................................ 132
Membuat Common Dialog Widget ......................................................................................................... 132
Modifikasi main.dart............................................................................................................................... 137
Modifikasi registrasi_page.dart .............................................................................................................. 138
Modifikasi login_page.dart (fungsi login)................................................................................................ 143
Modifikasi produk_page.dart ................................................................................................................. 148
Memodifikasi Form Produk (produk_form.dart) .................................................................................... 154
4
Aplikasi Mobile dengan Flutter
Menyiapkan perangkat
Install Git
Buka laman https://git-scm.com/downloads, kemudian klik tombol download
Install JDK
JDK (Java Development Kit) adalah sebuah perangkat lunak yang digunakan untuk
melakukan proses kompilasi dari kode java ke bytecode yang dapat dimengerti dan dapat
dijalankan oleh JRE (Java Runtime Envirotment). JDK wajib terinstall pada komputer yang akan
melakukan proses pembuatan aplikasi berbasis java, namun tidak wajib terinstall di komputer
yang akan menjalankan aplikasi yang dibangun dengan java.
5
Pilih JDK 15, kemudian download file zip untuk windows, jika menggunakan windows
6
Kemudian pilih “Advanced System Setting”
Pilih Path pada bagian System Variables kemudian Klik tombol “Edit”
7
Kemudian klik tombol “New”
8
Kemudian masukkan alamat folder bin pada jdk yang telah kita ekstrak dalam hal ini misalnya
“C:\Program Files\Java\jdk-15.0.1\bin”
9
Biasanya agar JDK dapat berfungsi perlu dilakukan restart laptop/komputer. Untuk
memeriksa apakah installasi berhasil, buka command prompt kemudian ketikkan java -version
atau javac -version
10
Kemudian pilih tipe standar dan klik next
11
Pilih thema tampilan kemudian klik next
12
Kemudian klik tombol next
13
Pastikan komputer terhubung dengan internet yang stabil, karena android studio akan
mengunduh komponen-komponen yang diperlukan
14
Setelah selesai klik finish
Install Flutter
Flutter adalah sebuah framework open-source yang dikembangkan oleh Google untuk
membangun antarmuka (user interface/UI) aplikasi Android dan iOS.
Apa bedanya membuat aplikasi android menggunakan Java/Kotlin (native) dengan Flutter.
Dari bahasa pemrograman yang digunakan, Flutter menggunakan bahasa pemrograman Dart,
sedangkan Android Native menggunakan bahasa pemrograman Java dan Kotlin. Aplikasi yang
kita buat dengan Flutter dapat di-build ke Android dan iOS. Sedangkan Android Native hanya
bisa di-build ke Android saja.
Untuk menginstall flutter, buka laman https://flutter.dev/docs/get-started/install Kemudian
pilih “Windows”
15
Kemudian pilih flutter_windows_ untuk mengunduh file flutter
16
Kemudian pilih “Advanced System Setting”
17
Kemudian pilih pada “System Variables” pilih “Path” dan klik tombol “Edit”
18
Kemudian klik tombol “New”
19
Kemudian masukkan alamat folder bin pada flutter yang telah kita ekstrak dalam hal ini misalnya
“D:\Android\flutter\bin”
20
Konfigurasi Android Studio dengan Flutter
Jalankan Android Studio kemudian pada menu “Configure” pilih “Plugins”
21
Pilih “Flutter” kemudian klik tombol “Install”
22
Kemudian pilih “Flutter Application” dan klik “Next”
Kemudian tentukan :
Project Name : belajarflutter
Flutter SDK path : D:\Android\flutter (masukkan sesuai alamat folder flutter diletakkan)
23
Project location : D:\Belajar (bebas memasukkan dimanapun)
Description : Membuat Aplikasi Mobile Flutter (bebas)
Kemudian klik tombol “Next”
Kemudian klik tombol “Finish”. Pastikan perangkat terhubung ke internet, karena diperlukan untuk
mengunduh projek yang dibuat
24
Setelah selesai akan muncul projek yang telah dibuat
Untuk menjalankan projek, kita memerlukan emulator android. Pertama kita akan membuat
emulator android dengan cara klik “AVD Manager” pada pojok kiri atas
25
Kemudian klik tombol “Create Virtual Device”
Pilih salah satu device yang dinginkan, misalnya “Nexus S” kemudian klik tombol “Next”
Kemudian kita akan memilih Versi Sistem Operasi Android, dalam hal ini misalnya “Q”, jika belum
ada maka kita akan diminta untuk mengunduh terlebih dahulu.
26
Setelah itu klik Finish
27
Kemudian akan muncul emulator android seperti berikut:
28
Jika emulator sudah berjalan, kita dapat mengeksekusi projek dengan cara klik tombol play
(berwarna hijau) pada Android Studio
29
Setelah itu restart/tutup VSCode
Membuat projek flutter dengan VSCode
Jalankan VSCode, pada menubar pilih view -> command Palette... atau dapat juga dengan shortcut
Ctrl + Shift + P
30
Kemudian pilih Application
31
Kemudian tentukan nama projek flutter yang ingin dibuat misalnya
aplikasi_flutter_pertamaku
32
Menjalankan aplikasi dengan Handphone Android
Untuk menjalankan projek flutter dari VSCode dapat menggunakan Emulator AVD yang telah
dibuat sebelumnya menggunakan Android Studio ataupun menggunakan Device Handphone
Android langsung
Untuk menggunakan android device secara langsung, pertama aktifkan dulu mode developer
dengan cara buka Setting kemudian pilih System kemudian pilih About Phone, untuk
masingmasing device mungkin terdapat perbedaan untuk lokasi About Phone ada pula yang
berada pada Additional Setting
33
Kemudian pilih About Phone
34
Kemudian ketuk Build number beberapa kali, namun ini juga berbeda untuk beberapa versi
misalnya untuk Xiaomi dengan mengetuk MIUI Version beberapa kali
35
Selanjutnya mengaktifkan USB Debugger dengan cara pilih Developer Option pada System,
Developer Option ini akan muncul setelah mode Developer diaktifkan dengan cara diatas
36
Kemudian aktifkan USB Debugging
37
Jika telah selesai, hubungkan Handphone android dengan laptop/komputer dengan kabel data,
untuk memeriksa apakah sudah terhubung dengan Handphone, dapat dilihat pada
VSCode bagian pojok kanan bawah akan tertera nama device yang terhubung
38
Atau jika pada Android Studio terletak pada toolbar bagian atas tengah
Agar laptop bekerja lebih ringan dapat digunakan Text Editor VSCode dan menjalankan
projek langsung menggunakan Handphone Android. Untuk menjalankan projek melalui
VSCode dengan klik logo play pada bagian pojok kanan atas
39
Struktur Folder Flutter
Adapun struktur folder Projek flutter adalah sebagai berikut:
40
android berisi source code untuk aplikasi android; ios berisi source code untuk aplikasi
iOS; lib berisi source code Dart, di sini kita akan menulis kode aplikasi; test berisi
source code Dart untuk testing aplikasi;
.metadata merupakan file yang berisi metadata project yang di-generate otomatis;
.packages merupakan file yang berisi alamat path package yang dibuat oleh pub;
flutter_app.iml merupakan file XML yang berisi keterangan project;
pubspec.lock merupakan file yang berisi versi-versi library atau package. File ini dibuat
oleh pub. Fungsinya untuk mengunci versi package.
pubspec.yaml merupakan file yang berisi informasi tentang project dan libraray yang
dibutuhkan;
README.md merupakan file markdown yang berisi penjelasan tentang source code.
1. import 'package:flutter/material.dart';
2.
3. void main() {
4. runApp(const MyApp());
5. }
41
6.
7. class MyApp extends StatelessWidget {
8. const MyApp({Key? key}) : super(key: key);
9.
10. @override
11. Widget build(BuildContext context) {
12. return MaterialApp(
13. title: "Aplikasi Flutter Pertama",
14. home: Scaffold(
15. appBar: AppBar(
16. title: const Text('Belajar Flutter'),
17. ),
18. ),
19. );
20. }
21. }
42
Kemudian untuk menambahkan tampilan dibagian dalam (body), pada fungsi Scaffold terdapat
parameter body. Silahkan modifikasi main.dart menjadi seperti berikut
1. import 'package:flutter/material.dart';
2.
3. void main() {
4. runApp(const MyApp());
5. }
6.
7. class MyApp extends StatelessWidget {
8. const MyApp({Key? key}) : super(key: key);
9.
10. @override
11. Widget build(BuildContext context) {
12. return MaterialApp(
13. title: "Aplikasi Flutter Pertama",
14. home: Scaffold(
43
15. appBar: AppBar(
16. title: Text('Belajar Flutter'),
17. ),
18. body: const Center(
19. child: Text("Hello World"),
20. ),
21. ),
22. );
23. }
24. }
Pada aplikasi di atas, kita membuat StatelessWidget yang berisi widget MaterialApp().
44
Kemudian di dalam MateralApp() berisi widget lagi: Scaffold, AppBar, Center, dan Text.
Ini adalah widget dasar. Penjelasan:
Untuk mempermudah dalam pembacaan kode dan maintenance dapat dilakukan dengan
memisahkan MyApp dengan halaman yang ingin ditampilkan.
Silahkan buat sebuah file dengan nama hello_world.dart di dalam folder lib
Kemudian bagian Scaffold pada main.dart yang telah dibuat tadi akan kita masukkan ke dalam
hello_world.dart, sehingga pada hello_world.dart akan menjadi
45
1. import 'package:flutter/material.dart' ;
2.
3. class HelloWorld extends StatelessWidget {
4. @override
5. Widget build(BuildContext context) {
6. return Scaffold(
7. appBar: AppBar(
8. title: const Text('Belajar Flutter'),
9. ),
10. body: const Center(
11. child: Text('Hello World'),
12. ),
13. );
14. }
15. }
Pada file main.dart kita modifikasi kembali pada bagian home menjadi
1. import 'package:aplikasi_flutter_pertamaku/hello_world.dart';
2. import 'package:flutter/material.dart';
3.
4. void main() {
5. runApp(const MyApp());
6. }
7.
8. class MyApp extends StatelessWidget {
9. const MyApp({Key? key}) : super(key: key);
10.
11. @override
12. Widget build(BuildContext context) {
13. Return const MaterialApp(
14. title: "Aplikasi Flutter Pertama",
15. home: HelloWorld(),
16. );
17. }
18. }
Pada bagian home, kita memanggil class HelloWorld yang telah kita buat sebelumnya pada
file hello_world.dart
Jika kita perhatikan pada bagian body, terdapat Widget Center kemudian didalam Widget
Center tersebut terdapat parameter child untuk meletakkan Widget lain didalam widget
tersebut, dalam hal ini adalah Widget Text
Center(
child: Text('Hello World'),
),
Catatan : dalam Widget selain child, terdapat pula children dengan type data array yang
dimana kita dapat menempatkan beberapa Widget didalamnya contohnya pada Widget
Column dan Row
Untuk mempercepat dalam pembuatan class pada VSCode dapat dilakukan dengan mengetik
st kemudian memilih stateless widget ataupun stateless widget kemudian ketikkan nama
class yang diinginkan
46
Membuat Widget Column
Buat sebuah file dengan nama column_widget.dart didalam folder lib, kemudian ketikkan kode
berikut
1. import 'package:flutter/material.dart' ;
2.
3. class ColumnWidget extends StatelessWidget {
4. const ColumnWidget({Key? key}) : super(key: key);
5.
6. @override
7. Widget build(BuildContext context) {
8. return Scaffold(
9. appBar: AppBar(
10. title: const Text('Widget Column'),
11. ),
12. body: Column(
13. children: const [
14. Text('Kolom 1'),
15. Text('Kolom 3'),
16. Text('Kolom 2'),
17. Text('Kolom 4')
18. ],
19. ));
20. }
21. }
47
16. );
17. }
18. }
Dan hasilnya akan menjadi seperti berikut
48
1. import 'package:flutter/material.dart' ;
2.
3. class RowWidget extends StatelessWidget {
4. const RowWidget({Key? key}) : super(key: key);
5.
6. @override
7. Widget build(BuildContext context) {
8. return Scaffold(
9. appBar: AppBar(
10. title: const Text('Widget Row'),
11. ),
12. body: Row(
13. children: const [
14. Text('Row 1'),
15. Text('Row 2'),
16. Text('Row 3'),
17. Text('Row 4')
18. ],
19. ),
20. );
21. }
22. }
Kemudian seperti sebelumnya masukkan class RowWidget tersebut kedalam home pada main.dart,
dan hasilnya akan menjadi
49
StatelessWidget dan StatefullWidget
StatelessWidget adalah class widget yang propertinya immutable, artinya nilainya tidak bisa
diubah, sedangkan StatefullWidget nilainya dapat berubah-ubah.
Contoh StatelessWidget :
1. class HelloWorld extends StatelessWidget {
2. const HelloWorld({ Key? key }) : super(key: key);
3.
4. @override
5. Widget build(BuildContext context) {
6. return Container(
7.
8. );
50
9. }
10. }
Contoh StatefullWidget
1. class HelloWorld extends StatefulWidget {
2. const HelloWorld({ Key? key }) : super(key: key);
3.
4. @override
5. _HelloWorldState createState() => _HelloWorldState();
6. }
7.
8. class _HelloWorldState extends State<HelloWorld> {
9. @override
10. Widget build(BuildContext context) {
11. return Container(
12.
13. );
14. }
15. }
Membuat Form
Selanjutnya kita akan belajar membuat form pada flutter, agar lebih rapi untuk tampilan
halaman akan kita kelompokkan dalam sebuah folder tersendiri, dalam hal ini kita membuat
folder dengan nama ui didalam folder lib.
51
Kemudian didalam folder ui tersebut kita buat sebuah file dengan nama produk_form.dart
52
53
Kemudian Ketikkan kode berikut
54
1. import 'package:flutter/material.dart';
2.
3. class ProdukForm extends StatefulWidget { 4.
const ProdukForm({Key? key}) : super(key: key);
5.
6. @override
7. _ProdukFormState createState() => _ProdukFormState();
8. }
9.
10. class _ProdukFormState extends State<ProdukForm> {
11. @override
12. Widget build(BuildContext context) {
13. return Scaffold(
14. appBar: AppBar(
15. title: const Text('Form Produk'),
16. ),
17. body: SingleChildScrollView(
18. child: Column(
19. children: [
20. TextField(decoration: const InputDecoration(labelText: "Kode Produk")),
21. TextField(decoration: const InputDecoration(labelText: "Nama Produk")),
22. TextField(decoration: const InputDecoration(labelText: "Harga")),
23. ElevatedButton(onPressed: () {}, child: const Text('Simpan'))
24. ],
25. ),
26. ),
27. );
28. }
29. }
Ubah pada main.dart dengan memanggil class ProdukForm, sehingga hasilnya akan menjadi
55
Pemisahan Widget Kedalam fungsi-fungsi
Agar kode mudah dibaca dan dikembangkan, akan lebih baik jika widget-widget yang
digunakan dipisahkan kedalam method/function tertentu, misalnya pada produk_form.dart
terdapat widget seperti TextField dan Button, pada widget tersebut akan kita pisahkan
kedalam method tersendiri didalam class, sehingga menjadi seperti berikut
1. import 'package:flutter/material.dart';
2.
3. class ProdukForm extends StatefulWidget { 4.
const ProdukForm({Key? key}) : super(key: key);
5.
6. @override
7. _ProdukFormState createState() => _ProdukFormState();
56
Membuat Detail Produk
Buat sebuah file dengan nama produk_detail.dart di dalam folder ui, kemudian ketikkan kode
berikut
57
1. import 'package:flutter/material.dart' ;
2.
3. class ProdukDetail extends StatefulWidget {
4. final String? kodeProduk;
5. final String? namaProduk;
6. final int? harga;
7.
8. const ProdukDetail({Key? key, this.kodeProduk, this.namaProduk, this.harga})
9. : super(key: key);
10.
11. @override
12. _ProdukDetailState createState() => _ProdukDetailState();
13. }
14.
15. class _ProdukDetailState extends State<ProdukDetail> {
16. @override
17. Widget build(BuildContext context) {
18. return Scaffold(
19. appBar: AppBar(
20. title: const Text('Detail Produk'),
21. ),
23. children: [
28. ),
29. );
30. }
31. }
Membuat fungsi tombol simpan dan menampilkan data pada Detail Produk
Buka kembali file produk_form.dart tambahkan attribute
final _kodeProdukTextboxController = TextEditingController(); final
_namaProdukTextboxController = TextEditingController(); final
_hargaProdukTextboxController = TextEditingController();
58
41. return TextField(
42. decoration: const InputDecoration(labelText: "Nama Produk"));
43. }
44.
45. _textboxHargaProduk() {
46. return TextField(decoration: const InputDecoration(labelText: "Harga"));
47. }
48.
49. _tombolSimpan() {
59
50. return ElevatedButton(onPressed: () {}, child: const Text('Simpan'));
51. }
52. }
Pada setiap masing-masing TextField yang telah dibuat, data yang diinput dikirim ke attribute
TextEditingController() yang telah kita buat sebelumnya
Pada fungsi _textboxKodeProduk() menjadi
_textboxKodeProduk() { return
TextField(
decoration: const InputDecoration(labelText: "Kode Produk"),
controller: _kodeProdukTextboxController, );
}
Kemudian pada fungsi _tombolSimpan() pada saat diklik akan mengirim data inputan dan
menampilkan data tersebut pada ProdukDetail yang telah kita buat sebelumnya
_tombolSimpan() {
return ElevatedButton(
onPressed: () {
String kodeProduk = _kodeProdukTextboxController.text;
String namaProduk = _namaProdukTextboxController.text;
int harga = int.parse(
_hargaProdukTextboxController.text); //parsing dari String ke int
// pindah ke halaman Produk Detail dan mengirim
data Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ProdukDetail(
kodeProduk: kodeProduk,
60
namaProduk: namaProduk,
harga: harga,
)));
},
child: const Text('Simpan'));
}
61
56. _tombolSimpan() {
57. return ElevatedButton(
58. onPressed: () {
59. String kodeProduk = _kodeProdukTextboxController.text;
60. String namaProduk = _namaProdukTextboxController.text;
61. int harga = int.parse(
62. _hargaProdukTextboxController.text); //parsing dari String ke int
63. // pindah ke halaman Produk Detail dan mengirim data
64. Navigator.of(context).push(MaterialPageRoute(
65. builder: (context) => ProdukDetail(
66. kodeProduk: kodeProduk,
67. namaProduk: namaProduk,
68. harga: harga,
69. )));
70. },
71. child: const Text('Simpan'));
72. }
73. }
62
6. @override
7. _ProdukPageState createState() => _ProdukPageState();
8. }
9.
10. class _ProdukPageState extends State<ProdukPage> {
11. @override
12. Widget build(BuildContext context) {
13. return Scaffold(
14. appBar: AppBar(
15. title: const Text('Data Produk'),
16. ),
17. body: ListView(
18. children: const [
19. // List 1
20. Card(
21. child: ListTile(
22. title: Text('Kulkas'),
23. subtitle: Text('2500000'),
24. ),
25. ),
26. // List 2
27. Card(
28. child: ListTile(
29. title: Text('TV'),
30. subtitle: Text('5000000'),
31. ),
32. ),
33. // List 3
34. Card(
35. child: ListTile(
36. title: Text('Mesin Cuci'),
37. subtitle: Text('1500000'),
38. ),
39. )
40. ],
41. ),
42. );
43. }
44. }
Kemudian daftarkan ProdukPage pada main.dart, dan hasilnya akan menjadi seperti berikut
63
Membuat Route (Pindah Halaman)
Buka file produk_page.dart, kemudian modifikasi pada bagian AppBar menjadi seperti berikut
AppBar( title: const Text("Data
Produk"), actions: [
GestureDetector(
// menampilkan icon + child:
const Icon(Icons.add),
//pada saat icon + di tap onTap:
() async {
//berpindah ke halaman ProdukForm
Navigator.push( context,
MaterialPageRoute( builder: (context) => const
ProdukForm())); })
], )
GestureDetector adalah widget yang digunakan untuk mendeteksi gesture pada widget seperti
gesture ontap, doubletab dan lain-lain.
Secara Keseluruhan kode tersebut akan menjadi
64
Hasilnya akan muncul icon + pada bagian kanan AppBar, jika diklik akan membuka ProdukForm
65
Pemisahan Widget ke dalam Class StatelessWidget
Selain pemisahan widget ke dalam suatu function/method, pemisahan juga dapat dilakukan
menggunakan class StatelessWidget, pada contoh kali ini kita akan memisahkan Card dengan
membuat class tersendiri. Buka file produk_page.dart, kemudian buat sebuah class
ItemProduk diluar class ProdukPage
class ItemProduk extends StatelessWidget
{ final String? kodeProduk; final
String? namaProduk; final int? harga;
@override
Widget build(BuildContext context) {
return Card( child: ListTile(
title: Text(namaProduk.toString()),
subtitle: Text(harga.toString()),
),
);
}
}
66
Sehingga kode pada produk_page.dart menjadi
67
61. const ItemProduk({Key? key, this.kodeProduk, this.namaProduk, this.harga})
62. : super(key: key);
63.
64. @override
65. Widget build(BuildContext context) {
66. return Card(
67. child: ListTile(
68. title: Text(namaProduk.toString()),
69. subtitle: Text(harga.toString()),
70. ),
71. );
72. }
73. }
Kita akan memodifikasi Class ItemProduk pada file produk_page.dart. Untuk menambahkan
widget diatas widget yang telah dibuat dapat dilakukan dengan cara, arahkan kursor pada
widget, misalnya dalam hal ini adalah widget Card
Pada bagian kiri akan muncul logo lampu, kemudian klik lampu tersebut dan pilih widget yang ingin
ditambahkan atau dalam hal ini kita akan memilih Warp with widget..
68
Kemudian akan menjadi
Setelah itu ubah widget menjadi GestureDetector dan kita juga menambahkan onTap yang
kemudian akan membuka halaman Detail Produk, sehingga kode untuk Class ItemProduk
menjadi
69
class ItemProduk extends StatelessWidget {
final String? kodeProduk; final String?
namaProduk;
final int? harga;
@override
Widget build(BuildContext context) {
return GestureDetector( child:
Card( child: ListTile(
title: Text(namaProduk.toString()),
subtitle: Text(harga.toString()),
), ),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProdukDetail(
kodeProduk: kodeProduk,
namaProduk: namaProduk,
harga: harga,
)));
},
);
}
}
1. import 'package:aplikasi_flutter_pertamaku/ui/produk_detail.dart';
2. import 'package:aplikasi_flutter_pertamaku/ui/produk_form.dart'; 3. import
'package:flutter/material.dart';
4.
5. class ProdukPage extends StatefulWidget { 6.
const ProdukPage({Key? key}) : super(key: key);
7.
8. @override
9. _ProdukPageState createState() => _ProdukPageState();
10. }
11.
12. class _ProdukPageState extends State<ProdukPage> {
13. @override
14. Widget build(BuildContext context) {
15. return Scaffold(
16. appBar: AppBar(
17. title: const Text('Data Produk'),
18. actions: [
19. GestureDetector(
20. // menampilkan icon +
21. child: const Icon(Icons.add),
22. onTap: () async {
23. // berpindah ke halaman ProdukForm
24. Navigator.push(
25. context,
26. MaterialPageRoute(
70
27. builder: (context) => const ProdukForm()));
28. })
29. ],
30. ),
31. body: ListView(
32. children: const [
33. // List 1
34. ItemProduk(
35. kodeProduk: "A001",
36. namaProduk: "Kulkas",
37. harga: 2500000,
38. ),
39. // List 2
40. ItemProduk(
41. kodeProduk: "A002",
42. namaProduk: "TV",
43. harga: 5000000,
44. ),
45. // List 3
46. ItemProduk(
47. kodeProduk: "A003",
48. namaProduk: "Mesin Cuci",
49. harga: 1500000,
50. ),
51. ],
52. ),
53. );
54. }
55. }
56.
57. class ItemProduk extends StatelessWidget {
58. final String? kodeProduk;
59. final String? namaProduk;
60. final int? harga;
61.
62. const ItemProduk({Key? key, this.kodeProduk, this.namaProduk, this.harga})
63. : super(key: key);
64.
65. @override
66. Widget build(BuildContext context) {
67. return GestureDetector(
68. child: Card(
69. child: ListTile(
70. title: Text(namaProduk.toString()),
71. subtitle: Text(harga.toString()),
72. ),
73. ),
74. onTap: () {
75. Navigator.push(
76. context,
77. MaterialPageRoute(
78. builder: (context) => ProdukDetail(
79. kodeProduk: kodeProduk,
80. namaProduk: namaProduk,
71
81. harga: harga,
82. )));
83. },
84. );
85. }
86. }
72
Sumber : codepolitan.com
Arsitektur API
Ada tiga arsitektur API yang sering digunakan oleh developer dalam pembangunan aplikasi.
Arsitektur ini berkaitan pada bentuk data yang dikirim. Adapun Arsitektur API yang sering digunakan
adalah 1. RPC
RPC merupakan teknologi untuk membuat komunikasi antara client side dan server side bisa
dilakukan dengan konsep sederhana.
RPC memiliki dua jenis, yaitu XML-RPC dan JSON-RPC. Sesuai namanya, XML-RPC menggunakan format
XML sebagai media perpindahan data, sedangkan JSON-RPC menggunakan JSON untuk perpindahan
data.
2. SOAP
Arsitektur API lainnya adalah SOAP (Simple Object Access Protocol). Arsitektur ini menggunakan XML
(Extensible Markup Language) yang memungkinkan semua data disimpan dalam dokumen.
3. REST
REST atau Representational State Transfer adalah arsitektur API yang cukup populer karena
kemudahan penggunaannya. Tak perlu coding yang panjang untuk menggunakannya.
REST menggunakan JSON sebagai bentuk datanya sehingga lebih ringan. Performa aplikasi pun
menjadi lebih baik.
73
Berikutnya akan muncul jendela Setup-XAMPP. Klik tombol Next untuk melanjutkan proses
berikutnya.
Selanjutnya akan muncul jendela Select Components, yang meminta untuk memilih aplikasi yang
akan diinstall. Centang saja semua kemudian klik tombol Next.
Kemudian akan muncul jendela Installation Folder, dimana anda diminta untuk menentukan lokasi
penyimpanan folder xampp, secara bawaan akan diarahkan ke lokasi c:\xampp. Jika anda ingin
menyimpannya di folder lain, anda dapat menekan tombol bergambar folder (Browse), kemudian
klik tombol Next.
74
Kita akan menjumpai jendela tawaran untuk mempelajari lebih lanjut tentang Bitnami.
Silahkan checklist jika ingin mempelajari lebih lanjut. Bitnami adalah pustaka dari aplikasi
client server yang populer seperti misalnya CMS WordPress atau Drupal, dengan penawaran
kemudahan dalam installasi hanya dengan satu klik. Kemudian klik tombol Next.
Kemudian muncul jendela Ready To Install yang menunjukkan xampp sudah siap di install.
Kemudian klik tombol Next.
75
Dan proses installasi pun berjalan.
Tunggu hingga proses install selesai dan muncul jendela sebagai berikut.
76
Klik tombol Finish setelah itu akan muncul jendela Xampp Control Panel yang berguna untuk
menjalankan server.
Klik tombol Start pada kolom Actions untuk module Apache dan MySQL.
77
Untuk mengetahui apakah installasi telah berhasil atau tidak, ketikkan ‘localhost/’ pada browser,
jika berhasil akan muncul halaman seperti gambar dibawah.
Install Postman
Postman adalah sebuah aplikasi fungsinya adalah sebagai REST Client atau istilahnya adalah
aplikasi yang digunakan untuk melakukan uji coba REST API yang telah kita buat. Postman ini
merupakan tools wajib bagi para developer yang bergerak pada pembuatan API, fungsi utama
postman ini adalah sebagai GUI API Caller Pemanggil. namun sekarang postman juga
menyediakan fitur lain yaitu Sharing Collection API for Documentation (free), Testing API
(free), Realtime Collaboration Team (paid), Monitoring API (paid), Integration (paid).
Postman tersedia sebagai aplikasi asli untuk sistem operasi macOS, Windows (32-bit dan 64-bit),
dan Linux (32-bit dan 64-bit). Untuk mendapatkan aplikasi Postman, dapat diunduh pada website
78
resminya yanitu getpostman.com atau dapat diunduk pada halaman
https://www.postman.com/downloads/
Setelah berhasil mengunduh paket instalasi postman, kemudian jalankan dengan cara klik dua kali.
Pilih run jika muncul pop up seperti berikut :
Kemudian tunggu hingga proses instalasi selesai dan muncul seperti gambar berikut
API SPEC
API SPEC ini bermaksud untuk membuat standar API sebagai dokumentasi kepada pengembang
baik itu frontend maupun backend
A. Registrasi
EndPoint /registrasi
Method POST
79
Body {
"nama" : "string",
"email" : "string, unique",
"password" : "string" }
Response {
"code" : "integer",
"status" : "boolean",
"data" : "string"
}
B. Login
EndPoint /login
Method POST
Body {
"email" : "string"
"password" : "string" }
Response {
"code" : "integer",
"status" : "boolean",
"data" : {
"token" : "string",
"user" : {
"id" : "integer",
"email" : "string",
}
}
}
C. Produk
1. List Produk
EndPoint /produk
Method GET
Response {
"code" : "integer",
"status" : "boolean",
"data" : [
80
{
"id" : "integer",
"kode_produk" : "string",
"nama_produk" : "string",
"harga" : "integer",
},
{
"id" : "integer",
"kode_produk" : "string",
"nama_produk" : "string",
"harga" : "integer",
}
]
}
2. Create Produk
EndPoint /produk
Method POST
Body {
"kode_produk" : "string",
"nama_produk" : "string",
"harga" : "integer" }
Response {
"code" : "integer",
"status" : "boolean",
"data" : {
"id" : "integer",
"kode_produk" : "string",
"nama_produk" : "string",
"harga" : "integer",
}
}
3. Update Produk
EndPoint /produk/{id}/update
Method POST
Body {
"kode_produk" : "string",
"nama_produk" : "string",
"harga" : "integer" }
81
Response {
"code" : "integer",
"status" : "boolean",
"data" : "boolean"
}
4. Show Produk
EndPoint /produk/{id}
Method GET
Response {
"code" : "integer",
"status" : "boolean",
"data" : {
"id" : "integer",
"kode_produk" : "string",
"nama_produk" : "string",
"harga" : "integer",
}
}
5. Delete Produk
EndPoint /produk/{id}
Method DELETE
Response {
"code" : "integer",
"status" : "boolean",
"data" : "boolean"
}
Pembuatan Database
Buat database dengan nama : toko_api
82
CREATE table member ( id INT NOT
NULL AUTO_INCREMENT, nama
VARCHAR(255) NOT NULL, email
VARCHAR(255) NOT NULL, password
VARCHAR(255) NOT NULL,
PRIMARY KEY(id)
);
83
Installasi CodeIgniter 4 sebagai Restful API
Selanjutnya install projek CodeIgniter pada web server (pada folder C:\xampp\htdocs)
84
Kemudian ubah nama folder menjadi toko-api. Pada projek buka file Database.php yang
public $default = [
'DSN' => '',
'hostname' => 'localhost',
'username' => '',
'password' => '',
'database' => '',
'DBDriver' => 'MySQLi',
'DBPrefix' => '',
'pConnect' => false,
'DBDebug' => (ENVIRONMENT !== 'production'),
'charset' => 'utf8',
'DBCollat' => 'utf8_general_ci',
'swapPre' => '',
'encrypt' => false,
'compress' => false,
'strictOn' => false,
'failover' => [],
'port' => 3306, ];
public $default = [
'DSN' => '',
'hostname' => 'localhost',
85
'username' => 'root',
'password' => '',
'database' => 'toko_api',
'DBDriver' => 'MySQLi',
'DBPrefix' => '',
'production'),
'pConnect' => false,
'DBDebug' => (ENVIRONMENT !== ,
'charset' => 'utf8' ,
'DBCollat ' => 'utf8_general_ci'
'swapPre' => '',
'encrypt' => false,
'compress' => false,
'strictOn' false,
=>
'failover' ];
=> [],
'port' => 3306 ,
86
Registrasi
Membuat model Registrasi
Buat sebuah file dengan nama MRegistrasi.php pada folder app/Models
87
Kemudian pada file RegistrasiController.php tersebut masukkan kode berikut
1. <?php
2.
3. namespace App\Controllers;
4.
5. use App\Models\MRegistrasi;
6.
7. class RegistrasiController extends RestfulController
8. {
9.
10. public function registrasi()
11. {
12. $data = [
13. 'nama' => $this->request->getVar('nama'),
14. 'email' => $this->request->getVar('email'),
15. 'password' => password_hash($this->request->getVar('password'),
PASSWORD_DEFAULT)
16. ];
17.
18. $model = new MRegistrasi();
19. $model->save($data);
20. return $this->responseHasil(200, true, "Registrasi Berhasil");
21. }
22. }
Kemudian lihat baris ke 34, telah terdapat routing dengan method get, kita akan menambahkan
routing untuk registrasi sehingga kode menjadi seperti berikut
/*
* -------------------------------------------------------------------- *
Route Definitions
* --------------------------------------------------------------------
*/
88
// We get a performance increase by specifying the default
// route since we don't have to scan directories.
$routes->get('/', 'Home::index');
$routes->post('/registrasi', 'RegistrasiController::registrasi);
Pada baris terakhir kita menambahkan routing registrasi agar dapat diakses dengan method
POST. Untuk mengakses registrasi, kita gunakan Postman dengan alamat url
localhost/tokoapi/public/registrasi dengan method POST
Adapun langkah menggunakan postman untuk menguji Rest API yang telah dibuat adalah sebagai
berikut:
6. Kemudian isi dengan format JSON sesuai dengan field request pada RegistrasiController pada
fungsi registrasi yaitu nama, email, password kemudian klik tombol Send
89
$data = [
'nama' => $this->request->getPost('nama'),
'email' => $this->request->getPost('email'),
'password' => password_hash($this->request-
>getPost('password'), PASSWORD_DEFAULT)
];
Contoh isian data
{
"nama":"Administrator",
"email":"[email protected]",
"password":"admin"
}
Login
Membuat model Member
Buat sebuah file dengan nama MMember.php pada folder app\Models dan ketikkan kode
berikut
1. <?php
2.
3. namespace App\Models;
4.
5. use CodeIgniter\Model;
6.
7. class MMember extends Model
8. {
9. protected $table = 'member';
10. }
90
1. <?php
2.
3. namespace App\Models;
4.
5. use CodeIgniter\Model;
6.
7. class MLogin extends Model
8. {
9. protected $table = 'member_token';
10. protected $allowedFields = ['member_id', 'auth_key'];
11. }
91
46. for ($i = 0; $i < $length; $i++) {
47. $str .= $karakkter[rand(0, $panjang_karakter - 1)];
48. }
49. return $str;
50. }
51. }
92
$routes->post( '/registrasi', 'RegistrasiController::registrasi');
$routes->post( '/login', 'LoginController::login');
Mencoba Rest
Silahkan coba Rest API dengan memasukkan url http://localhost/toko-api/public/login dengan
method POST
CRUD Produk
Membuat model Produk
Buat sebuah file dengan nama MProduk.php pada folder app/ Models dan ketikkan kode berikut
1. <?php
2.
3. namespace App\Models;
4.
5. use CodeIgniter\Model;
6.
7. class MProduk extends Model
8. {
9. protected $table = 'produk';
10. protected $primaryKey = 'id';
11. protected $allowedFields = ['kode_produk', 'nama_produk', 'harga'];
12. }
94
$model = new MProduk();
$model->update($id, $data);
$produk = $model->find($id);
95
Membuat fungsi delete produk
public function hapus($id)
{
$model = new MProduk();
$produk = $model->delete($id);
96
51.
52. public function hapus($id)
53. {
54. $model = new MProduk();
55. $produk = $model->delete($id);
56.
57. return $this->responseHasil(200, true, $produk);
58. }
59. }
Mencoba Rest
Create Produk (localhost/toko-api/public/produk) dengan method POST
97
Show Produk (localhost/toko-api/public/produk/{id}) dengan method GET
98
Membuat Model
Buat folder dengan nama model pada folder lib
99
Login
Buat sebuah file dengan nama login.dart pada folder model. Kemudian masukkan kode berikut
1. class Login {
2. int? code;
3. bool? status;
4. String? token;
5. int? userID;
6. String? userEmail;
7.
8. Login({this.code, this.status, this.token, this.userID, this.userEmail});
9.
10. factory Login.fromJson(Map<String, dynamic> obj) {
11. return Login(
12. code: obj['code'],
13. status: obj['status'],
14. token: obj['data']['token'],
15. userID: obj['data']['user']['id'],
16. userEmail: obj['data']['user']['email']);
17. }
100
18. }
Registrasi
Buat sebuah file dengan nama registrasi.dart pada folder model. Kemudian masukkan kode berikut
1. class Registrasi {
2. int? code;
3. bool? status;
4. String? data;
5.
6. Registrasi({this.code, this.status, this.data});
7.
8. factory Registrasi.fromJson(Map<String, dynamic> obj) {
9. return Registrasi(
10. code: obj['code'],
11. status: obj['status'],
12. data: obj['data']);
13. }
14. }
Produk
Buat sebuah file dengan nama produk.dart pada folder model. Kemudian ketikkan kode berikut
1. class Produk {
2. int? id;
3. String? kodeProduk;
4. String? namaProduk;
5. int? hargaProduk;
6.
7. Produk({this.id, this.kodeProduk, this.namaProduk, this.hargaProduk});
8.
9. factory Produk.fromJson(Map<String, dynamic> obj) {
10. return Produk(
11. code: obj['id'],
12. kodeProduk: obj['kode_produk'],
13. namaProduk: obj['nama_produk'],
14. hargaProduk: obj['harga']
15. );
16. }
17. }
Membuat Halaman
Pertama kita akan memecah bagian-bagian kode menjadi beberapa bagian, adapun untuk tampilan,
dikelompokkan kedalam folder ui.
101
Registrasi
Buat sebuah file dengan nama registrasi_page.dart pada folder ui.
102
Pada file registrasi_page.dart ketikkan kode berikut
1. import 'package:flutter/material.dart';
2.
3. class RegistrasiPage extends StatefulWidget { 4.
const RegistrasiPage({Key? key}) : super(key: key);
5.
6. @override
7. _RegistrasiPageState createState() => _RegistrasiPageState();
8. }
9.
10. class _RegistrasiPageState extends State<RegistrasiPage> {
11. final _formKey = GlobalKey<FormState>(); 12. bool _isLoading =
false;
13.
14. final _namaTextboxController = TextEditingController();
15. final _emailTextboxController = TextEditingController(); 16. final
_passwordTextboxController = TextEditingController();
17.
18. @override
19. Widget build(BuildContext context) {
20. return Scaffold(
21. appBar: AppBar(
22. title: const Text("Registrasi"),
23. ),
24. body: SingleChildScrollView(
25. child: Padding(
26. padding: const EdgeInsets.all(8.0),
27. child: Form(
103
28. key: _formKey,
29. child: Column(
104
79. },
80. );
81. }
82.
83. //Membuat Textbox password
84. Widget _passwordTextField() {
85. return TextFormField(
86. decoration: const InputDecoration(labelText: "Password"),
87. keyboardType: TextInputType.text,
88. obscureText: true,
89. controller: _passwordTextboxController,
90. validator: (value) {
91. //jika karakter yang dimasukkan kurang dari 6 karakter
92. if (value!.length < 6) {
Untuk mencoba halaman registrasi_page, buka file main.dart kemudian ubah kode menjadi seperti
berikut ini
105
1. import 'package:flutter/material.dart' ;
2. import 'package:tokokita/ui/registrasi_page.dart';
3.
4. void main() {
5. runApp(const MyApp());
6. }
7.
8. class MyApp extends StatelessWidget {
9. const MyApp({Key? key}) : super(key: key);
10.
11. @override
12. Widget build(BuildContext context) {
13. return const MaterialApp(
14. title: 'Toko Kita',
15. debugShowCheckedModeBanner: false,
16. home: RegistrasiPage(),
17. );
18. }
19. }
Login
Buat sebuah file dengan nama login_page.dart pada folder ui dengan kode berikut
107
108
94. style: TextStyle(color: Colors.blue),
95. ),
96. onTap: () {
97. Navigator.push(context,
98. MaterialPageRoute(builder: (context) => const RegistrasiPage()));
99. },
100. ),
101. );
102. }
103. }
93. "Registrasi",
Untuk mencobanya modifikasi file main.dart dimana pada bagian home akan memanggil
LoginPage()
1. import 'package:flutter/material.dart' ;
2. import 'package:tokokita/ui/login_page.dart';
3.
4. void main() {
5. runApp(const MyApp());
6. }
7.
8. class MyApp extends StatelessWidget {
9. const MyApp({Key? key}) : super(key: key);
10.
11. @override
12. Widget build(BuildContext context) {
13. return const MaterialApp(
14. title: 'Toko Kita',
15. debugShowCheckedModeBanner: false,
16. home: LoginPage(),
17. );
18. }
19. }
Pada saat dijalankan akan terdapat link untuk membuka halaman registrasi pada bagian
bawah form
109
Form Produk
Form produk yang akan kita buat berikut ini memiliki 2 fungsi yaitu untuk menambah data
produk dan mengubah data produk
Buat sebuah file dengan nama produk_form.dart pada folder ui dengan kode berikut
1. import 'package:flutter/material.dart'; 2.
import 'package:tokokita/model/produk.dart';
3.
4. class ProdukForm extends StatefulWidget { 5.
Produk? produk;
6.
7. ProdukForm({Key? key, this.produk}) : super(key: key);
8.
9. @override
10. _ProdukFormState createState() => _ProdukFormState();
11. }
12.
13. class _ProdukFormState extends State<ProdukForm> {
14. final _formKey = GlobalKey<FormState>();
15. bool _isLoading = false;
16. String judul = "TAMBAH PRODUK";
17. String tombolSubmit = "SIMPAN";
18.
19. final _kodeProdukTextboxController = TextEditingController();
20. final _namaProdukTextboxController = TextEditingController(); 21. final
_hargaProdukTextboxController = TextEditingController();
22.
110
23. @override
24. void initState() {
111
25. super.initState();
26. isUpdate();
27. }
28.
29. isUpdate() {
30. if (widget.produk != null) {
31. setState(() {
112
113
86. decoration: const InputDecoration(labelText: "Nama Produk"),
87. keyboardType: TextInputType.text,
88. controller: _namaProdukTextboxController,
89. validator: (value) {
Detail Produk
100. return TextFormField(
101. decoration: const InputDecoration(labelText: "Harga"),
102. keyboardType: TextInputType.number,
103. controller: _hargaProdukTextboxController,
104. validator: (value) {
105. if (value!.isEmpty) {
106. return "Harga harus diisi";
107. }
108. return null;
109. },
110. );
111. }
112.
113. //Membuat Tombol Simpan/Ubah
114. Widget _buttonSubmit() {
115. return OutlinedButton(
116. child: Text(tombolSubmit),
117. onPressed: () {
118. var validate = _formKey.currentState!.validate();
119. });
120. }
121. }
90. if (value!.isEmpty) {
91. return "Nama Produk harus diisi";
92. }
93. return null;
94. },
95. );
96. }
97.
98. //Membuat Textbox Harga Produk
99. Widget _hargaProdukTextField() {
Buat sebuah file dengan nama produk_detail.dart pada folder ui dengan kode berikut
114
1. import 'package:flutter/material.dart' ;
2. import 'package:tokokita/model/produk.dart';
3. import 'package:tokokita/ui/produk_form.dart';
4.
5. class ProdukDetail extends StatefulWidget {
6. Produk? produk;
7.
8. ProdukDetail({Key? key, this.produk}) : super(key: key);
9.
10. @override
11. _ProdukDetailState createState() => _ProdukDetailState();
12. }
13.
14. class _ProdukDetailState extends State<ProdukDetail> {
15. @override
16. Widget build(BuildContext context) {
17. return Scaffold(
18. appBar: AppBar(
19. title: const Text('Detail Produk'),
20. ),
21. body: Center(
22. child: Column(
23. children: [
24. Text(
25. "Kode : ${widget.produk!.kodeProduk}",
26. style: const TextStyle(fontSize: 20.0),
27. ),
28. Text(
29. "Nama : ${widget.produk!.namaProduk}",
30. style: const TextStyle(fontSize: 18.0),
31. ),
32. Text(
33. "Harga : Rp. ${widget.produk!.hargaProduk.toString()}",
115
116
34. style: const TextStyle(fontSize: 18.0),
117
Tampil List Produk
Buat sebuah file dengan nama produk_page.dart pada folder ui dengan kode berikut
1. import 'package:flutter/material.dart';
2. import 'package:tokokita/model/produk.dart';
3. import 'package:tokokita/ui/produk_detail.dart'; 4. import
'package:tokokita/ui/produk_form.dart';
5.
6. class ProdukPage extends StatefulWidget { 7.
const ProdukPage({Key? key}) : super(key: key);
8.
9. @override
10. _ProdukPageState createState() => _ProdukPageState();
11. }
12.
13. class _ProdukPageState extends State<ProdukPage> {
14. @override
15. Widget build(BuildContext context) {
16. return Scaffold(
17. appBar: AppBar(
18. title: const Text('List Produk'),
19. actions: [
20. Padding(
21. padding: const EdgeInsets.only(right: 20.0),
22. child: GestureDetector(
23. child: const Icon(Icons.add, size: 26.0),
24. onTap: () async {
25. Navigator.push(context,
26. MaterialPageRoute(builder: (context) => ProdukForm()));
27. },
28. ))
29. ],
30. ),
31. drawer: Drawer(
32. child: ListView(
33. children: [
34. ListTile(
35. title: const Text('Logout'),
36. trailing: const Icon(Icons.logout),
37. onTap: () async {},
38. )
39. ],
40. ),
41. ),
42. body: ListView(
43. children: [
44. ItemProduk(
45. produk: Produk(
46. id: 1,
47. kodeProduk: 'A001',
118
48. namaProduk: 'Kamera',
49. hargaProduk: 5000000)),
50. ItemProduk(
51. produk: Produk(
52. id: 2,
53. kodeProduk: 'A002',
54. namaProduk: 'Kulkas',
55. hargaProduk: 2500000)),
56. ItemProduk(
57. produk: Produk(
58. id: 3,
59. kodeProduk: 'A003',
60. namaProduk: 'Mesin Cuci',
61. hargaProduk: 2000000)),
62. ],
63. ));
64. }
65. }
66.
67. class ItemProduk extends StatelessWidget {
68. final Produk produk;
69.
70. const ItemProduk({Key? key, required this.produk}) : super(key: key);
71.
72. @override
73. Widget build(BuildContext context) {
74. return GestureDetector(
75. onTap: () {
76. Navigator.push(
77. context,
78. MaterialPageRoute(
79. builder: (context) => ProdukDetail(
80. produk: produk,
81. )));
82. },
83. child: Card(
84. child: ListTile(
85. title: Text(produk.namaProduk!),
86. subtitle: Text(produk.hargaProduk.toString()),
87. ),
88. ),
89. );
90. }
91. }
119
1. import 'package:flutter/material.dart' ;
2. import 'package:tokokita/ui/produk_page.dart';
3.
4. void main() {
5. runApp(const MyApp());
6. }
7.
8. class MyApp extends StatelessWidget {
9. const MyApp({Key? key}) : super(key: key);
10.
11. @override
12. Widget build(BuildContext context) {
13. return const MaterialApp(
14. title: 'Toko Kita',
15. debugShowCheckedModeBanner: false,
16. home: ProdukPage(),
17. );
18. }
19. }
120
Pada saat tombol tambah diklik maka akan muncul form produk seperti berikut
121
Jika salah satu data produk diklik maka akan muncul detail produk
Ketika tombol EDIT diklik maka akan muncul form produk untuk mengubah data produk
122
Pada materi selanjutnya akan ada modifikasi pada tampil produk agar dapat menampilkan
data dari Rest API serta modifikasi pada Form Produk sehingga dapat berfungsi untuk
menyimpan ataupun mengubah data pada Rest API
123
Kemudian pada folder helpers buat sebuah file dengan nama user_info.dart dan masukkan
kode berikut
1. import 'package:shared_preferences/shared_preferences.dart';
2.
3. class UserInfo {
4. Future setToken(String value) async {
5. final SharedPreferences pref = await SharedPreferences.getInstance();
6. return pref.setString("token", value); 7. }
8.
9. Future<String?> getToken() async {
10. final SharedPreferences pref = await SharedPreferences.getInstance();
124
11. return pref.getString("token");
12. }
13.
14. Future setUserID(int value) async {
15. final SharedPreferences pref = await SharedPreferences.getInstance();
16. return pref.setInt("userID", value);
17. }
18.
19. Future<int?> getUserID() async {
20. final SharedPreferences pref = await SharedPreferences.getInstance();
21. return pref.getInt("userID");
22. }
23.
24. Future logout() async {
25. final SharedPreferences pref = await SharedPreferences.getInstance();
26. pref.clear();
27. }
28. }
Http request
Membuat Modul Error Handling
Buat sebuah file pada folder helpers dengan nama app_exception.dart kemudian
ketikkan kode berikut
125
Pada file ini berfungsi sebagai penanganan jika terjadi error saat melakukan
permintaan atau pengiriman ke Rest API
1. import 'dart:io';
2.
3. import 'package:http/http.dart' as http;
4. import 'package:tokokita/helpers/user_info.dart'; 5. import
'app_exception.dart';
6.
7. class Api {
8. Future<dynamic> post(dynamic url, dynamic data) async {
9. var token = await UserInfo().getToken();
10. var responseJson;
11. try {
12. final response = await http.post(Uri.parse(url),
13. body: data,
14. headers: {HttpHeaders.authorizationHeader: "Bearer $token"});
15. responseJson = _returnResponse(response);
16. } on SocketException {
17. throw FetchDataException('No Internet connection');
18. }
19. return responseJson; 20. }
21.
22. Future<dynamic> get(dynamic url) async {
23. var token = await UserInfo().getToken();
24. var responseJson;
25. try {
26. final response = await http.get(url,
27. headers: {HttpHeaders.authorizationHeader: "Bearer $token"});
28. responseJson = _returnResponse(response);
29. } on SocketException {
30. throw FetchDataException('No Internet connection');
31. }
32. return responseJson; 33. }
34.
35. Future<dynamic> delete(dynamic url) async {
36. var token = await UserInfo().getToken();
37. var responseJson;
38. try {
39. final response = await http.delete(url,
40. headers: {HttpHeaders.authorizationHeader: "Bearer $token"});
41. responseJson = _returnResponse(response);
42. } on SocketException {
43. throw FetchDataException('No Internet connection');
44. }
45. return responseJson; 46. }
47.
126
48. dynamic _returnResponse(http.Response response) {
49. switch (response.statusCode) {
50. case 200:
51. return response;
52. case 400:
53. throw BadRequestException(response.body.toString());
54. case 401:
55. case 403:
56. throw UnauthorisedException(response.body.toString());
57. case 422:
58. throw InvalidInputException(response.body.toString());
59. case 500:
60. default:
61. throw FetchDataException(
62. 'Error occured while Communication with Server with StatusCode :
${response.statusCode}');
63. }
64. }
65. }
1. class ApiUrl {
2. static const String baseUrl = 'http://10.0.2.2/toko-api/public';
3.
4. static const String registrasi = baseUrl + '/registrasi';
5. static const String login = baseUrl + '/login';
6. static const String listProduk = baseUrl + '/produk'; 7. static const String
createProduk = baseUrl + '/produk';
8.
9. static String updateProduk(int id) {
10. return baseUrl + '/produk/' + id.toString() + '/update'; 11. }
12.
13. static String showProduk(int id) {
14. return baseUrl + '/produk/' + id.toString(); 15. }
16.
17. static String deleteProduk(int id) {
18. return baseUrl + '/produk/' + id.toString();
19. }
20. }
Pada baris kedua (baseUrl) merupakan alamat IP dari Rest API, untuk memeriksa apakah
terhubung dengan emulator atau tidak, dapat dilakukan dengan memasukkan alamat
tersebut pada browser yang ada pada emulator atau handphone android yang
terkoneksi dengan laptop
127
Membuat Bloc
Buat sebuah folder bernama bloc. Di dalam folder ini berisis file-file yang berfungsi sebagai
controller baik itu untuk melakukan proses login, registrasi dan lain-lain.
128
Registrasi
Buat sebuah file dengan nama registrasi_bloc.dart pada folder bloc. Kemudian masukkan kode
berikut
1. import 'dart:convert';
2.
3. import 'package:tokokita/helpers/api.dart';
4. import 'package:tokokita/helpers/api_url.dart';
5. import 'package:tokokita/model/registrasi.dart';
129
6.
7. class RegistrasiBloc {
8. static Future<Registrasi> registrasi(
9. {String? nama, String? email, String? password}) async {
10. String apiUrl = ApiUrl.registrasi;
11.
12. var body = {"nama": nama, "email": email, "password": password};
13.
14. var response = await Api().post(apiUrl, body);
15. var jsonObj = json.decode(response.body);
16. return Registrasi.fromJson(jsonObj);
17. }
18. }
Login
Buat sebuah file dengan nama login_bloc.dart pada folder bloc. Kemudian masukkan kode
berikut
1. import 'dart:convert';
2.
3. import 'package:tokokita/helpers/api.dart';
4. import 'package:tokokita/helpers/api_url.dart'; 5. import
'package:tokokita/model/login.dart';
6.
7. class LoginBloc {
8. static Future<Login> login({String? email, String? password}) async {
9. String apiUrl = ApiUrl.login;
10. var body = {"email": email, "password": password};
11. var response = await Api().post(apiUrl, body);
12. var jsonObj = json.decode(response.body);
13. return Login.fromJson(jsonObj);
14. }
15. }
Logout
Buat sebuah file dengan nama logout_bloc.dart pada folder bloc. Kemudian masukkan kode
berikut
1. import 'package:tokokita/helpers/user_info.dart';
2.
3. class LogoutBloc{
4. static Future logout() async {
5. await UserInfo().logout();
6. }
7. }
Produk
Pada bagian ini akan dibuat beberapa fungsi untuk mengambil, mengubah dan menghapus
data produk dari Rest API. Buat sebuah file dengan nama produk_bloc.dart pada folder bloc
kemudian masukkan kode berikut
130
1. import 'dart:convert';
2.
3. import 'package:tokokita/helpers/api.dart';
4. import 'package:tokokita/helpers/api_url.dart'; 5. import
'package:tokokita/model/produk.dart';
6.
7. class ProdukBloc {
8. static Future<List<Produk>> getProduks() async {
9. String apiUrl = ApiUrl.listProduk;
10. var response = await Api().get(apiUrl);
11. var jsonObj = json.decode(response.body);
12. List<dynamic> listProduk = (jsonObj as Map<String, dynamic>)['data'];
13. List<Produk> produks = [];
14. for (int i = 0; i < listProduk.length; i++) {
15. produks.add(Produk.fromJson(listProduk[i]));
16. }
17. return produks; 18. }
19.
20. static Future addProduk({Produk? produk}) async { 21.
String apiUrl = ApiUrl.createProduk;
22.
23. var body = {
24. "kode_produk": produk!.kodeProduk,
25. "nama_produk": produk.namaProduk,
26. "harga": produk.hargaProduk.toString() 27. };
28.
29. var response = await Api().post(apiUrl, body);
30. var jsonObj = json.decode(response.body);
31. return jsonObj['status']; 32. }
33.
34. static Future<bool> updateProduk({required Produk produk}) async { 35.
String apiUrl = ApiUrl.updateProduk(produk.id!);
36.
37. var body = {
38. "kode_produk": produk.kodeProduk,
39. "nama_produk": produk.namaProduk,
40. "harga": produk.hargaProduk.toString()
41. };
42. print("Body : $body");
43. var response = await Api().post(apiUrl, body);
44. var jsonObj = json.decode(response.body);
45. return jsonObj['data']; 46. }
47.
48. static Future<bool> deleteProduk({int? id}) async { 49.
String apiUrl = ApiUrl.deleteProduk(id!);
50.
51. var response = await Api().delete(apiUrl);
52. var jsonObj = json.decode(response.body);
53. return (jsonObj as Map<String, dynamic>)['data'];
131
54. }
55. }
Menyatukan Fungsionalitas
Membuat Common Dialog Widget
Pada bagian ini akan dibuat dua buah dialog yang nantinya akan digunakan pada tampilan.
Buat sebuah folder dengan nama widget
132
1. import 'package:flutter/material.dart' ;
2.
3. class Consts {
4. Consts._();
5.
6. static const double padding = 16.0;
7. static const double avatarRadius = 66.0;
8. }
9.
10. class SuccessDialog extends StatelessWidget {
11. final String? description;
12. final VoidCallback? okClick;
13.
14. const SuccessDialog({Key? key, this.description, this.okClick})
15. : super(key: key);
16.
17. @override
18. Widget build(BuildContext context) {
19. return Dialog(
20. shape: RoundedRectangleBorder(
21. borderRadius: BorderRadius.circular(Consts.padding)),
22. elevation: 0.0,
23. backgroundColor: Colors.transparent,
133
24. child: dialogContent(context),
134
80. );
81. }
82. }
Kemudian buat file dengan nama warning_dialog.dart dengan kode
135
59. description!,
60. textAlign: TextAlign.center,
61. style: const TextStyle(
62. fontSize: 16.0,
63. ),
64. ),
136
65. const SizedBox(height: 24.0),
66. Align(
67. alignment: Alignment.bottomRight,
68. child: ElevatedButton(
69. onPressed: () {
70. Navigator.of(context).pop(); // To close the dialog
71. okClick!();
72. },
73. child: const Text("OK"),
74. ),
75. )
76. ],
77. ),
78. );
79. }
80. }
Modifikasi main.dart
Buka kembali file main.dart kita akan memodifikasi file tersebut dengan kondisi jika belum
login maka akan membuka halaman login, namun jika sudah login maka akan membuka
halaman list produk
137
34. page = const LoginPage();
35. });
36. }
37. }
38.
39. @override
40. Widget build(BuildContext context) {
41. return MaterialApp(
42. title: 'Toko Kita',
43. debugShowCheckedModeBanner: false,
44. home: page,
45. );
46. }
47. }
Modifikasi registrasi_page.dart
Buka file registrasi_page.dart pada folder ui kemudian modifikasi fungsi _buttonRegistrasi dan
tambahkan fungsi dengan nama _submit seperti dibawah
119. //Membuat Tombol Registrasi
120. Widget _buttonRegistrasi() {
121. return ElevatedButton(
122. child: const Text("Registrasi"),
123. onPressed: () {
124. var validate = _formKey.currentState!.validate();
125. if (validate) {
126. if (!_isLoading) _submit();
127. }
138
128. });
129. }
130.
131. void _submit() {
132. _formKey.currentState!.save();
133. setState(() {
134. _isLoading = true;
135. });
136. RegistrasiBloc.registrasi(
137. nama: _namaTextboxController.text,
138. email: _emailTextboxController.text,
139. password: _passwordTextboxController.text)
140. .then((value) {
141. showDialog(
142. context: context,
143. barrierDismissible: false,
144. builder: (BuildContext context) => SuccessDialog(
145. description: "Registrasi berhasil, silahkan login",
146. okClick: () {
147. Navigator.pop(context);
148. },
149. ));
150. }, onError: (error) {
151. showDialog(
152. context: context,
153. barrierDismissible: false,
154. builder: (BuildContext context) => const WarningDialog(
155. description: "Registrasi gagal, silahkan coba lagi",
156. ));
157. });
158. setState(() {
159. _isLoading = false;
160. });
161. }
139
Sehingga keseluruhan kode pada registrasi_page.dart menjadi seperti berikut
1. import 'package:flutter/material.dart';
2. import 'package:tokokita/bloc/registrasi_bloc.dart';
3. import 'package:tokokita/widget/success_dialog.dart';
4. import 'package:tokokita/widget/warning_dialog.dart';
5.
6. class RegistrasiPage extends StatefulWidget { 7.
const RegistrasiPage({Key? key}) : super(key: key);
8.
9. @override
10. _RegistrasiPageState createState() => _RegistrasiPageState();
11. }
12.
13. class _RegistrasiPageState extends State<RegistrasiPage> {
14. final _formKey = GlobalKey<FormState>(); 15. bool _isLoading =
false;
16.
17. final _namaTextboxController = TextEditingController();
18. final _emailTextboxController = TextEditingController(); 19. final
_passwordTextboxController = TextEditingController();
20.
21. @override
22. Widget build(BuildContext context) {
23. return Scaffold(
24. appBar: AppBar(
25. title: const Text("Registrasi"),
26. ),
27. body: SingleChildScrollView(
28. child: Padding(
29. padding: const EdgeInsets.all(8.0),
30. child: Form(
31. key: _formKey,
32. child: Column(
33. mainAxisAlignment: MainAxisAlignment.center,
34. children: [
35. _namaTextField(),
36. _emailTextField(),
37. _passwordTextField(),
38. _passwordKonfirmasiTextField(),
39. _buttonRegistrasi()
40. ],
41. ),
42. ),
43. ),
44. ),
45. ); 46. }
47.
48. //Membuat Textbox Nama
49. Widget _namaTextField() {
50. return TextFormField(
51. decoration: const InputDecoration(labelText: "Nama"),
52. keyboardType: TextInputType.text,
53. controller: _namaTextboxController,
54. validator: (value) {
55. if (value!.length < 3) {
140
56. return "Nama harus diisi minimal 3 karakter";
57. }
58. return null;
59. },
60. );
61. }
62.
63. //Membuat Textbox email
64. Widget _emailTextField() {
65. return TextFormField(
66. decoration: const InputDecoration(labelText: "Email"),
67. keyboardType: TextInputType.emailAddress,
68. controller: _emailTextboxController,
69. validator: (value) {
70. //validasi harus diisi
71. if (value!.isEmpty) {
72. return 'Email harus diisi';
73. }
74. //validasi email
75. Pattern pattern =
76. r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0
-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zAZ]{2,}))$';
77. RegExp regex = RegExp(pattern.toString());
78. if (!regex.hasMatch(value)) {
79. return "Email tidak valid";
80. }
81. return null;
82. },
83. ); 84. }
85.
86. //Membuat Textbox password
87. Widget _passwordTextField() {
88. return TextFormField(
89. decoration: const InputDecoration(labelText: "Password"),
90. keyboardType: TextInputType.text,
91. obscureText: true,
92. controller: _passwordTextboxController,
93. validator: (value) {
94. //jika karakter yang dimasukkan kurang dari 6 karakter
95. if (value!.length < 6) {
96. return "Password harus diisi minimal 6 karakter";
97. }
98. return null;
99. },
100. ); 101. } 102.
103. //membuat textbox Konfirmasi Password
104. Widget _passwordKonfirmasiTextField() {
105. return TextFormField(
106. decoration: const InputDecoration(labelText: "Konfirmasi Password"),
107. keyboardType: TextInputType.text,
108. obscureText: true,
109. validator: (value) {
110. //jika inputan tidak sama dengan password
111. if (value != _passwordTextboxController.text) {
112. return "Konfirmasi Password tidak sama";
113. }
114. return null;
115. },
141
116. ); 117. } 118.
119. //Membuat Tombol Registrasi
120. Widget _buttonRegistrasi() {
121. return ElevatedButton(
122. child: const Text("Registrasi"),
123. onPressed: () {
124. var validate = _formKey.currentState!.validate();
125. if (validate) {
126. if (!_isLoading) _submit();
127. }
128. });
129. }
130.
131. void _submit() {
132. _formKey.currentState!.save();
133. setState(() {
134. _isLoading = true;
135. });
136. RegistrasiBloc.registrasi(
137. nama: _namaTextboxController.text,
138. email: _emailTextboxController.text,
139. password: _passwordTextboxController.text)
140. .then((value) {
141. showDialog(
142. context: context,
143. barrierDismissible: false,
144. builder: (BuildContext context) => SuccessDialog(
145. description: "Registrasi berhasil, silahkan login",
146. okClick: () {
147. Navigator.pop(context);
148. },
149. ));
150. }, onError: (error) {
151. showDialog(
152. context: context,
153. barrierDismissible: false,
154. builder: (BuildContext context) => const WarningDialog(
155. description: "Registrasi gagal, silahkan coba lagi",
156. ));
157. });
158. setState(() {
159. _isLoading = false;
160. });
161. }
162. }
142
Modifikasi login_page.dart (fungsi login)
Buka file login_page.dart pada folder ui kemudian modifikasi fungsi _buttonLogin dan
tambahkan fungsi dengan nama _submit seperti dibawah
144
52. return TextFormField(
58. if (value!.isEmpty) {
60. }
62. },
63. );
64. }
65.
75. if (value!.isEmpty) {
77. }
79. },
145
80. );
81. }
82.
87. onPressed: () {
89. if (validate) {
91. }
92. });
93. }
94.
96. _formKey.currentState!.save();
97. setState(() {
99. });
100. LoginBloc.login(
106. Navigator.pushReplacement(
146
108. }, onError: (error) {
109. print(error);
110. showDialog(
115. ));
116. });
117. setState(() {
119. });
120. }
121.
127. "Registrasi",
129. ),
130. onTap: () {
131. Navigator.push(context,
134. ),
135. );
147
136. }
137. }
Modifikasi produk_page.dart
Menambahkan fungsi logout pada drawer
Agar link logout dapat berfungsi, akan ditambahkan kode pada drawer logout, seperti
berikut
148
33. drawer: Drawer(
34. child: ListView(
35. children: [
36. ListTile(
37. title: const Text('Logout'),
38. trailing: const Icon(Icons.logout),
39. onTap: () async {
40. await LogoutBloc.logout().then((value) => {
41. Navigator.pushReplacement(
42. context,
43. MaterialPageRoute(
44. builder: (context) => LoginPage()))
45. });
46. },
47. )
48. ],
49. ),
50. ),
51. body: ListView(
1. import 'package:flutter/material.dart';
2. import 'package:tokokita/bloc/logout_bloc.dart';
3. import 'package:tokokita/model/produk.dart';
4. import 'package:tokokita/ui/login_page.dart';
5. import 'package:tokokita/ui/produk_detail.dart';
6. import 'package:tokokita/ui/produk_form.dart';
7.
8. class ProdukPage extends StatefulWidget {
9. const ProdukPage({Key? key}) : super(key: key);
10.
11. @override
12. _ProdukPageState createState() => _ProdukPageState();
13. }
14.
15. class _ProdukPageState extends State<ProdukPage> {
16. @override
17. Widget build(BuildContext context) {
18. return Scaffold(
19. appBar: AppBar(
20. title: const Text('List Produk'),
21. actions: [
22. Padding(
23. padding: const EdgeInsets.only(right: 20.0),
24. child: GestureDetector(
25. child: const Icon(Icons.add, size: 26.0),
26. onTap: () async {
27. Navigator.push(context,
28. MaterialPageRoute(builder: (context) => ProdukForm()));
29. },
30. ))
31. ],
149
32. ),
33. drawer: Drawer(
34. child: ListView(
35. children: [
36. ListTile(
37. title: const Text('Logout'),
38. trailing: const Icon(Icons.logout),
39. onTap: () async {
40. await LogoutBloc.logout().then((value) => {
41. Navigator.pushReplacement(
42. context,
43. MaterialPageRoute(
44. builder: (context) => LoginPage()))
45. });
46. },
47. )
48. ],
49. ),
50. ),
51. body: ListView(
52. children: [
53. ItemProduk(
54. produk: Produk(
55. id: 1,
56. kodeProduk: 'A001',
57. namaProduk: 'Kamera',
58. hargaProduk: 5000000)),
59. ItemProduk(
60. produk: Produk(
61. id: 2,
62. kodeProduk: 'A002',
63. namaProduk: 'Kulkas',
64. hargaProduk: 2500000)),
65. ItemProduk(
66. produk: Produk(
150
Menampilkan Data Produk dari Rest API
Pada bagian ini akan dimodifikasi file produk_page.dart sehingga dapat menampilkan data
dari Rest API. Berikut kode keseluruhan
1. import 'package:flutter/material.dart';
2. import 'package:tokokita/bloc/logout_bloc.dart';
3. import 'package:tokokita/bloc/produk_bloc.dart';
4. import 'package:tokokita/model/produk.dart';
5. import 'package:tokokita/ui/login_page.dart';
6. import 'package:tokokita/ui/produk_detail.dart'; 7. import
'package:tokokita/ui/produk_form.dart';
8.
9. class ProdukPage extends StatefulWidget { 10.
const ProdukPage({Key? key}) : super(key: key);
11.
12. @override
13. _ProdukPageState createState() => _ProdukPageState();
14. }
15.
16. class _ProdukPageState extends State<ProdukPage> {
17. @override
18. Widget build(BuildContext context) {
151
19. return Scaffold(
20. appBar: AppBar(
21. title: const Text('List Produk'),
22. actions: [
23. Padding(
24. padding: const EdgeInsets.only(right: 20.0),
25. child: GestureDetector(
26. child: const Icon(Icons.add, size: 26.0),
27. onTap: () async {
28. Navigator.push(context,
29. MaterialPageRoute(builder: (context) => ProdukForm()));
30. },
31. ))
32. ],
33. ),
34. drawer: Drawer(
35. child: ListView(
36. children: [
37. ListTile(
38. title: const Text('Logout'),
39. trailing: const Icon(Icons.logout),
40. onTap: () async {
41. await LogoutBloc.logout().then((value) => {
42. Navigator.pushReplacement(context,
43. MaterialPageRoute(builder: (context) => LoginPage()))
44. });
45. },
46. )
47. ],
48. ),
49. ),
50. body: FutureBuilder<List>(
51. future: ProdukBloc.getProduks(),
52. builder: (context, snapshot) {
53. if (snapshot.hasError) print(snapshot.error);
54. return snapshot.hasData
55. ? ListProduk(
56. list: snapshot.data,
57. )
58. : const Center(
59. child: CircularProgressIndicator(),
60. );
61. },
62. ),
63. );
64. }
65. }
66.
67. class ListProduk extends StatelessWidget { 68.
final List? list;
69.
70. const ListProduk({Key? key, this.list}) : super(key: key);
71.
72. @override
73. Widget build(BuildContext context) {
74. return ListView.builder(
75. itemCount: list == null ? 0 : list!.length,
76. itemBuilder: (context, i) {
77. return ItemProduk(
152
78. produk: list![i],
79. );
80. });
81. }
82. }
83.
84. class ItemProduk extends StatelessWidget {
85. final Produk produk;
86.
87. const ItemProduk({Key? key, required this.produk}) : super(key: key);
88.
89. @override
90. Widget build(BuildContext context) {
91. return GestureDetector(
92. onTap: () {
93. Navigator.push(
94. context,
95. MaterialPageRoute(
96. builder: (context) => ProdukDetail(
97. produk: produk,
98. )));
99. },
100. child: Card(
101. child: ListTile(
102. title: Text(produk.namaProduk!),
103. subtitle: Text(produk.hargaProduk.toString()),
104. ),
105. ),
106. );
107. }
108. }
Adapun perubahan yang dilakukan adalah penambahan sebuah class bernama ListProduk
dengan kode
67. class ListProduk extends StatelessWidget {
68. final List? list;
69.
70. const ListProduk({Key? key, this.list}) : super(key: key);
71.
72. @override
73. Widget build(BuildContext context) {
74. return ListView.builder(
75. itemCount: list == null ? 0 : list!.length,
76. itemBuilder: (context, i) {
77. return ItemProduk(
78. produk: list![i],
79. );
80. });
81. }
82. }
153
53. if (snapshot.hasError) print(snapshot.error);
54. return snapshot.hasData
55. ? ListProduk(
56. list: snapshot.data,
57. )
58. : const Center(
59. child: CircularProgressIndicator(),
60. );
61. },
62. ),
Serta memasukkan beberapa package yang diperlukan
1. import 'package:flutter/material.dart' ;
2. import 'package:tokokita/bloc/logout_bloc.dart';
3. import 'package:tokokita/bloc/produk_bloc.dart';
4. import 'package:tokokita/model/produk.dart';
5. import 'package:tokokita/ui/login_page.dart';
6. import 'package:tokokita/ui/produk_detail.dart';
7. import 'package:tokokita/ui/produk_form.dart';
154
116. //Membuat Tombol Simpan/Ubah
117. Widget _buttonSubmit() {
118. return OutlinedButton(
119. child: Text(tombolSubmit),
120. onPressed: () {
121. var validate = _formKey.currentState!.validate();
122. if (validate) {
123. if (!_isLoading) {
124. if (widget.produk != null) {
125. //kondisi update produk
126.
127. } else {
128. //kondisi tambah produk
129. simpan();
130. }
131. }
132. }
133. });
134. }
135.
136. simpan() {
137. setState(() {
138. _isLoading = true;
139. });
140. Produk createProduk = Produk(id: null);
141. createProduk.kodeProduk = _kodeProdukTextboxController.text;
142. createProduk.namaProduk = _namaProdukTextboxController.text;
143. createProduk.hargaProduk = int.parse(_hargaProdukTextboxController.text);
1. import 'package:flutter/material.dart';
2. import 'package:tokokita/bloc/produk_bloc.dart';
3. import 'package:tokokita/model/produk.dart';
4. import 'package:tokokita/ui/produk_page.dart'; 5. import
'package:tokokita/widget/warning_dialog.dart';
6.
7. class ProdukForm extends StatefulWidget { 8.
Produk? produk;
9.
155
10. ProdukForm({Key? key, this.produk}) : super(key: key);
11.
12. @override
13. _ProdukFormState createState() => _ProdukFormState();
14. }
15.
16. class _ProdukFormState extends State<ProdukForm> {
17. final _formKey = GlobalKey<FormState>();
18. bool _isLoading = false;
19. String judul = "TAMBAH PRODUK";
20. String tombolSubmit = "SIMPAN";
21.
22. final _kodeProdukTextboxController = TextEditingController();
23. final _namaProdukTextboxController = TextEditingController(); 24. final
_hargaProdukTextboxController = TextEditingController();
25.
26. @override
27. void initState() {
28. super.initState();
29. isUpdate();
30. }
31.
32. isUpdate() {
33. if (widget.produk != null) {
34. setState(() {
35. judul = "UBAH PRODUK";
36. tombolSubmit = "UBAH";
37. _kodeProdukTextboxController.text = widget.produk!.kodeProduk!;
38. _namaProdukTextboxController.text = widget.produk!.namaProduk!;
39. _hargaProdukTextboxController.text =
40. widget.produk!.hargaProduk.toString();
41. });
42. } else {
43. judul = "TAMBAH PRODUK";
44. tombolSubmit = "SIMPAN";
45. }
46. }
47.
48. @override
49. Widget build(BuildContext context) {
50. return Scaffold(
51. appBar: AppBar(title: Text(judul)),
52. body: SingleChildScrollView(
53. child: Padding(
54. padding: const EdgeInsets.all(8.0),
55. child: Form(
56. key: _formKey,
57. child: Column(
58. children: [
59. _kodeProdukTextField(),
60. _namaProdukTextField(),
61. _hargaProdukTextField(),
62. _buttonSubmit()
63. ],
156
64. ),
65. ),
66. ),
67. ),
68. );
69. }
70.
71. //Membuat Textbox Kode Produk
72. Widget _kodeProdukTextField() {
73. return TextFormField(
74. decoration: const InputDecoration(labelText: "Kode Produk"),
75. keyboardType: TextInputType.text,
76. controller: _kodeProdukTextboxController,
77. validator: (value) {
78. if (value!.isEmpty) {
79. return "Kode Produk harus diisi";
80. }
81. return null;
82. },
83. );
84. }
85.
86. //Membuat Textbox Nama Produk
87. Widget _namaProdukTextField() {
88. return TextFormField(
89. decoration: const InputDecoration(labelText: "Nama Produk"),
90. keyboardType: TextInputType.text,
91. controller: _namaProdukTextboxController,
92. validator: (value) {
93. if (value!.isEmpty) {
94. return "Nama Produk harus diisi";
95. }
96. return null;
97. },
98. ); 99. }
100.
101. //Membuat Textbox Harga Produk
102. Widget _hargaProdukTextField() {
103. return TextFormField(
104. decoration: const InputDecoration(labelText: "Harga"),
105. keyboardType: TextInputType.number,
106. controller: _hargaProdukTextboxController,
107. validator: (value) {
108. if (value!.isEmpty) {
109. return "Harga harus diisi";
110. }
111. return null;
112. },
113. ); 114. } 115.
116. //Membuat Tombol Simpan/Ubah
117. Widget _buttonSubmit() {
118. return OutlinedButton(
119. child: Text(tombolSubmit),
120. onPressed: () {
121. var validate = _formKey.currentState!.validate();
122. if (validate) {
157
123. if (!_isLoading) {
124. if (widget.produk != null) {
125. //kondisi update produk
126.
127. } else {
128. //kondisi tambah produk
129. simpan();
130. }
131. }
132. }
133. }); 134. } 135.
136. simpan() {
137. setState(() {
138. _isLoading = true;
139. });
140. Produk createProduk = Produk(id: null);
141. createProduk.kodeProduk = _kodeProdukTextboxController.text;
142. createProduk.namaProduk = _namaProdukTextboxController.text;
143. createProduk.hargaProduk =
int.parse(_hargaProdukTextboxController.text);
144. ProdukBloc.addProduk(produk: createProduk).then((value) {
145. Navigator.of(context).push(MaterialPageRoute(
146. builder: (BuildContext context) => const ProdukPage()));
147. }, onError: (error) {
148. showDialog(
149. context: context,
150. builder: (BuildContext context) => const WarningDialog(
151. description: "Simpan gagal, silahkan coba lagi",
152. ));
153. });
154. setState(() {
155. _isLoading = false;
156. });
157. }
158. }
159. ubah() {
160. setState(() {
161. _isLoading = true;
162. });
163. Produk updateProduk = Produk(id: null);
164. updateProduk.id = widget.produk!.id;
165. updateProduk.kodeProduk = _kodeProdukTextboxController.text;
166. updateProduk.namaProduk = _namaProdukTextboxController.text;
167. updateProduk.hargaProduk =
int.parse(_hargaProdukTextboxController.text);
168. ProdukBloc.updateProduk(produk: updateProduk).then((value) {
169. Navigator.of(context).push(MaterialPageRoute(
170. builder: (BuildContext context) => const ProdukPage()));
158
171. }, onError: (error) {
172. showDialog(
173. context: context,
174. builder: (BuildContext context) => const WarningDialog(
175. description: "Permintaan ubah data gagal, silahkan coba lagi",
176. ));
177. });
178. setState(() {
179. _isLoading = false;
180. });
181. }
159
Dengan kode keseluruhan menjadi seperti berikut
160
161
Menambahkan fungsi hapus pada Detail Produk (produk_detail.dart)
162
128. //kondisi tambah produk
129. simpan();
130. }
131. }
132. }
133. });
134. }
135.
136. simpan() {
137. setState(() {
138. _isLoading = true;
139. });
140. Produk createProduk = Produk(id: null);
141. createProduk.kodeProduk = _kodeProdukTextboxController.text;
142. createProduk.namaProduk = _namaProdukTextboxController.text;
143. createProduk.hargaProduk = int.parse(_hargaProdukTextboxController.text);
144. ProdukBloc.addProduk(produk: createProduk).then((value) {
145. Navigator.of(context).push(MaterialPageRoute(
146. builder: (BuildContext context) => const ProdukPage()));
147. }, onError: (error) {
148. showDialog(
149. context: context,
150. builder: (BuildContext context) => const WarningDialog(
151. description: "Simpan gagal, silahkan coba lagi",
152. ));
153. });
154. setState(() {
155. _isLoading = false;
156. });
157. }
158.
159. ubah() {
160. setState(() {
161. _isLoading = true;
162. });
163. Produk updateProduk = Produk(id: null);
164. updateProduk.id = widget.produk!.id;
165. updateProduk.kodeProduk = _kodeProdukTextboxController.text;
166. updateProduk.namaProduk = _namaProdukTextboxController.text;
167. updateProduk.hargaProduk = int.parse(_hargaProdukTextboxController.text);
168. ProdukBloc.updateProduk(produk: updateProduk).then((value) {
169. Navigator.of(context).push(MaterialPageRoute(
170. builder: (BuildContext context) => const ProdukPage()));
171. }, onError: (error) {
172. showDialog(
173. context: context,
174. builder: (BuildContext context) => const WarningDialog(
175. description: "Permintaan ubah data gagal, silahkan coba lagi",
176. ));
177. });
178. setState(() {
179. _isLoading = false;
180. });
163
181. }
182. }
Buka file produk_detail.dart pada folder ui, kemudian kita modifikasi pada fungsi confirmHapus
menjadi seperti berikut
1. import 'package:flutter/material.dart';
2. import 'package:tokokita/model/produk.dart'; 3. import
'package:tokokita/ui/produk_form.dart';
4.
5. class ProdukDetail extends StatefulWidget { 6.
Produk? produk;
7.
8. ProdukDetail({Key? key, this.produk}) : super(key: key);
9.
10. @override
11. _ProdukDetailState createState() => _ProdukDetailState();
12. }
13.
14. class _ProdukDetailState extends State<ProdukDetail> {
15. @override
16. Widget build(BuildContext context) {
17. return Scaffold(
18. appBar: AppBar(
19. title: const Text('Detail Produk'),
20. ),
21. body: Center(
22. child: Column(
164
23. children: [
24. Text(
25. "Kode : ${widget.produk!.kodeProduk}",
26. style: const TextStyle(fontSize: 20.0),
27. ),
28. Text(
29. "Nama : ${widget.produk!.namaProduk}",
30. style: const TextStyle(fontSize: 18.0),
31. ),
32. Text(
33. "Harga : Rp. ${widget.produk!.hargaProduk.toString()}",
34. style: const TextStyle(fontSize: 18.0),
35. ),
36. _tombolHapusEdit()
37. ],
165
166
Daftar Pustaka
167