ETS PPB I
Nama : Tegar Ganang Satrio Priambodo
NRP : 5025201002
Kelas : PPB I
ETS PPB I
Implementasi Redesign Aplikasi Pemesanan Tiket
- Halaman LoginScreen.kt

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.traveloka | |
import android.util.Log | |
import androidx.compose.foundation.Image | |
import androidx.compose.foundation.clickable | |
import androidx.compose.foundation.layout.Arrangement | |
import androidx.compose.foundation.layout.Column | |
import androidx.compose.foundation.layout.Row | |
import androidx.compose.foundation.layout.Spacer | |
import androidx.compose.foundation.layout.fillMaxSize | |
import androidx.compose.foundation.layout.fillMaxWidth | |
import androidx.compose.foundation.layout.height | |
import androidx.compose.foundation.layout.padding | |
import androidx.compose.foundation.layout.size | |
import androidx.compose.material3.Button | |
import androidx.compose.material3.ButtonDefaults | |
import androidx.compose.material3.OutlinedTextField | |
import androidx.compose.material3.Text | |
import androidx.compose.runtime.Composable | |
import androidx.compose.runtime.getValue | |
import androidx.compose.runtime.mutableStateOf | |
import androidx.compose.runtime.remember | |
import androidx.compose.runtime.setValue | |
import androidx.compose.ui.Alignment | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.res.painterResource | |
import androidx.compose.ui.text.font.FontWeight | |
import androidx.compose.ui.text.input.PasswordVisualTransformation | |
import androidx.compose.ui.unit.dp | |
import androidx.compose.ui.unit.sp | |
import androidx.navigation.NavController | |
import com.example.traveloka.R | |
@Composable | |
fun LoginScreen(navController: NavController) { | |
var email by remember { | |
mutableStateOf("") | |
} | |
var password by remember { | |
mutableStateOf("") | |
} | |
Column( | |
modifier = Modifier.fillMaxSize(), | |
verticalArrangement = Arrangement.Center, | |
horizontalAlignment = Alignment.CenterHorizontally | |
) { | |
Image( | |
painter = painterResource(id = R.drawable.traveloka), | |
contentDescription = "Login Image", | |
modifier = Modifier.size(200.dp) | |
) | |
Text(text = "Welcome Back", fontSize = 28.sp, fontWeight = FontWeight.Bold) | |
Spacer(modifier = Modifier.height(4.dp)) | |
Text(text = "Login to your account") | |
OutlinedTextField( | |
value = email, | |
onValueChange = { email = it }, | |
label = { Text(text = "Email address") } | |
) | |
Spacer(modifier = Modifier.height(16.dp)) | |
OutlinedTextField( | |
value = password, | |
onValueChange = { password = it }, | |
label = { Text(text = "Password") }, | |
visualTransformation = PasswordVisualTransformation() | |
) | |
Spacer(modifier = Modifier.height(16.dp)) | |
Button( | |
onClick = { | |
Log.i("Credential", "Email: $email Password: $password") | |
navController.navigate("home") | |
}, | |
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF00AEEF)) | |
) { | |
Text( | |
text = "Login", | |
modifier = Modifier.padding(8.dp) | |
) | |
} | |
Spacer(modifier = Modifier.height(32.dp)) | |
Text( | |
text = "Forgot Password?", | |
modifier = Modifier.clickable { | |
} | |
) | |
Spacer(modifier = Modifier.height(32.dp)) | |
Text(text = "Or Sign in with") | |
Row( | |
modifier = Modifier | |
.fillMaxWidth() | |
.padding(40.dp), | |
horizontalArrangement = Arrangement.SpaceEvenly | |
) { | |
Image( | |
painter = painterResource(id = R.drawable.google), | |
contentDescription = "Google", | |
modifier = Modifier | |
.size(40.dp) | |
.clickable { | |
// Google Clicked | |
} | |
) | |
Image( | |
painter = painterResource(id = R.drawable.fb), | |
contentDescription = "Facebook", | |
modifier = Modifier | |
.size(40.dp) | |
.clickable { | |
// Facebook Clicked | |
} | |
) | |
Image( | |
painter = painterResource(id = R.drawable.x), | |
contentDescription = "X", | |
modifier = Modifier | |
.size(40.dp) | |
.clickable { | |
// X Clicked | |
} | |
) | |
} | |
} | |
} |
- Halaman HomeScreen.kt

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.traveloka | |
import androidx.compose.foundation.BorderStroke | |
import androidx.compose.foundation.background | |
import androidx.compose.foundation.border | |
import androidx.compose.foundation.clickable | |
import androidx.compose.foundation.layout.* | |
import androidx.compose.foundation.shape.CircleShape | |
import androidx.compose.foundation.text.BasicTextField | |
import androidx.compose.material.icons.Icons | |
import androidx.compose.material.icons.filled.Search | |
import androidx.compose.material3.* | |
import androidx.compose.runtime.Composable | |
import androidx.compose.runtime.mutableStateOf | |
import androidx.compose.runtime.remember | |
import androidx.compose.ui.Alignment | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.draw.clip | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.res.painterResource | |
import androidx.compose.ui.text.input.TextFieldValue | |
import androidx.compose.ui.unit.dp | |
import androidx.navigation.NavController | |
@OptIn(ExperimentalMaterial3Api::class) | |
@Composable | |
fun HomeScreen(navController: NavController) { | |
Column( | |
modifier = Modifier | |
.fillMaxSize() | |
.padding(16.dp), | |
verticalArrangement = Arrangement.Top, | |
horizontalAlignment = Alignment.CenterHorizontally | |
) { | |
TopBar() | |
Spacer(modifier = Modifier.height(32.dp)) | |
MenuOptions(navController) | |
} | |
} | |
@Composable | |
fun TopBar() { | |
Row( | |
modifier = Modifier | |
.fillMaxWidth() | |
.padding(vertical = 16.dp), | |
horizontalArrangement = Arrangement.SpaceBetween, | |
verticalAlignment = Alignment.CenterVertically | |
) { | |
SearchBar() | |
Row(verticalAlignment = Alignment.CenterVertically) { | |
Icon( | |
painter = painterResource(id = R.drawable.ic_notification), | |
contentDescription = "Notifications", | |
modifier = Modifier.size(24.dp) | |
) | |
Spacer(modifier = Modifier.width(16.dp)) | |
Icon( | |
painter = painterResource(id = R.drawable.ic_profile), | |
contentDescription = "Profile", | |
modifier = Modifier.size(24.dp) | |
) | |
} | |
} | |
} | |
@Composable | |
fun SearchBar() { | |
val textState = remember { mutableStateOf(TextFieldValue("")) } | |
Box( | |
modifier = Modifier | |
.clip(shape = CircleShape) | |
.background(Color.White) | |
.border( | |
BorderStroke(2.dp, Color(0xFF00A8E8)), // Blue stroke for the search bar | |
shape = CircleShape | |
) | |
.padding(horizontal = 32.dp, vertical = 8.dp), | |
contentAlignment = Alignment.CenterStart | |
) { | |
Row(verticalAlignment = Alignment.CenterVertically) { | |
Icon(imageVector = Icons.Default.Search, contentDescription = "Search Icon") | |
Spacer(modifier = Modifier.width(8.dp)) | |
BasicTextField( | |
value = textState.value, | |
onValueChange = { textState.value = it }, | |
singleLine = true, | |
modifier = Modifier.fillMaxWidth(), | |
decorationBox = { innerTextField -> | |
if (textState.value.text.isEmpty()) { | |
Text(text = "Promo Tiket Pesawat", color = Color.Gray) | |
} | |
innerTextField() | |
} | |
) | |
} | |
} | |
} | |
@Composable | |
fun MenuOptions(navController: NavController) { | |
Row( | |
modifier = Modifier.fillMaxWidth(), | |
horizontalArrangement = Arrangement.SpaceAround | |
) { | |
MenuItem( | |
iconRes = R.drawable.ic_flight, | |
label = "Tiket Pesawat", | |
backgroundColor = Color(0xFF00AEEF), | |
onClick = { navController.navigate("travel") } | |
) | |
MenuItem( | |
iconRes = R.drawable.ic_hotel, | |
label = "Hotel", | |
backgroundColor = Color(0xFF0000FF) | |
) | |
} | |
} | |
@Composable | |
fun MenuItem(iconRes: Int, label: String, backgroundColor: Color, onClick: () -> Unit = {}) { | |
Column( | |
horizontalAlignment = Alignment.CenterHorizontally, | |
modifier = Modifier.clickable { onClick() } | |
) { | |
Box( | |
modifier = Modifier | |
.size(64.dp) | |
.background(backgroundColor, shape = CircleShape), | |
contentAlignment = Alignment.Center | |
) { | |
Icon( | |
painter = painterResource(id = iconRes), | |
contentDescription = label, | |
tint = Color.White | |
) | |
} | |
Spacer(modifier = Modifier.height(8.dp)) | |
Text(text = label, style = MaterialTheme.typography.bodyMedium, color = Color.Gray) | |
} | |
} |
- Halaman TravelScreen.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.traveloka | |
import android.annotation.SuppressLint | |
import androidx.compose.foundation.background | |
import androidx.compose.foundation.border | |
import androidx.compose.foundation.clickable | |
import androidx.compose.foundation.layout.* | |
import androidx.compose.foundation.shape.RoundedCornerShape | |
import androidx.compose.material3.* | |
import androidx.compose.runtime.Composable | |
import androidx.compose.runtime.mutableStateOf | |
import androidx.compose.runtime.remember | |
import androidx.compose.ui.Alignment | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.draw.clip | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.res.painterResource | |
import androidx.compose.ui.text.input.TextFieldValue | |
import androidx.compose.ui.tooling.preview.Preview | |
import androidx.compose.ui.unit.dp | |
import androidx.compose.ui.unit.sp | |
import androidx.navigation.NavController | |
import com.example.traveloka.ui.theme.TravelokaTheme | |
@Composable | |
fun TravelScreen(navController: NavController) { | |
Column( | |
modifier = Modifier | |
.fillMaxSize() | |
.background(Color(0xFF00A8E8)) | |
.padding(10.dp) | |
) { | |
Header(navController) | |
Spacer(modifier = Modifier.height(5.dp)) | |
BookingForm(navController) | |
} | |
} | |
@Composable | |
fun Header(navController: NavController) { | |
Row( | |
modifier = Modifier | |
.fillMaxWidth() | |
.padding(8.dp), | |
verticalAlignment = Alignment.CenterVertically | |
) { | |
Icon( | |
painter = painterResource(id = R.drawable.ic_arrow_back), | |
contentDescription = "Back", | |
modifier = Modifier.size(54.dp).clickable { navController.navigate("home") }, tint = Color.White | |
) | |
Spacer(modifier = Modifier.width(16.dp)) | |
Text( | |
text = "Tiket Pesawat", | |
color = Color.White, | |
fontSize = 18.sp | |
) | |
} | |
} | |
@SuppressLint("UnrememberedMutableState") | |
@Composable | |
fun BookingForm(navController: NavController) { | |
val isRoundTrip = remember { mutableStateOf(true) } | |
val fromState = remember { TextFieldValue("Tarakan (TRK)") } | |
val toState = remember { TextFieldValue("Surabaya (SUB)") } | |
val nameState = remember { mutableStateOf(TextFieldValue("Tegar")) } | |
val passengersState = remember { mutableStateOf(TextFieldValue("Tarakan (TRK)")) } | |
val classState = remember { mutableStateOf(TextFieldValue("Surabaya (SUB)")) } | |
val dateState = remember { mutableStateOf(TextFieldValue("Jumat, 17 Mei 2024")) } | |
val isReturn = remember { mutableStateOf(false) } | |
Column( | |
modifier = Modifier | |
.fillMaxWidth() | |
.padding(16.dp) | |
.background(Color.White, shape = RoundedCornerShape(16.dp)) | |
.padding(16.dp) | |
) { | |
Row( | |
// modifier = Modifier.fillMaxWidth(), | |
horizontalArrangement = Arrangement.SpaceBetween | |
) { | |
ToggleButton(text = "Pergi / Pulang", selected = isRoundTrip.value) { | |
isRoundTrip.value = true | |
} | |
ToggleButton(text = "Multi-Kota", selected = !isRoundTrip.value) { | |
isRoundTrip.value = false | |
} | |
} | |
Spacer(modifier = Modifier.height(16.dp)) | |
BookingTextField(label = "Dari:", textState = "Tarakan (TRK)" ) | |
Spacer(modifier = Modifier.height(8.dp)) | |
BookingTextField(label = "Ke:", textState = "Surabaya (SUB)") | |
Spacer(modifier = Modifier.height(8.dp)) | |
BookingTextField(label = "Nama Pemesan:", textState = "Tegar") | |
Spacer(modifier = Modifier.height(8.dp)) | |
BookingTextField(label = "Penumpang:", textState = "1 Penumpang") | |
Spacer(modifier = Modifier.height(8.dp)) | |
BookingTextField(label = "Kelas Penerbangan:", textState = "Ekonomi") | |
Spacer(modifier = Modifier.height(8.dp)) | |
BookingTextField(label = "Tanggal Berangkat:", textState = "Jumat, 17 Mei 2024", showIcon = true) | |
Spacer(modifier = Modifier.height(8.dp)) | |
Row( | |
modifier = Modifier.fillMaxWidth(), | |
verticalAlignment = Alignment.CenterVertically | |
) { | |
Text(text = "Pulang Pergi?") | |
Spacer(modifier = Modifier.width(8.dp)) | |
Switch(checked = isReturn.value, onCheckedChange = { isReturn.value = it }) | |
} | |
Spacer(modifier = Modifier.height(16.dp)) | |
Button( | |
onClick = { navController.navigate("booking") }, | |
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFFF5722)), | |
modifier = Modifier | |
.fillMaxWidth() | |
.height(48.dp), | |
shape = RoundedCornerShape(24.dp) | |
) { | |
Text(text = "Cari", color = Color.White) | |
} | |
} | |
} | |
@Composable | |
fun ToggleButton(text: String, selected: Boolean, onClick: () -> Unit) { | |
Box( | |
contentAlignment = Alignment.Center, | |
modifier = Modifier | |
.size(width = 150.dp, height = 58.dp) | |
.padding(4.dp) | |
.clip(RoundedCornerShape(24.dp)) | |
.background(if (selected) Color.White else Color(0xFF00A8E8)) | |
.border( | |
width = 1.dp, | |
color = if (selected) Color(0xFF00A8E8) else Color.Transparent, | |
shape = RoundedCornerShape(24.dp) | |
) | |
.clickable { onClick() } | |
.padding(vertical = 12.dp) | |
) { | |
Text(text = text, color = if (selected) Color(0xFF00A8E8) else Color.White) | |
} | |
} | |
@Composable | |
fun BookingTextField(label: String, textState: String, showIcon: Boolean = false) { | |
Column { | |
Text(text = label, color = Color.Gray) | |
Spacer(modifier = Modifier.height(4.dp)) | |
Box( | |
modifier = Modifier | |
.fillMaxWidth() | |
.clip(RoundedCornerShape(8.dp)) | |
.background(Color(0xFFF2F2F2)) | |
.padding(horizontal = 8.dp, vertical = 12.dp) | |
) { | |
Row(verticalAlignment = Alignment.CenterVertically) { | |
Text(text = textState, color = Color.Gray) | |
if (showIcon) { | |
Icon( | |
painter = painterResource(id = R.drawable.ic_calendar), | |
contentDescription = "Calendar", | |
modifier = Modifier.size(24.dp) | |
) | |
} | |
} | |
} | |
} | |
} | |
@Preview(showBackground = true) | |
@Composable | |
fun TravelScreenPreview() { | |
TravelokaTheme { | |
TravelScreen() | |
} | |
} | |
fun TravelScreen() { | |
TODO("Not yet implemented") | |
} |
- Halaman BookingScreen.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.traveloka | |
import androidx.compose.foundation.background | |
import androidx.compose.foundation.clickable | |
import androidx.compose.foundation.layout.* | |
import androidx.compose.foundation.shape.RoundedCornerShape | |
import androidx.compose.material3.* | |
import androidx.compose.runtime.* | |
import androidx.compose.ui.Alignment | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.res.painterResource | |
import androidx.compose.ui.text.font.FontWeight | |
import androidx.compose.ui.unit.dp | |
import androidx.compose.ui.unit.sp | |
import androidx.compose.ui.tooling.preview.Preview | |
import androidx.navigation.NavController | |
import com.example.traveloka.ui.theme.TravelokaTheme | |
@Composable | |
fun BookingScreen(navController: NavController) { | |
Column( | |
modifier = Modifier | |
.fillMaxSize() | |
.background(Color(0xFF00AEEF)) | |
.padding(16.dp) | |
) { | |
// Header | |
BookingHeader(navController) | |
Spacer(modifier = Modifier.height(16.dp)) | |
// Harga Termurah Button | |
Button( | |
onClick = { /* Handle harga termurah click */ }, | |
modifier = Modifier.fillMaxWidth(), | |
colors = ButtonDefaults.buttonColors(containerColor = Color.White) | |
) { | |
Text(text = "Harga Termurah", color = Color.Black) | |
} | |
Spacer(modifier = Modifier.height(16.dp)) | |
// List of Flight Options | |
FlightOptions() | |
} | |
} | |
@Composable | |
fun BookingHeader(navController: NavController) { | |
Row( | |
modifier = Modifier.fillMaxWidth(), | |
// horizontalArrangement = Arrangement.SpaceBetween, | |
verticalAlignment = Alignment.CenterVertically | |
) { | |
Icon( | |
painter = painterResource(id = R.drawable.ic_arrow_back), | |
contentDescription = "Back", | |
modifier = Modifier.size(54.dp).clickable { navController.navigate("home") }, tint = Color.White | |
) | |
Spacer(modifier = Modifier.width(8.dp)) | |
Column ( | |
verticalArrangement = Arrangement.Center | |
){ | |
Text( | |
text = "Tarakan ➔ Surabaya", | |
style = MaterialTheme.typography.titleLarge, | |
color = Color.White | |
) | |
Spacer(modifier = Modifier.height(4.dp)) | |
Text( | |
text = "Jum, 17 Mei - 1 Pax - Economy", | |
style = MaterialTheme.typography.bodyMedium, | |
color = Color.White | |
) | |
} | |
} | |
} | |
@Composable | |
fun FlightOptions() { | |
val flightDetails = listOf( | |
FlightDetail(time = "13:10", duration = "6j 20mnt", arrival = "18:30", price = "Rp 1.653.700/org", points = "1778 Point", airline = "Super Air Jet"), | |
FlightDetail(time = "13:10", duration = "6j 20mnt", arrival = "18:30", price = "Rp 1.653.700/org", points = "1778 Point", airline = "Super Air Jet"), | |
FlightDetail(time = "13:10", duration = "6j 20mnt", arrival = "18:30", price = "Rp 1.653.700/org", points = "1778 Point", airline = "Super Air Jet"), | |
FlightDetail(time = "13:10", duration = "6j 20mnt", arrival = "18:30", price = "Rp 1.653.700/org", points = "1778 Point", airline = "Super Air Jet") | |
) | |
Column { | |
flightDetails.forEach { flightDetail -> | |
FlightOptionItem(flightDetail) | |
Spacer(modifier = Modifier.height(8.dp)) | |
} | |
} | |
} | |
data class FlightDetail( | |
val time: String, | |
val duration: String, | |
val arrival: String, | |
val price: String, | |
val points: String, | |
val airline: String | |
) | |
@Composable | |
fun FlightOptionItem(flightDetail: FlightDetail) { | |
Column( | |
modifier = Modifier | |
.fillMaxWidth() | |
.background(Color.White, shape = RoundedCornerShape(8.dp)) | |
.padding(16.dp) | |
) { | |
Row( | |
modifier = Modifier.fillMaxWidth(), | |
horizontalArrangement = Arrangement.SpaceBetween | |
) { | |
Text( | |
text = "${flightDetail.time} ➔ ${flightDetail.arrival}", | |
style = MaterialTheme.typography.bodyLarge, | |
fontWeight = FontWeight.Bold | |
) | |
Text( | |
text = flightDetail.duration, | |
style = MaterialTheme.typography.bodyMedium, | |
color = Color.Gray | |
) | |
} | |
Spacer(modifier = Modifier.height(8.dp)) | |
Text( | |
text = flightDetail.price, | |
style = MaterialTheme.typography.bodyLarge.copy(fontSize = 24.sp), | |
color = Color(0xFFFF5722), | |
fontWeight = FontWeight.Bold | |
) | |
Spacer(modifier = Modifier.height(4.dp)) | |
Row( | |
modifier = Modifier.fillMaxWidth(), | |
horizontalArrangement = Arrangement.SpaceBetween | |
) { | |
Text( | |
text = flightDetail.airline, | |
style = MaterialTheme.typography.bodyMedium, | |
color = Color.Gray | |
) | |
Spacer(modifier = Modifier.height(8.dp)) | |
Text( | |
text = flightDetail.points, | |
style = MaterialTheme.typography.bodyMedium, | |
color = Color.Green | |
) | |
} | |
} | |
} | |
//@Preview(showBackground = true) | |
//@Composable | |
//fun BookingScreenPreview() { | |
// TravelokaTheme { | |
// BookingScreen() | |
// } | |
//} | |
// | |
//fun BookingScreen() { | |
// TODO("Not yet implemented") | |
//} | |
Komentar
Posting Komentar