Tugas Pertemuan 13 Pemrograman Perangkat Bergerak B
Nama : Fadaukas Daffa Tajuddin
NRP : 5025231149
Kelas : PPB (B)
Membuat Registrasi Siswa
Aplikasi Registrasi Siswa adalah solusi manajemen data siswa sederhana yang memungkinkan pengguna untuk melakukan operasi CRUD (Create, Read, Update, Delete). Aplikasi ini dibangun menggunakan teknologi modern Android yaitu Jetpack Compose untuk antarmuka pengguna dan Room Database untuk penyimpanan data lokal secara persisten.
Komponen Utama
Siswa.kt
package com.example.registrasisiswa.data
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "siswa")
data class Siswa(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val nama: String,
val email: String
)
SiswaDao.kt
package com.example.registrasisiswa.data
import androidx.room.*
import kotlinx.coroutines.flow.Flow
@Dao
interface SiswaDao {
@Query("SELECT * FROM siswa ORDER BY nama ASC")
fun getAllSiswa(): Flow<List<Siswa>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertSiswa(siswa: Siswa)
@Update
suspend fun updateSiswa(siswa: Siswa)
@Delete
suspend fun deleteSiswa(siswa: Siswa)
}
Database
package com.example.registrasisiswa.data
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(entities = [Siswa::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun siswaDao(): SiswaDao
companion object {
@Volatile
private var Instance: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
return Instance ?: synchronized(this) {
Room.databaseBuilder(context, AppDatabase::class.java, "siswa_database")
.build()
.also { Instance = it }
}
}
}
}
StudentViewModel.kt
package com.example.registrasisiswa.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.registrasisiswa.data.Siswa
import com.example.registrasisiswa.data.SiswaDao
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
class StudentViewModel(private val dao: SiswaDao) : ViewModel() {
val allSiswa: StateFlow<List<Siswa>> = dao.getAllSiswa()
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = emptyList()
)
fun insertSiswa(nama: String, email: String) {
viewModelScope.launch {
dao.insertSiswa(Siswa(nama = nama, email = email))
}
}
fun updateSiswa(siswa: Siswa) {
viewModelScope.launch {
dao.updateSiswa(siswa)
}
}
fun deleteSiswa(siswa: Siswa) {
viewModelScope.launch {
dao.deleteSiswa(siswa)
}
}
}
FormInput.kt
package com.example.registrasisiswa.ui
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun FormInput(
onAddClick: (String, String) -> Unit,
modifier: Modifier = Modifier
) {
var nama by remember { mutableStateOf("") }
var email by remember { mutableStateOf("") }
Column(
modifier = modifier
.fillMaxWidth()
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
OutlinedTextField(
value = nama,
onValueChange = { nama = it },
label = { Text("Nama") },
modifier = Modifier.fillMaxWidth()
)
OutlinedTextField(
value = email,
onValueChange = { email = it },
label = { Text("Email") },
modifier = Modifier.fillMaxWidth()
)
Button(
onClick = {
if (nama.isNotBlank() && email.isNotBlank()) {
onAddClick(nama, email)
nama = ""
email = ""
}
},
modifier = Modifier.fillMaxWidth(),
shape = MaterialTheme.shapes.medium
) {
Icon(Icons.Default.Add, contentDescription = null)
Spacer(Modifier.width(8.dp))
Text("Tambah Siswa")
}
}
}
StudentItem.kt
package com.example.registrasisiswa.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.registrasisiswa.data.Siswa
@Composable
fun StudentItem(
siswa: Siswa,
onEditClick: () -> Unit,
onDeleteClick: () -> Unit,
modifier: Modifier = Modifier
) {
Card(
modifier = modifier
.fillMaxWidth()
.padding(vertical = 4.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) {
Row(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
// Initial Circle
Box(
modifier = Modifier
.size(40.dp)
.background(
color = Color(0xFFE3F2FD),
shape = CircleShape
),
contentAlignment = Alignment.Center
) {
val initial = if (siswa.nama.isNotEmpty()) siswa.nama.take(2).uppercase() else "?"
Text(
text = initial,
color = Color(0xFF1976D2),
fontWeight = FontWeight.Bold,
fontSize = 14.sp
)
}
Spacer(Modifier.width(16.dp))
Column(modifier = Modifier.weight(1f)) {
Text(
text = siswa.nama,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold
)
Text(
text = siswa.email,
style = MaterialTheme.typography.bodySmall,
color = Color.Gray
)
}
IconButton(onClick = onEditClick) {
Icon(
Icons.Default.Edit,
contentDescription = "Edit",
tint = Color(0xFF3F51B5)
)
}
IconButton(onClick = onDeleteClick) {
Icon(
Icons.Default.Delete,
contentDescription = "Delete",
tint = Color(0xFFE57373)
)
}
}
}
}
MainActivity.kt
package com.example.registrasisiswa
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.registrasisiswa.data.AppDatabase
import com.example.registrasisiswa.data.SiswaDao
import com.example.registrasisiswa.ui.MainScreen
import com.example.registrasisiswa.ui.theme.RegistrasiSiswaTheme
import com.example.registrasisiswa.viewmodel.StudentViewModel
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 1. Inisialisasi database dan DAO
val database = AppDatabase.getDatabase(applicationContext)
val dao = database.siswaDao()
enableEdgeToEdge()
setContent {
RegistrasiSiswaTheme {
// 2. Inisialisasi ViewModel dengan Factory agar bisa menerima parameter DAO
val viewModel: StudentViewModel = viewModel(
factory = StudentViewModelFactory(dao)
)
// 3. Tampilkan Layar Utama
MainScreen(viewModel = viewModel)
}
}
}
}
// Factory untuk membuat StudentViewModel
class StudentViewModelFactory(private val dao: SiswaDao) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(StudentViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return StudentViewModel(dao) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
Aplikasi
Komentar
Posting Komentar