Modul Mobile3
Modul Mobile3
Dengan hadirnya modul ajar ini, semoga dapat memberikan pengetahuan kepada mahasiswa
dalam mengikuti perkuliahan pada mata kuliah Pemrograman Mobile-3.
Wassalamu’alaikum Warahmatullahi Wabarakatuh
i
DAFTAR ISI
KATA PENGANTAR......................................................................................................... i
DAFTAR ISI ...................................................................................................................... ii
RENCANA PEMBELAJARAN SEMESTER GENAP ................................................... iv
Pengantar Flutter & SQLite .............................................................................................. 1
1.1 Database SQLite ..................................................................................................... 1
1.2 Membuat Project Flutter ......................................................................................... 2
1.3 Menggunakan SQLite Pada Flutter ......................................................................... 3
Model Data JSON .............................................................................................................. 4
2.1 Membuat Model User ............................................................................................. 4
2.2 Membuat Model Note ............................................................................................. 7
Membuat Database dan Tabel........................................................................................... 9
3.1 Membuat Database, Tabel Users dan Tabel Notes ................................................... 9
UI Halaman Login ............................................................................................................15
4.1 Desain User Interface Halaman Login ....................................................................15
Proses Halaman Login ......................................................................................................21
5.1 Membuat TextEditingController ............................................................................21
5.2 Menampilkan dan Menyembunyikan Teks Password .............................................21
5.3 Menambahkan Validasi Form ................................................................................23
5.4 Membuat Fungsi Login ..........................................................................................25
UI Halaman Create Account ............................................................................................29
6.1 Desain User Interface Halaman Create Account .....................................................29
Proses Halaman Create Account ......................................................................................36
7.1 Membuat TextEditingController ............................................................................36
7.2 Menampilkan dan Menyembunyikan Teks Password .............................................37
7.3 Menampilkan dan Menyembunyikan Teks Confirm Password................................38
7.4 Menambahkan Validasi Form ................................................................................39
7.5 Membuat Fungsi Create Account ...........................................................................41
7.6 Membuat Navigator TextButton Login...................................................................44
Ujian Tengah Semester .....................................................................................................45
8.1 Soal UTS ...............................................................................................................45
Homepage .........................................................................................................................46
9.1 Desain User Interface Homepage ...........................................................................46
Fitur Create Data..............................................................................................................50
10.1 Desain User Interface Halaman Create Data ...........................................................50
10.2 Membuat Proses Create Data .................................................................................53
ii
Fitur Read Data ................................................................................................................59
11.1 Membuat Fungsi Menampilkan Data .....................................................................59
Fitur Update Data .............................................................................................................62
12.1 Desain User Interface Halaman Update Data ..........................................................62
12.1 Membuat Proses Update Data ................................................................................65
Fitur Delete Data ..............................................................................................................72
13.1 Desain User Interface Delete Data .........................................................................72
13.1 Membuat Proses Delete Data .................................................................................74
Fitur Search Data .............................................................................................................76
14.1 Membuat Proses Search Data .................................................................................76
Deployment .......................................................................................................................78
15.1 Deployment ...........................................................................................................78
15.1 Build APK (Android Package Kit) .........................................................................78
Ujian Akhir Semester .......................................................................................................81
16.1 Soal UAS ..............................................................................................................81
iii
RENCANA PEMBELAJARAN SEMESTER GENAP
PROGRAM STUDI : SISTEM INFORMASI
STMIK TRIGUNA DHARMA
Alokasi Waktu / Bobot SKS 16 x Pertemuan (90 Menit Tatap Muka) / 2 SKS
Mata Kuliah ini membahas tentang bagaimana cara membuat aplikasi mobile yang menggunakan media penyimpanan
Deskripsi Mata Kuliah internal sebagai media penyimpanan data menggunakan database SQLite. Materi meliputi pembuatan database, autentikasi
pengguna, menambah data baru, menampilkan data, mengubah data, menghapus data serta melakukan pencarian data.
iv
1. Kehadiran : 10%
2. Tugas / Evaluasi : 20%
v
Sesi Materi Pembelajaran Sub Materi Pembelajaran Indikator Capaian Kemampuan Bentuk Pembelajaran Media Referensi
vi
Whiteboard
1. Desain User Interface Halaman Ruang kelas,
Mahasiswa mampu membuat fitur
12 Fitur Update Data Update Data Lecturing and practice LCD, -
update data
2. Membuat Fungsi Update Data Whiteboard
1. Desain User Interface Delete Data Ruang kelas,
Mahasiswa mampu membuat fitur
13 Fitur Delete Data Lecturing and practice LCD, -
2. Membuat Fungsi Delete Data delete data
Whiteboard
Ruang kelas,
1. Membuat Fungsi Search Data Mahasiswa mampu membuat fitur
14 Fitur Search Data Lecturing and practice LCD, -
search data
Whiteboard
1. Build APK (Android Package Mahasiswa memahami tentang Ruang kelas,
15 Deployment deployment dan melakukan build Lecturing and practice LCD, -
Kit)
APK Whiteboard
16 Ujian Akhir Semester
vii
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 1 (Satu)
Telp/Fax. 061 822 4051
[Link]
1. Database SQLite
Materi Pembelajaran : 2. Membuat Project Flutter
3. Menggunakan SQLite Pada Flutter
SQLite adalah sebuah mesin database relasional (RDBMS) yang ringan, cepat, dan
berbasis file. Tidak seperti sistem database besar seperti MySQL atau PostgreSQL, SQLite tidak
membutuhkan server yang berjalan secara terpisah. Ini membuatnya sangat praktis untuk
aplikasi berskala kecil hingga menengah. SQLite merupakan salah satu mesin database yang
paling banyak digunakan di seluruh dunia, dikenal karena efisiensi dan fleksibilitasnya. SQLite
tidak hanya digunakan oleh para pengembang, ia telah terintegrasi ke dalam banyak ponsel,
komputer, dan aplikasi sehari-hari yang kita gunakan, menjadikannya bagian penting dari
kehidupan digital kita.
1
lokal di perangkat pengguna. Pengguna dapat terus menggunakan aplikasi, melihat
data, dan bahkan membuat perubahan (yang akan disinkronkan nanti) meskipun tidak
ada koneksi internet.
Instalasi Mudah: Pengembang hanya perlu menambahkan dependensi sqflite ke
[Link], dan database siap digunakan.
[Link]
import 'package:flutter/[Link]';
void main() {
runApp(const MainApp());
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Notes App',
theme: ThemeData(
colorScheme: [Link](
seedColor: [Link],
),
),
home: const Scaffold(
body: Center(
child: Text('Notes App'),
),
2
),
);
}
}
1. Tambahkan package sqflite dan beberapa package lainnya yang dibutuhkan dalam
pengembangan aplikasi.
a. Buka jendela Terminal dan Jalankan command berikut :
flutter pub add sqflite
flutter pub add path
flutter pub add intl
flutter pub add path_provider
Package Keterangan
SQLite plugin untuk Flutter, digunakan untuk menyimpan data lokal
sqflite
di database SQLite.
Manipulasi path file sistem, kegunaan untuk menggabungkan dan
path
memanipulasi path file atau direktori secara cross-platform.
Formatting data internasional, untuk format tanggal, waktu, angka,
intl
dan localization.
Akses direktori khusus perangkat, untuk mendapatkan path direktori
path_provider
seperti dokumen, temporary, atau aplikasi
[Link]
dependencies:
flutter:
sdk: flutter
intl: ^0.19.0
path: ^1.8.3
path_provider: ^2.1.3
sqflite: ^2.3.2
c. Selain menambahkan melalui command pada jendela terminal, bisa juga dengan cara
menambahkan langsung package tersebut pada file [Link] lalu simpan (ctrl + s).
3
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 2 (Dua)
Telp/Fax. 061 822 4051
[Link]
Dalam pengembangan aplikasi Flutter, model data JSON adalah representasi terstruktur
dari data yang diterima atau dikirim ke API, database, atau penyimpanan lokal. JSON
(JavaScript Object Notation) adalah format pertukaran data yang ringan dan mudah dibaca,
sementara model data di Dart/Flutter membantu mengkonversi JSON menjadi objek yang lebih
mudah dikelola, dan bisa dikatakan bahwa model data adalah cara terstruktur untuk mengelola
data di Flutter.
4
3. Buat model user yang merepresentasikan entitas "pengguna" (User), dengan membuat kode
seperti berikut pada file user_model.dart:
user_model.dart
class UserModel {
final int? userId;
final String userName;
final String userPassword;
UserModel({
[Link],
required [Link],
required [Link],
});
Ini adalah deklarasi sebuah kelas bernama UserModel. Dalam pemrograman berorientasi
objek, kelas adalah blueprint atau cetakan untuk membuat objek.
Bagian ini merupakan Properti (Attributes) dari UserModel. Penggunaan kata kunci final
berarti bahwa nilai userId, userName, userPassword hanya dapat ditetapkan sekali saat
objek UserModel dibuat (melalui konstruktor) dan tidak dapat diubah setelahnya. Dan
Tanda ? menunjukkan bahwa userId bisa bernilai null. Ini berguna ketika membuat objek
5
UserModel baru sebelum disisipkan ke database, di mana userId mungkin belum
ditetapkan (karena biasanya dihasilkan oleh database).
UserModel({
[Link],
required [Link],
required [Link],
});
Ini adalah konstruktor untuk kelas UserModel. Konstruktor adalah metode khusus yang
dipanggil saat membuat instance (objek) baru dari kelas ini. Kata kunci required berarti
kita harus menyediakan nilai untuk userName, userPassword saat membuat objek
UserModel. Tanpa nilai ini, kode akan menghasilkan error saat kompilasi.
Ini adalah factory constructor bernama fromMap. Factory constructor digunakan ketika kita
ingin memiliki lebih banyak kontrol atas bagaimana objek dibuat. Dalam kasus ini, fromMap
digunakan untuk membuat objek UserModel dari sebuah Map<String, dynamic>.
Kata kunci factory menunjukkan bahwa ini adalah factory constructor. Berbeda dengan
konstruktor reguler, factory constructor tidak selalu membuat instance baru dari kelas; ia
bisa mengembalikan instance yang sudah ada atau melakukan logika lain sebelum
membuat instance baru.
Map<String, dynamic> json: Parameter ini adalah sebuah Map yang diasumsikan berisi
data pengguna, biasanya dalam format JSON yang telah didekodekan. Kunci dari Map
adalah String (misalnya, "userId", "userName") dan nilainya bisa berupa tipe data apa
pun (dynamic).
=>: Ini adalah sintaks arrow function atau fat arrow di Dart, yang merupakan singkatan
untuk fungsi yang hanya memiliki satu ekspresi pengembalian.
UserModel(...): Di sini, data dari json (Map) diekstrak dan digunakan untuk memanggil
konstruktor utama UserModel untuk membuat objek baru. Misalnya, json["userId"]
akan mengambil nilai yang terkait dengan kunci "userId " dari map.
Fungsi utama fromMap: Konversi data dari format Map (seringkali dari JSON yang diterima
dari API atau database) menjadi objek UserModel yang terstruktur.
6
Map<String, dynamic> toMap() => {
"userId": userId,
"userName": userName,
"userPassword": userPassword,
};
Ini adalah sebuah metode instance bernama toMap. Metode ini berfungsi kebalikan dari
fromMap. userId, userName, userPassword: Nilai-nilai dari properti objek UserModel saat
ini diambil dan dijadikan nilai dalam Map.
Fungsi utama toMap: Konversi objek UserModel menjadi format Map. Ini sangat umum
untuk serialisasi data, yaitu mempersiapkan data untuk dikirim ke API, disimpan ke
database atau disimpan ke local storage.
4. Buat model note dengan menambahkan baris kode berikut pada file note_model.dart:
note_model.dart
class NoteModel {
final int? noteId;
final String noteTitle;
final String noteContent;
final String createdAt;
NoteModel({
[Link],
required [Link],
required [Link],
required [Link],
});
7
createdAt: json["createdAt"],
);
8
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 3 (Tiga)
Telp/Fax. 061 822 4051
[Link]
1. Membuat Database
Materi Pembelajaran :
2. Membuat Tabel
3. Buat database, tabel users dan tabel notes dengan menambahkan baris kode berikut pada file
database_helper.dart :
database_helper.dart
import 'package:path/[Link]';
import 'package:sqflite/[Link]';
class DatabaseHelper {
// Singleton instance
static final DatabaseHelper _instance = DatabaseHelper._internal();
factory DatabaseHelper() => _instance;
DatabaseHelper._internal();
// Configuration variables
static Database? _database;
final String databaseName = "[Link]";
final int databaseVersion = 1;
9
// create note table
final String createNoteTable = '''
CREATE TABLE notes (
noteId INTEGER PRIMARY KEY AUTOINCREMENT,
noteTitle TEXT NOT NULL,
noteContent TEXT NOT NULL,
createdAt TEXT DEFAULT CURRENT_TIMESTAMP
)
''';
return openDatabase(
path,
version: databaseVersion,
onCreate: (db, version) async {
await [Link](createUserTable);
await [Link](createNoteTable);
},
);
}
1. // Singleton instance
Bagian ini merupakan implementasi dari pola desain Singleton dalam Dart/Flutter. Pola
ini memastikan bahwa kelas DatabaseHelper hanya memiliki satu instance tunggal yang
bisa dibuat dan diakses sepanjang siklus hidup aplikasi. Secara sederhana, ini berarti
hanya ada satu "pengurus database" yang aktif. Setiap kali "pengurus database" itu
diminta, akan selalu didapatkan instance yang sama, bukan yang baru.
10
Keuntungan Utama Penggunaan Singleton pada DatabaseHelper:
1) Efisiensi dan Penghematan Sumber Daya: Mencegah pembuatan koneksi database
ganda, tidak perlu membuka dan menutup koneksi database berkali-kali, yang bisa
memakan sumber daya. Satu koneksi, digunakan bersama.
2) Konsistensi Data: Menjamin semua bagian aplikasi berinteraksi dengan instance
database yang sama. Hal ini menjaga konsistensi data dan menghindari potensi error
atau konflik yang bisa timbul jika ada banyak koneksi database yang berbeda.
3) Manajemen Terpusat: Menyediakan satu titik kontrol untuk semua operasi database,
membuat pengelolaan dan pemeliharaan kode lebih mudah.
Bagian ini membuat sebuah konstruktor publik yang akan dipanggil di bagian lain kode
kita nanti dengan nama DatabaseHelper(). Setiap kali kita memanggil
DatabaseHelper() maka konstruktor factory ini akan selalu mengembalikan satu-
satunya objek _instance yang sudah ada.
DatabaseHelper._internal();
Konstruktor ini hanya dipanggil satu kali oleh baris pertama (static final...) untuk
membuat instance awal _instance. Karena ini pribadi, tidak ada bagian lain dari kode
kita yang bisa membuat DatabaseHelper baru.
2. // Configuration variables
Mendeklarasikan beberapa variabel yang akan digunakan untuk mengatur dan mengakses
database SQLite yang akan dibuat.
11
Variabel _database akan menjadi objek koneksi ke database yang sebenarnya.
Variabel databaseName merupakan nama file database yang akan dibuat di perangkat.
12
Future<Database> initDB() async {...}
Ini adalah sebuah fungsi asinkron (async) bernama initDB. Fungsi ini akan
mengembalikan sebuah Future<Database>, yang berarti ia akan menghasilkan objek
Database di masa depan (setelah proses inisialisasi selesai). Menggunakan Future dan
async/await sangat penting karena operasi database (seperti membuka file) bisa
memakan waktu dan kita tidak ingin aplikasi macet saat menunggu.
return openDatabase()
openDatabase() adalah fungsi dari sqflite yang bertanggung jawab untuk membuka
koneksi ke database. Jika database belum ada, openDatabase() akan secara otomatis
membuatnya di lokasi yang ditentukan dan jika database sudah ada, ia hanya akan
membuka koneksi ke database tersebut.
path
version: databaseVersion
version adalah nomor versi database. Ini sangat penting untuk migrasi database.
onCreate adalah sebuah callback (fungsi yang dipanggil kembali) yang akan dieksekusi
hanya sekali, yaitu saat database pertama kali dibuat di perangkat pengguna. Di dalam
onCreate, kita menerima objek db (yang merupakan instance dari Database) dan version.
13
await [Link](createUserTable)
await [Link](createNoteTable);
Bagian ini menjalankan perintah SQL yang ada pada variabel createUserTable dan
createNoteTable untuk membuat tabel users dan tabel notes di database.
get database Ini adalah sintaks untuk getter. Artinya, kita bisa mengaksesnya seperti
sebuah properti (misalnya, await DatabaseHelper().database;).
if (_database != null): Ini adalah pemeriksaan awal yang sangat penting. Baris ini
memeriksa apakah objek _database sudah ada dan tidak null (yaitu, database sudah
dibuka dan siap digunakan). Jika _database sudah ada, maka fungsi ini akan langsung
mengembalikan objek database yang sudah ada tersebut. Tanda seru (!) setelah
_database adalah operator "null assertion". Ini memberi tahu Dart bahwa "Saya yakin
_database tidak null di sini, jadi silakan perlakukan sebagai Database non-null." kita
bisa yakin karena kita baru saja memeriksa bahwa itu != null.
Baris ini hanya akan dieksekusi jika _database masih null. Dan await initDB()
adalah bagian yang akan menginisialisasi (membuka atau membuat) database dan
menjalankan perintah laiinya yang ada pada fungsi initDB().
return _database!;
Setelah _database berhasil diinisialisasi (atau jika sudah ada dari awal), baris ini akan
mengembalikan objek _database yang sekarang berisi koneksi database yang aktif.
14
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 4 (Empat)
Telp/Fax. 061 822 4051
[Link]
UI Halaman Login
3. Buat 1 buah class pada file login_screen.dart dengan nama LoginScreen menggunakan
StatefulWidget, lalu tambahkan widget Scaffold sebagai struktur dasar halaman.
Tambahkan juga sebuah properti body pada widget Scaffold untuk menentukan konten
yang akan ditampilkan pada halaman login.
login_screen.dart
import 'package:flutter/[Link]';
@override
State<LoginScreen> createState() => _LoginScreenState();
}
15
4. Modifikasi file [Link]. Ubah properti home pada MaterialApp sehingga halaman
pertama yang akan ditampilkan pada saat aplikasi dijalankan adalah LoginScreen.
[Link]
...
home: const LoginScreen(),
...
5. Hasil dari perubahan kode yang telah dilakukan ketika aplikasi dijalankan :
6. Menambahkan sebuah gambar yang akan digunakan pada halamann login. Tambahkan 1
buah folder di dalam folder lib dengan nama images lalu copy sebuah gambar didalamnya.
Contoh sebuah gambar yang akan digunakan dengan nama [Link].
[Link]
7. Modifikasi file [Link]. Tambahkan perintah untuk mendaftarkan file aset (gambar)
yang akan digunakan pada aplikasi seperti berikut.
[Link]
flutter:
uses-material-design: true
assets:
16
- lib/images/
8. Modifikasi file login_screen.dart. Ubah bagian properti body menjadi seperti berikut
untuk membuat sebuah form dan menampilkan gambar yang digunakan.
login_screen.dart
...
body: Center(
child: SingleChildScrollView(
child: Padding(
padding: const [Link](10.0),
child: Form(
child: Column(
children: [
[Link](
'lib/images/[Link]',
width: 300,
),
],
),
),
),
),
),
...
9. Menambahkan text brand aplikasi dibawah gambar. Tambahkan beberapa baris kode seperti
berikut dibawah widget Image.
login_screen.dart
...
const SizedBox(height: 15),
const Text(
"Notes App",
style: TextStyle(
fontSize: 22,
color: [Link],
fontWeight: [Link],
),
),
...
17
10. Membuat textfield untuk inputan username. Tambahkan beberapa baris kode berikut
dibawah widget Text "Notes App".
login_screen.dart
...
const SizedBox(height: 8),
Container(
margin: const [Link](8),
padding: const [Link](
horizontal: 10,
vertical: 4,
),
decoration: BoxDecoration(
borderRadius: [Link](6),
color: [Link](.1),
),
child: TextFormField(
textAlignVertical: [Link],
decoration: const InputDecoration(
icon: Icon([Link]),
border: [Link],
hintText: "Username",
),
),
),
...
11. Membuat textfield untuk inputan password. Tambahkan beberapa baris kode berikut
dibawah TextFormField "Username".
login_screen.dart
...
Container(
margin: const [Link](8),
padding: const [Link](
horizontal: 10,
vertical: 4,
),
decoration: BoxDecoration(
borderRadius: [Link](6),
color: [Link](.1),
),
child: TextFormField(
18
textAlignVertical: [Link],
decoration: InputDecoration(
icon: const Icon([Link]),
border: [Link],
hintText: "Password",
suffixIcon: IconButton(
onPressed: () {
setState(() {});
},
icon: const Icon([Link]),
),
),
),
),
...
12. Membuat button login. Tambahkan beberapa baris kode berikut dibawah TextFormField
"Password".
login_screen.dart
...
Container(
margin: const [Link](left: 8, top: 8, right: 8),
height: 55,
width: [Link],
child: ElevatedButton(
onPressed: () {},
style: [Link](
shape: RoundedRectangleBorder(
borderRadius: [Link](6),
)),
child: const Row(
mainAxisSize: [Link],
children: [
Icon([Link]),
SizedBox(width: 8),
Text(
"Login",
style: TextStyle(
color: [Link],
fontSize: 18,
fontWeight: [Link],
19
),
),
],
),
),
),
...
13. Membuat button Create account yang berfungsi untuk membuka halaman buat akun
pengguna. Tambahkan beberapa baris kode berikut dibawah button login.
login_screen.dart
...
Row(
mainAxisAlignment: [Link],
children: [
const Text("Don't have an account?"),
TextButton(
onPressed: () {},
child: const Text("Create account"),
),
],
),
...
20
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 5 (Lima)
Telp/Fax. 061 822 4051
[Link]
login_screen.dart
...
class _LoginScreenState extends State<LoginScreen> {
final usernameController = TextEditingController();
final passwordController = TextEditingController();
...
login_screen.dart
...
child: TextFormField(
controller: usernameController,
...
login_screen.dart
...
child: TextFormField(
controller: passwordController,
...
1. Tambahkan 1 buah variabel isVisible dengan tipe data boolean. Nilai variabel secara
default bernilai false yang berarti teks pada password akan disembunyikan.
21
login_screen.dart
...
final passwordController = TextEditingController();
login_screen.dart
...
child: TextFormField(
controller: passwordController,
obscureText: !isVisible,
...
login_screen.dart
...
hintText: "Password",
suffixIcon: IconButton(
onPressed: () {
setState(() {
isVisible = !isVisible;
});
},
icon: Icon(isVisible
? [Link]
: Icons.visibility_off),
),
...
22
5.3 Menambahkan Validasi Form
login_screen.dart
...
bool isVisible = false;
login_screen.dart
...
child: Form(
key: formKey,
...
login_screen.dart
...
validator: (value) {
if (value!.isEmpty) {
return "username is required";
}
return null;
23
},
...
login_screen.dart
...
validator: (value) {
if (value!.isEmpty) {
return "password is required";
}
return null;
},
...
login_screen.dart
...
onPressed: () {
if ([Link]!.validate()) {}
},
...
6. Hasil yang ditampilkan setelah validasi dibuat. Ketika button login di tap sedangkan
username dan password tidak diisi maka akan muncul pesan validasi seperti gambar berikut.
24
5.4 Membuat Fungsi Login
1. Buat fungsi login di dalam file database_helper.dart. Jika pada tabel users ditemukan
baris (pengguna) yang memiliki userName dan userPassword yang sama dengan yang
dimasukkan oleh pengguna (artinya result tidak kosong), berarti login berhasil, dan fungsi
akan mengembalikan true. Jika tidak ditemukan (artinya result kosong), berarti login
gagal, dan fungsi mengembalikan false.
database_helper.dart
import '../models/user_model.dart';
...
...
// Login method
Future<bool> login(UserModel user) async {
final db = await database;
return [Link];
}
...
2. Buat proses login (sementara) pada file login_screen.dart. Tambahkan beberapa baris
kode berikut di dalam class _LoginScreenState, pastikan lakukan import file
database_helper.dart dan user_model.dart. Proses yang dibuat adalah; mengambil
inputan userName dan userPassword dari pengguna, lalu dikirimkan ke database untuk
diverifikasi, menuggu hasil (response) berhasil atau tidak, jika berhasil akan ditampilkan
snackbar dengan pesan 'Login success', dan jika tidak berhasil akan ditampilkan pesan
'Login failed! Please try again.'.
login_screen.dart
import '../database/database_helper.dart';
import '../models/user_model.dart';
...
...
final formKey = GlobalKey<FormState>();
25
final db = DatabaseHelper();
// Fungsi Login
Future<void> login() async {
try {
var response = await [Link](
UserModel(
userName: [Link],
userPassword: [Link],
),
);
if (!mounted) return;
if (response == true) {
[Link](context).showSnackBar(
SnackBar(
content: const Text('Login success'),
backgroundColor: [Link][400],
behavior: [Link],
),
);
} else {
[Link](context).showSnackBar(
const SnackBar(
content: Text('Login failed! Please try again.'),
backgroundColor: [Link],
behavior: [Link],
),
);
}
} catch (e) {
if (!mounted) return;
[Link](context).showSnackBar(
SnackBar(
content: Text(' Login failed! Please try again.'),
26
backgroundColor: [Link],
behavior: [Link],
),
);
}
}
...
if (!mounted) return;
mounted: Adalah properti yang bernilai true jika widget Anda masih "terpasang" di
pohon widget (masih terlihat di layar).
if (!mounted) return: Melakukan pengecekan keamanan yang penting di Flutter,
terutama dalam widget StatefulWidget yang asinkron. "Jika widget ini sudah tidak ada di
layar (misalnya, pengguna sudah pindah halaman), maka berhenti jalankan kode ini." Ini
mencegah kesalahan (error) jika aplikasi mencoba memperbarui UI pada widget yang
sudah tidak ada.
login_screen.dart
...
onPressed: () {
if ([Link]!.validate()) {
login();
}
},
...
4. Hasil login sementara. Jika login gagal, misal user tidak ditemukan atau password salah,
maka akan muncul sebuah SnackBar dengan pesan “Login failed!. Please try
again”.
27
Nb :
1. Untuk menguji login jika berhasil belum bisa dikarenakan belum ada akun yang
terdaftar di dalam tabel users.
2. Proses login jika berhasil belum selesai, akan dilakukan modifikasi kode pada bab
berikutnya karena belum ada class yang dibuat untuk menampilkan halaman notes
ketika login berhasil.
28
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 6 (Enam)
Telp/Fax. 061 822 4051
[Link]
create_account_screen.dart
import 'package:flutter/[Link]';
@override
State<CreateAccount> createState() => _CreateAccountState();
}
29
3. Modifikasi kode button Create account pada file login_screen.dart. tambahkan perintah
untuk membuka halaman Create Account ketika TextButton di tap.
login_screen.dart
...
import 'create_account_screen.dart';
...
onPressed: () {
[Link](
context,
MaterialPageRoute(
builder: (context) => const CreateAccount(),
),
);
},
child: const Text("Create account"),
...
4. Hasil yang ditampilkan ketika button Create account di tap akan membuka halaman Create
Account seperti yang terlihat pada gambar berikut.
create_account_screen.dart
...
return Scaffold(
body: Center(
30
child: SingleChildScrollView(
child: Form(
child: Padding(
padding: const [Link](8.0),
child: Column(
mainAxisAlignment: [Link],
children: [
const ListTile(
title: Center(
child: Text(
"Create a New Account",
style: TextStyle(
fontSize: 22,
fontWeight: [Link],
color: [Link],
),
),
),
),
],
),
),
),
),
),
);
...
6. Membuat TextFormField untuk inputan username. Tambahkan beberapa baris kode berikut
dibawah widget ListTile.
create_account_screen.dart
...
// TextFormField Username
Container(
margin: const [Link](8),
padding: const [Link](
horizontal: 10,
vertical: 4,
),
decoration: BoxDecoration(
borderRadius: [Link](6),
31
color: [Link](.1),
),
child: TextFormField(
textAlignVertical: [Link],
decoration: const InputDecoration(
icon: Icon([Link]),
border: [Link],
hintText: "Username",
),
),
),
...
7. Membuat TextFormField untuk inputan password. Tambahkan beberapa baris kode berikut
dibawah TextFormField Username.
create_account_screen.dart
...
// TextFormField Password
Container(
margin: const [Link](8),
padding: const [Link](
horizontal: 10,
vertical: 4,
),
decoration: BoxDecoration(
borderRadius: [Link](6),
color: [Link](.1),
),
child: TextFormField(
textAlignVertical: [Link],
decoration: InputDecoration(
icon: const Icon([Link]),
border: [Link],
hintText: "Password",
suffixIcon: IconButton(
onPressed: () {},
icon: const Icon([Link]),
),
),
),
),
32
...
8. Membuat TextFormField untuk inputan confirm password. Tambahkan beberapa baris kode
berikut dibawah TextFormField Password.
create_account_screen.dart
...
// TextFormField Confirm Password
Container(
margin: const [Link](8),
padding: const [Link](
horizontal: 10,
vertical: 4,
),
decoration: BoxDecoration(
borderRadius: [Link](6),
color: [Link](.1),
),
child: TextFormField(
textAlignVertical: [Link],
decoration: InputDecoration(
icon: const Icon([Link]),
border: [Link],
hintText: "Confirm Password",
suffixIcon: IconButton(
onPressed: () {},
icon: const Icon([Link]),
),
),
),
),
...
9. Membuat button create account. Tambahkan beberapa baris kode berikut dibawah
TextFormField Confirm Password.
create_account_screen.dart
...
// Button Create Account
Container(
margin: const [Link](left: 8, top: 8, right: 8),
height: 55,
width: [Link],
33
child: ElevatedButton(
onPressed: () {},
style: [Link](
shape: RoundedRectangleBorder(
borderRadius: [Link](6),
)),
child: const Row(
mainAxisSize: [Link],
children: [
Icon(Icons.person_add_alt_1),
SizedBox(width: 8),
Text(
"Create Account",
style: TextStyle(
color: [Link],
fontSize: 18,
fontWeight: [Link],
),
),
],
),
),
),
...
10. Membuat TextButton login untuk membuka halaman login. Tambahkan beberapa baris
kode berikut dibawah Button Create Account.
create_account_screen.dart
...
// TextButton Login
Row(
mainAxisAlignment: [Link],
children: [
const Text("Already have an account?"),
TextButton(
onPressed: () {},
child: const Text("Login"),
),
],
),
...
34
15. Hasil dari desain user interface halaman create account dapat dilihat pada gambar berikut.
35
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 7 (Tujuh)
Telp/Fax. 061 822 4051
[Link]
create_account_screen.dart
...
class _CreateAccountState extends State<CreateAccount> {
final usernameController = TextEditingController();
final passwordController = TextEditingController();
final confirmPasswordController = TextEditingController();
...
create_account_screen.dart
...
child: TextFormField(
controller: usernameController,
...
create_account_screen.dart
...
child: TextFormField(
controller: passwordController,
...
36
create_account_screen.dart
...
child: TextFormField(
controller: confirmPasswordController,
...
1. Tambahkan 1 buah variabel isVisiblePassword dengan tipe data boolean. Nilai variabel
secara default bernilai false yang berarti teks pada password akan disembunyikan.
create_account_screen.dart
...
final passwordController = TextEditingController();
create_account_screen.dart
...
child: TextFormField(
controller: passwordController,
obscureText: !isVisiblePassword,
...
create_account_screen.dart
...
hintText: "Password",
suffixIcon: IconButton(
onPressed: () {
setState(() {
isVisiblePassword = !isVisiblePassword;
});
},
icon: Icon(isVisiblePassword
? [Link]
: Icons.visibility_off),
),
37
...
create_account_screen.dart
...
bool isVisiblePassword = false;
bool isVisibleConfirmPassword = false;
...
create_account_screen.dart
...
child: TextFormField(
controller: confirmPasswordController,
obscureText: !isVisibleConfirmPassword,
...
create_account_screen.dart
...
hintText: "Password",
suffixIcon: IconButton(
onPressed: () {
setState(() {
isVisibleConfirmPassword = !isVisibleConfirmPassword;
});
},
icon: Icon(isVisibleConfirmPassword
? [Link]
: Icons.visibility_off),
),
...
38
4. Hasil untuk menampilkan atau menyembunyikan teks password dan teks confirm password.
create_account_screen.dart
...
bool isVisibleConfirmPassword = false;
create_account_screen.dart
...
child: Form(
key: formKey,
...
create_account_screen.dart
...
validator: (value) {
if (value!.isEmpty) {
return "username is required";
}
39
return null;
},
...
create_account_screen.dart
...
validator: (value) {
if (value!.isEmpty) {
return "password is required";
}
return null;
},
...
create_account_screen.dart
...
validator: (value) {
if (value!.isEmpty) {
return "confirm password is required";
} else if ([Link] != [Link]) {
return "Password don't match";
}
return null;
},
...
create_account_screen.dart
...
onPressed: () {
if ([Link]!.validate()) {}
},
...
40
7. Hasil yang ditampilkan setelah validasi dibuat. Ketika button create account di tap
sedangkan username, password dan confirm password tidak diisi maka akan muncul pesan
validasi seperti gambar berikut.
8. Hasil yang ditampilkan jika password yang diisi tidak sama dengan confirm password, maka
akan muncul pesan validasi seperti gambar berikut.
1. Buat fungsi create account di dalam file database_helper.dart. Fungsi ini akan
memasukkan data pengguna baru ke dalam tabel users.
database_helper.dart
...
// Fungsi Create Account
41
Future<int> createAccount(UserModel user) async {
final Database db = await database;
create_account_screen.dart
import '../database/database_helper.dart';
import '../models/user_model.dart';
import 'login_screen.dart';
...
...
final formKey = GlobalKey<FormState>();
final db = DatabaseHelper();
if (!mounted) return;
if (result > 0) {
[Link](context).showSnackBar(
SnackBar(
content: Text('Account created successfully!'),
42
backgroundColor: [Link][400],
behavior: [Link],
),
);
[Link](context).showSnackBar(
SnackBar(
content: Text('An error occurred while creating the account'),
backgroundColor: [Link],
behavior: [Link],
),
);
}
}
...
create_account_screen.dart
...
onPressed: () {
if ([Link]!.validate()) {
createAccount();
}
},
...
43
4. Setelah membuat fungsi create account selanjutnya adalah menguji proses create account
dengan mengisi username, password, dan confirm password, jika berhasil maka akan muncul
sebuah SnackBar dengan pesan “Account created successfully!” dan akan diarahkan
ke halaman login, dan jika gagal maka akan muncul sebuah SnackBar dengan pesan
“Failed to create account. Please try again.” seperti yang terlihat pada gambar
berikut.
1. Tambahkan perintah pada TextButton login. Jika TextButton login di tap maka aplikasi
akan membuka halaman login.
create_account_screen.dart
...
TextButton(
onPressed: () {
[Link](
context,
MaterialPageRoute(
builder: (context) => const LoginScreen(),
),
);
},
child: const Text("Login"),
),
...
44
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 8 (Delapan)
Telp/Fax. 061 822 4051
[Link]
Soal UTS
45
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 9 (Sembilan)
Telp/Fax. 061 822 4051
[Link]
Homepage
3. Buat 1 buah class pada file notes_screen.dart dengan nama NotesScreen menggunakan
StatefulWidget, lalu tambahkan widget Scaffold sebagai struktur dasar halaman.
Tambahkan juga sebuah properti body pada widget Scaffold untuk menentukan konten
yang akan ditampilkan pada homepage (halaman notes).
notes_screen.dart
import 'package:flutter/[Link]';
@override
State<NotesScreen> createState() => _NotesScreenState();
}
46
4. Selanjutnya modifikasi fungsi login yang berada pada file login_screen.dart.
tambahkan perintah navigasi untuk membuka halaman Notes jika login berhasil.
login_screen.dart
...
import '../notes/notes_screen.dart';
...
// Navigasi ke halaman Notes jika login berhasil
[Link](
context,
MaterialPageRoute(
builder: (context) => const NotesScreen(),
),
);
...
5. Setelah melakukan modifikasi fungsi login, lakukan pengujian fungsi login dengan
cara mengisi username dan password dengan akun yang sudah terdaftar sebelumnya,
lalu tap button Login. Jika login berhasil maka aplikasi akan membuka halaman
Notes, seperti yang terlihat pada gambar berikut.
6. Jika sudah berhasil login selanjutnya desain user interface halaman Notes.
Tambahkan sebuah AppBar yang berisi title aplikasi dan terdapat sebuah icon untuk
logout seperti berikut.
47
notes_screen.dart
...
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: const Text("Notes App"),
actions: [
IconButton(
onPressed: () {},
icon: const Icon([Link]),
),
],
),
body: Center(
child: Text("Halaman Notes"),
),
);
...
48
Container(
padding: const [Link](horizontal: 10),
margin: const [Link](horizontal: 10),
decoration: BoxDecoration(
color: [Link](.1),
borderRadius: [Link](6),
),
child: TextFormField(
decoration: const InputDecoration(
border: [Link],
hintText: "Search notes",
icon: Icon([Link])),
),
),
],
),
),
...
9. Menambahkan perintah pada button logout sehingga ketika button logout di tap
maka akan menutup halaman Notes dan membuka halaman login.
notes_screen.dart
import 'package:flutter/[Link]';
import '../auth/login_screen.dart';
...
...
IconButton(
onPressed: () {
[Link](
context,
MaterialPageRoute(
builder: (context) => const LoginScreen(),
),
// Hapus semua route sebelumnya
(route) => false,
);
},
icon: const Icon([Link]),
),
...
49
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 10 (Sepuluh)
Telp/Fax. 061 822 4051
[Link]
create_note_screen.dart
import 'package:flutter/[Link]';
@override
State<CreateNoteScreen> createState() => _CreateNoteScreenState();
}
50
),
body: const Center(
child: Text("Halaman Create Note"),
),
);
}
}
...
3. Selanjutnya modifikasi fungsi onPressed pada button add yang berada pada file
notes_screen.dart. Tambahkan perintah navigasi untuk membuka halaman create
...
floatingActionButton: FloatingActionButton(
onPressed: () {
[Link](
context,
MaterialPageRoute(
builder: (context) => const CreateNoteScreen(),
),
);
},
child: const Icon([Link]),
),
...
4. Setelah melakukan modifikasi pada button add dengan menambahkan perintah navigasi
untuk membuka halaman create data, lakukan pengujian dengan cara tap button add, jika
berhasil maka halaman create data akan dibuka.
51
5. Tambahkan sebuah IconButton check pada bagian AppBar yang
berfungsi untuk melakukan proses penyimpanan data ketika
IconButton di tap.
create_note_screen.dart
...
appBar: AppBar(
title: const Text("Create Note"),
actions: [
IconButton(
onPressed: () {},
icon: const Icon([Link]),
),
],
),
...
6. Modifikasi bagian body dengan menambahkan sebuah Form dan sebuah TextFormField
title untuk menginput judul Note.
create_note_screen.dart
...
body: Form(
child: Padding(
padding: const [Link](10.0),
child: Column(
crossAxisAlignment: [Link],
52
children: [
// TextFormField untuk input judul
TextFormField(
decoration: const InputDecoration(
labelText: "Title",
border: OutlineInputBorder(),
),
),
],
),
),
),
...
create_note_screen.dart
...
const SizedBox(height: 10),
// TextField untuk input isi catatan/note
TextFormField(
maxLines: 5,
decoration: const InputDecoration(
labelText: "Content",
border: OutlineInputBorder(),
alignLabelWithHint: true,
),
),
...
Setelah tahap desain user interface halaman create data selesai, selanjutnya adalah
membuat agar aplikasi bisa melakukan proses penyimpanan data ke dalam database, lakukan
langkah-langkah berikut :
53
create_note_screen.dart
...
class _CreateNoteScreenState extends State<CreateNoteScreen> {
final titleController = TextEditingController();
final contentController = TextEditingController();
@override
Widget build(BuildContext context) {
...
create_note_screen.dart
...
child: TextFormField(
controller: titleController,
...
create_note_screen.dart
...
child: TextFormField(
controller: contentController,
...
create_note_screen.dart
...
final contentController = TextEditingController();
5. Tambahkan properti key pada widget Form dengan value nama variabel
GlobalKey<FormState> yang telah dibuat sebelumnya.
create_note_screen.dart
...
body: Form(
54
key: formKey,
...
create_note_screen.dart
...
validator: (value) {
if (value!.isEmpty) {
return "Title is required";
}
return null;
},
...
create_note_screen.dart
...
validator: (value) {
if (value!.isEmpty) {
return "Content is required";
}
return null;
},
...
create_note_screen.dart
...
onPressed: () {
if ([Link]!.validate()) {}
},
...
9. Hasil yang ditampilkan setelah validasi dibuat. Ketika IconButton check di tap sedangkan
title dan content tidak diisi maka akan muncul pesan validasi seperti gambar berikut.
55
10. Selanjutnya buat fungsi create note di dalam file database_helper.dart dengan
melakukan import file note_model.dart sebelumnya. Fungsi ini untuk menyimpan note
ke dalam tabel notes.
database_helper.dart
import '../models/note_model.dart';
...
...
// Create note method
Future<int> createNote(NoteModel note) async {
final Database db = await database;
11. Buat proses create note pada file create_note_screen.dart. Tambahkan beberapa baris
kode berikut di dalam class _CreateNoteScreenState, pastikan lakukan import file
database_helper.dart dan note_model.dart.
create_note_screen.dart
...
import '../models/note_model.dart';
import '../database/database_helper.dart';
...
...
final formKey = GlobalKey<FormState>();
56
final db = DatabaseHelper();
if (!mounted) return;
if (result > 0) {
[Link](context).showSnackBar(
SnackBar(
content: const Text('Note created successfully!'),
backgroundColor: [Link][400],
behavior: [Link],
),
);
[Link](context).showSnackBar(
57
const SnackBar(
content: Text('An error occurred while creating the note.'),
backgroundColor: [Link],
behavior: [Link],
),
);
}
}
...
create_note_screen.dart
...
IconButton(
onPressed: () {
if ([Link]!.validate()) {
createNote();
}
},
icon: const Icon([Link]),
),
...
13. Setelah selesai membuat proses create note, lakukan pengujian dengan cara mengisi
title dan content lalu tap IconButton check. Jika berhasil maka note akan disimpan
ke dalam database (tabel notes) dan aplikasi akan kembali ke halaman homepage
dan menampilkan SnackBar dengan pesan 'Note created successfully!'.
58
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 11 (Sebelas)
Telp/Fax. 061 822 4051
[Link]
Pada tahap ini akan dilakukan pengembangan pada homepage dengan menampilkan
data (notes) yang telah ditambahkan ke dalam database. Lakukan langkah-langkah berikut untuk
membuatnya :
1. Buat fungsi untuk mengambil data dari tabel notes pada class DatabaseHelper yang
berada di dalam file database_helper.dart.
database_helper.dart
...
// Get notes method
Future<List<NoteModel>> getNotes() async {
final db = await database;
final result = await [Link]('notes');
2. Lakukan modifikasi pada file note_screen.dart. Lakukan import beberapa file yang
dibutuhkan seperti berikut.
note_screen.dart
import 'package:flutter/[Link]';
import '../auth/login_screen.dart';
import 'package:intl/[Link]';
import '../database/database_helper.dart';
import '../models/note_model.dart';
import 'create_note_screen.dart';
...
59
note_screen.dart
...
class _NotesScreenState extends State<NotesScreen> {
late DatabaseHelper handler;
late Future<List<NoteModel>> notes;
@override
void initState() {
[Link]();
handler = DatabaseHelper();
notes = [Link]();
}
...
note_screen.dart
...
Expanded(
child: FutureBuilder<List<NoteModel>>(
future: notes,
builder: (BuildContext context,
AsyncSnapshot<List<NoteModel>> snapshot) {
if ([Link] == [Link]) {
return const Center(child: CircularProgressIndicator());
} else if ([Link]) {
return Center(child: Text('Error: ${[Link]}'));
} else if (![Link] || [Link]!.isEmpty) {
return const Center(child: Text("No Data"));
} else {
final items = [Link]!;
return [Link](
itemCount: [Link],
padding: const [Link](8),
itemBuilder: (context, index) {
final note = items[index];
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: [Link],
margin: const [Link](vertical: 6),
child: Card(
60
shape: RoundedRectangleBorder(
borderRadius: [Link](6),
),
elevation: 4,
shadowColor: [Link](0.5),
child: ListTile(
contentPadding: const [Link](
horizontal: 16, vertical: 6),
title: Text(
[Link],
style: const TextStyle(
fontWeight: [Link], fontSize: 16),
),
subtitle: Text(
DateFormat("yMMMd")
.format([Link]([Link])),
style: const TextStyle(
color: [Link], fontSize: 13),
),
onTap: () {
// Navigasi ke halaman lihat/update note
},
),
),
);
},
);
}
},
),
),
...
61
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 12 (Dua Belas)
Telp/Fax. 061 822 4051
[Link]
Halaman update data berfungsi untuk menampilkan catatan secara detail dan untuk
melakukan perubahan catatan. Lakukan langkah-langkah berikut untuk membuatnya :
update_note_screen.dart
import 'package:flutter/[Link]';
@override
State<UpdateNoteScreen> createState() => _UpdateNoteScreenState();
}
62
}
3. Selanjutnya modifikasi fungsi onTap pada widget ListTile yang berada pada file
notes_screen.dart. Tambahkan perintah navigasi untuk membuka halaman update data
ketika ListTile di tap.
note_screen.dart
...
import 'update_note_screen.dart';
...
onTap: () {
// Navigasi ke halaman lihat/update note
[Link](
context,
MaterialPageRoute(
builder: (context) => UpdateNoteScreen(),
),
);
},
...
63
5. Tambahkan sebuah IconButton check pada bagian AppBar yang berfungsi untuk
melakukan proses penyimpanan data ketika IconButton di tap.
update_note_screen.dart
...
appBar: AppBar(
title: const Text("Update Note"),
actions: [
IconButton(
onPressed: () {},
icon: const Icon([Link]),
),
],
),
...
6. Modifikasi bagian body dengan menambahkan sebuah Form dan sebuah TextFormField
untuk menampilkan title dan content note.
update_note_screen.dart
...
body: Form(
child: Padding(
padding: const [Link](10.0),
child: Column(
crossAxisAlignment: [Link],
children: [
const SizedBox(height: 5),
// TextField untuk input judul
TextFormField(
decoration: const InputDecoration(
labelText: "Title",
border: OutlineInputBorder(),
),
),
const SizedBox(height: 10),
// TextField untuk input isi catatan/note
TextFormField(
maxLines: 5,
decoration: const InputDecoration(
labelText: "Content",
64
border: OutlineInputBorder(),
alignLabelWithHint: true,
),
),
],
),
),
),
...
Setelah tahap desain user interface halaman update data selesai, selanjutnya adalah
membuat agar aplikasi bisa melakukan proses update data ke dalam database, lakukan
langkah-langkah berikut :
1. Tambahkan sebuah variabel instans dengan nama note yang menggunakan tipe data
NoteModel di dalam class UpdateNoteScreen. Kemudian tambahkan parameter pada
konstruktor UpdateNoteScreen.
update_note_screen.dart
import 'package:flutter/[Link]';
import '../models/note_model.dart';
2. Selanjutnya modifikasi navigasi untuk ke halaman update data yang berada pada file
notes_screen.dart dengan menambahkan argumen note seperti berikut.
note_screen.dart
...
[Link](
context,
MaterialPageRoute(
builder: (context) =>
UpdateNoteScreen(note: note),
),
65
);
...
update_note_screen.dart
...
class _UpdateNoteScreenState extends State<UpdateNoteScreen> {
late TextEditingController titleController;
late TextEditingController contentController;
...
update_note_screen.dart
...
TextFormField(
controller: titleController,
...
update_note_screen.dart
...
TextFormField(
controller: contentController,
...
update_note_screen.dart
...
late TextEditingController contentController;
66
7. Tambahkan properti key pada widget Form dengan value nama variabel
GlobalKey<FormState> yang telah dibuat sebelumnya.
update_note_screen.dart
...
body: Form(
key: formKey,
...
update_note_screen.dart
...
validator: (value) {
if (value!.isEmpty) {
return "Title is required";
}
return null;
},
...
update_note_screen.dart
...
validator: (value) {
if (value!.isEmpty) {
return "Content is required";
}
return null;
},
...
update_note_screen.dart
...
onPressed: () {
if ([Link]!.validate()) {}
},
...
67
11. Selanjutnya buat fungsi update note di dalam file database_helper.dart. Fungsi ini
untuk merubah catatan (note) yang ada pada tabel notes berdasarkan noteId.
database_helper.dart
...
// Update note method
Future<int> updateNote(String title, String content, int noteId) async
{
final Database db = await database;
return [Link](
'notes',
{
'noteTitle': title,
'noteContent': content,
},
where: 'noteId = ?',
whereArgs: [noteId],
);
}
...
12. Buat proses update data pada file update_note_screen.dart. Tambahkan beberapa
baris kode berikut di dalam class _UpdateNoteScreenState, pastikan lakukan import
file database_helper.dart dan notes_screen.dart.
update_note_screen.dart
...
import '../database/database_helper.dart';
import 'notes_screen.dart';
...
...
final formKey = GlobalKey<FormState>();
final db = DatabaseHelper();
@override
void initState() {
[Link]();
titleController = TextEditingController(text:
[Link]);
68
contentController = TextEditingController(text:
[Link]);
}
if (!mounted) return;
if (result > 0) {
[Link](context).showSnackBar(
SnackBar(
content: Text('Note updated successfully!'),
backgroundColor: [Link][400],
behavior: [Link],
),
);
[Link](
context,
MaterialPageRoute(builder: (context) => const NotesScreen()),
);
} else {
[Link](context).showSnackBar(
const SnackBar(
content: Text('Failed to update note. Please try again.'),
backgroundColor: [Link],
behavior: [Link],
),
);
}
} catch (e) {
if (!mounted) return;
[Link](context).showSnackBar(
const SnackBar(
content: Text('An error occurred while updating the note.'),
69
backgroundColor: [Link],
behavior: [Link],
),
);
}
}
...
update_note_screen.dart
...
IconButton(
onPressed: () {
if ([Link]!.validate()) {
updateNote();
}
},
icon: const Icon([Link]),
),
...
14. Setelah selesai membuat proses update data, lakukan pengujian dengan cara tap pada
catatan (note) yang ingin dirubah, Selanjutnya lakukan perubahan isi title atau content
lalu tap IconButton check. Jika berhasil maka note akan disimpan ke dalam database
(tabel notes) dan aplikasi akan kembali ke halaman homepage dan menampilkan
SnackBar dengan pesan “Note updated successfully!”.
70
71
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 13 (Tiga Belas)
Telp/Fax. 061 822 4051
[Link]
Pada tahap ini aplikasi akan dikembangkan dengan menambahkan fitur untuk menghapus
data. Untuk desain user interface aplikasi, akan ditampilkan sebuah icon delete dan sebuah jendela
dialog yang berisi pesan konfirmasi keyakinan untuk menghapus data. Lakukan langkah-langkah
berikut untuk membuatnya :
note_screen.dart
...
trailing: IconButton(
onPressed: () {},
icon: const Icon(
[Link],
color: [Link],
),
),
...
2. Buat fungsi untuk menampilkan jendela konfirmasi di dalam class _NotesScreenState agar
data tidak langsung terhapus.
note_screen.dart
...
void showDeleteDialog(BuildContext context, int noteId) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Delete Note?'),
content: const Text('Are you sure you want to delete this note?'),
72
actions: [
TextButton(
onPressed: () => [Link](context),
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
[Link](context);
},
child: const Text(
'Delete',
style: TextStyle(color: [Link]),
),
),
],
),
);
}
...
3. Selanjutnya panggil fungsi showDeleteDialog() pada IconButton Delete. Jika berhasil maka
aplikasi akan menampilkan jendela konfirmasi seperti gambar berikut ketika IconButton
Delete di tap.
note_screen.dart
...
trailing: IconButton(
onPressed: () {
showDeleteDialog(
context, items[index].noteId!);
},
icon: const Icon(
[Link],
color: [Link],
),
),
...
73
13.2 Membuat Proses Delete Data
Setelah tahap desain user interface delete data selesai, selanjutnya adalah membuat agar
aplikasi bisa melakukan proses delete data yang ada di database, lakukan langkah-langkah berikut.
1. Selanjutnya buat fungsi delete note di dalam file database_helper.dart. Fungsi ini untuk
menghapus catatan (note) yang ada pada tabel notes berdasarkan noteId.
database_helper.dart
...
// Delete notes method
Future<int> deleteNote(int id) async {
final Database db = await database;
return [Link](
'notes',
where: 'noteId = ?',
whereArgs: [id],
);
}
...
2. Buat proses delete data di dalam properti onPressed widget TextButton Delete. Tambahkan
beberapa baris kode berikut.
note_screen.dart
...
onPressed: () async {
[Link](context);
if (result > 0) {
setState(() {
notes = [Link]();
});
[Link](context).showSnackBar(
SnackBar(
content: const Text('Note deleted successfully!'),
backgroundColor: [Link][400],
74
behavior: [Link],
),
);
} else {
[Link](context).showSnackBar(
const SnackBar(
content: Text('Failed to delete note. Please try again.'),
backgroundColor: [Link],
behavior: [Link],
),
);
}
},
...
3. Setelah selesai membuat proses delete data, lakukan pengujian dengan cara tap IconButton
delete pada data yang ingin dihapus, Selanjutnya pada jendela konfirmasi pilih Delete. Jika
berhasil maka note akan dihapus dari database dan aplikasi akan me-refresh halaman homepage
dan menampilkan SnackBar dengan pesan “Note deleted successfully!”.
75
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 14 (Empat Belas)
Telp/Fax. 061 822 4051
[Link]
Pada tahap ini aplikasi akan dikembangkan dengan menambahkan proses untuk pencarian
data dengan cara mengisi title atau content yang ingin dicari pada TextFormField pencarian yang
telah dibuat sebelumnya. Lakukan langkah-langkah berikut untuk membuatnya :
1. Tambahkan fungsi search note di dalam file database_helper.dart. Fungsi ini untuk
mengambil catatan (note) yang ada pada tabel notes berdasarkan keyword pencarian judul dan
isi catatan yang diberikan oleh pengguna.
database_helper.dart
...
// Search notes method
Future<List<NoteModel>> searchNotes(String keyword) async {
final Database db = await database;
note_screen.dart
...
final TextEditingController _searchController = TextEditingController();
String _searchKeyword = '';
...
76
3. Tambahkan properti controller pada TextFormField pencarian dengan value
TextEditingController yang telah dibuat sebelumnya.
note_screen.dart
...
child: TextFormField(
controller: _searchController,
...
4. Tambahkan properti onChanged pada TextFormField pencarian agar responsif, yaitu data yang
ditampilkan sesuai dengan apa yang dicari, dan jika tidak ada data yang dicari maka akan
ditampilkan seluruh data.
note_screen.dart
...
onChanged: (value) {
setState(() {
_searchKeyword = [Link]();
if (_searchKeyword.isEmpty) {
notes = [Link]();
} else {
notes = [Link](_searchKeyword);
}
});
},
...
5. Setelah selesai membuat proses search data, lakukan pengujian dengan cara ketik keyword yang
ingin dicari pada textfield pencarian. Jika berhasil maka yang ditampilkan hanyalah data yang
mengandung unsur keyword yang ada pada textfield pencarian.
77
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 15 (Lima Belas)
Telp/Fax. 061 822 4051
[Link]
Deployment
15.1 Deployment
Setelah tahap pengembangan aplikasi selesai, langkah selanjutnya adalah deployment.
Proses ini dimulai dengan membangun (build) proyek aplikasi yang telah selesai dibuat menjadi
format yang bisa dijalankan di berbagai platform, seperti APK (Android Package Kit) atau
AAB (Android App Bundle) untuk Android, dan IPA (iOS App Store Package) untuk iOS.
File-file inilah yang nantinya akan didistribusikan melalui Google Play Store atau App Store,
atau langsung diinstal pada perangkat Android/iOS.
[Link]
...
<application
android:label="NotesApp"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
...
2. Ubah icon aplikasi yang secara default adalah icon flutter dengan cara mengganti gambar
icon “ic_launcher.png” dengan berbagai ukuran resolusi yang berada pada folder
android/app/src/main/res/. Sebelumnya buat icon yang akan digunakan terlebih dahulu,
misal menggunakan Android Asset Studio melalui link
78
[Link] kemudian pilih Launcher icon
generator dan desain icon, misal icon seperti berikut.
3. Download icon yang sudah dibuat kemudian lakukan unzip berkas yang telah didownload.
Hasilnya adalah akan dibuatkan icon dengan beberapa ukuran resolusi (mipmap).
Selanjutnya copy isi folder res ke dalam android/app/src/main/res/ seperti berikut.
4. Setelah selesai mengatur nama dan icon aplikasi, langkah selanjutnya adalah mengubah
aplikasi kita menjadi format APK. Penting untuk diketahui bahwa secara umum ada 2 mode
aplikasi yang berbeda: debug dan release. APK debug biasanya digunakan untuk
pengujian internal dan pengembangan. Mode ini aktif secara default saat menjalankan
aplikasi dengan perintah flutter run. Dan untuk aplikasi yang siap dirilis ke Google Play
Store, Anda perlu membuat APK release. Mode ini dioptimalkan untuk performa dan
ukuran. Dan pada materi ini hanya membahas mode debug, caranya adalah buka jendela
terminal pada text editor kemudian jalankan perintah berikut.
79
flutter clean
flutter pub get
flutter build apk --debug
Perintah Fungsi
flutter clean Membersihkan cache dan hasil build sebelumnya
flutter pub get Mengunduh dan menginstal dependency dari [Link]
flutter build apk
Membangun file APK untuk Android dalam mode debug
--debug
5. Setelah proses build APK selesai akan ditampilkan informasi seperti berikut pada jendela
terminal.
√ Built build\app\outputs\flutter-apk\[Link].
6. Selanjutnya kirim file [Link] ke perangkat android lalu instal. Jika berhasil maka
aplikasi akan terpasang pada perangkat android tersebut.
80
STMIK TRIGUNA DHARMA
Jl. Jend. AH Nasution
No. 73 F Medan
Pertemuan 16 (Enam Belas)
Telp/Fax. 061 822 4051
[Link]
81