EAS - APP iSaku

    

EAS

Aplikasi iSaku

Nama    : Arya Nur Razzaq

NRP    : 5025201102

Kelas    : PPB B

Kali ini kita mendapatkan tugas EAS untuk membuat aplikasi iSaku, dalam aplikasi ini kita dapat melakukan login dan signup kemudian kita dapat melakukan top up saldo

1. Set up project

Buka android studio lalu pilih New Project untuk membuat project baru. Kemudian pilih Empty Activity untuk set up project


2. Source Code
  • MainActivity
package com.example.isaku

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
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.foundation.layout.width
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
import androidx.compose.foundation.lazy.staggeredgrid.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
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.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.isaku.ui.theme.AlfamindTheme
import kotlinx.coroutines.delay
import com.example.isaku.data.products

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AlfamindTheme {
// A surface container using the 'background' color from the theme
MainApp()
}
}
}
}

enum class Screen {
Load, Login, Signup, Home, Transaksi
}

@Composable
fun MainApp() {
var currentScreen by remember { mutableStateOf(Screen.Load) }

LaunchedEffect(Unit) {
delay(3000)
currentScreen = Screen.Login
}

Crossfade(targetState = currentScreen) { screen ->
when (screen) {
Screen.Load -> LoadScreen()
Screen.Login -> LoginScreen(
onLoginSuccess = { currentScreen = Screen.Home },
onSignupClick = { currentScreen = Screen.Signup }
)
Screen.Signup -> SignupScreen(
onBackToLogin = { currentScreen = Screen.Login },
onSignupSuccess = { currentScreen = Screen.Home }
)
Screen.Home -> HomeScreen(
onClickTopup ={currentScreen = Screen.Transaksi}
)
Screen.Transaksi -> TransaksiScreen(
onLoginSuccess = { currentScreen = Screen.Home }
)
}
}
}

@Composable
fun LoadScreen() {
val configuration = LocalConfiguration.current
val screenWidth = configuration.screenWidthDp.dp
val padding = screenWidth * 0.2F

Surface (
modifier = Modifier
.fillMaxSize(),
color = colorResource(id = R.color.white)
) {
Image(
modifier = Modifier
.size(dimensionResource(id = R.dimen.image_size))
.padding(padding),
painter = painterResource(id = R.drawable.logo),
contentDescription = stringResource(id = R.string.app_name)
)
}
}

@Preview
@Composable
fun LoadScreenPreview() {
LoadScreen()
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LoginScreen(onLoginSuccess: () -> Unit, onSignupClick: () -> Unit) {
val configuration = LocalConfiguration.current
val screenWidth = configuration.screenWidthDp.dp
val logoSize = screenWidth * 0.6F

var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }

Surface(
modifier = Modifier
.fillMaxSize(),
color = colorResource(id = R.color.white)
) {
Column(
modifier = Modifier
.width(logoSize)
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
modifier = Modifier.width(logoSize),
painter = painterResource(id = R.drawable.logo),
contentDescription = stringResource(id = R.string.app_name)
)
Spacer(modifier = Modifier.height(50.dp))
Text(
text = "Email",
style = MaterialTheme.typography.titleSmall,
color = colorResource(id = R.color.abu_gelap),
modifier = Modifier.width(logoSize)
)
Spacer(modifier = Modifier.height(5.dp))
OutlinedTextField(
value = email,
onValueChange = { email = it },
shape = RoundedCornerShape(10.dp),
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = colorResource(id = R.color.biru_saku),
unfocusedBorderColor = colorResource(id = R.color.abu_terang)
),
placeholder = {
Text(
text = "example@gmail.com",
style = MaterialTheme.typography.titleSmall,
color = colorResource(id = R.color.abu_gelap)
)
},
modifier = Modifier
.clip(shape = RoundedCornerShape(10.dp))
.background(color = colorResource(id = R.color.white))
.height(50.dp)
)
Spacer(modifier = Modifier.height(15.dp))
Text(
text = "Password",
style = MaterialTheme.typography.titleSmall,
color = colorResource(id = R.color.abu_gelap),
modifier = Modifier.width(logoSize)
)
Spacer(modifier = Modifier.height(5.dp))
OutlinedTextField(
value = password,
onValueChange = { password = it },
shape = RoundedCornerShape(10.dp),
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = colorResource(id = R.color.biru_saku),
unfocusedBorderColor = colorResource(id = R.color.abu_terang)
),
visualTransformation = PasswordVisualTransformation(),
placeholder = {
Text(
text = "******",
style = MaterialTheme.typography.titleSmall,
color = colorResource(id = R.color.abu_gelap)
)
},
modifier = Modifier
.clip(shape = RoundedCornerShape(10.dp))
.background(color = colorResource(id = R.color.white))
.height(50.dp)
)
Spacer(modifier = Modifier.height(15.dp))
Text(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 50.dp)
.clickable { onSignupClick() }, // Handle click event
style = MaterialTheme.typography.titleSmall,
textAlign = TextAlign.Start,
text = stringResource(id = R.string.belum_akun),
color = colorResource(id = R.color.abu_gelap)
)
Spacer(modifier = Modifier.height(30.dp))
Button(
onClick = { onLoginSuccess() },
modifier = Modifier
.height(35.dp)
.width(200.dp), // Misalnya, lebar 200dp
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.buttonColors(
containerColor = colorResource(id = R.color.biru_saku)
),
border = BorderStroke(width = 0.5.dp, color = colorResource(id = R.color.biru_saku))
) {
Text(
text = "Masuk",
style = MaterialTheme.typography.titleSmall
)
}
}
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SignupScreen(onBackToLogin: () -> Unit, onSignupSuccess: () -> Unit) {
val configuration = LocalConfiguration.current
val screenWidth = configuration.screenWidthDp.dp
val logoSize = screenWidth * 0.6F

var username by remember { mutableStateOf("") }
var email by remember { mutableStateOf("") }
var password1 by remember { mutableStateOf("") }
var password2 by remember { mutableStateOf("") }

Surface(
modifier = Modifier
.fillMaxSize(),
color = colorResource(id = R.color.white)
) {
Column(
modifier = Modifier
.width(logoSize)
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
modifier = Modifier.width(logoSize),
painter = painterResource(id = R.drawable.logo),
contentDescription = stringResource(id = R.string.app_name)
)
Spacer(modifier = Modifier.height(50.dp))
Text(
text = "Username",
style = MaterialTheme.typography.titleSmall,
color = colorResource(id = R.color.abu_gelap),
modifier = Modifier.width(logoSize)
)
Spacer(modifier = Modifier.height(5.dp))
OutlinedTextField(
value = username,
onValueChange = { username = it },
shape = RoundedCornerShape(10.dp),
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = colorResource(id = R.color.biru_saku),
unfocusedBorderColor = colorResource(id = R.color.abu_terang)
),
placeholder = {
Text(
text = "masukkan username",
style = MaterialTheme.typography.titleSmall,
color = colorResource(id = R.color.abu_gelap)
)
},
modifier = Modifier
.clip(shape = RoundedCornerShape(10.dp))
.background(color = colorResource(id = R.color.white))
.height(50.dp)
)
Spacer(modifier = Modifier.height(15.dp))
Text(
text = "Email",
style = MaterialTheme.typography.titleSmall,
color = colorResource(id = R.color.abu_gelap),
modifier = Modifier.width(logoSize)
)
Spacer(modifier = Modifier.height(5.dp))
OutlinedTextField(
value = email,
onValueChange = { email = it },
shape = RoundedCornerShape(10.dp),
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = colorResource(id = R.color.biru_saku),
unfocusedBorderColor = colorResource(id = R.color.abu_terang)
),
placeholder = {
Text(
text = "example@gmail.com",
style = MaterialTheme.typography.titleSmall,
color = colorResource(id = R.color.abu_gelap)
)
},
modifier = Modifier
.clip(shape = RoundedCornerShape(10.dp))
.background(color = colorResource(id = R.color.white))
.height(50.dp)
)
Spacer(modifier = Modifier.height(15.dp))
Text(
text = "Password",
style = MaterialTheme.typography.titleSmall,
color = colorResource(id = R.color.abu_gelap),
modifier = Modifier.width(logoSize)
)
Spacer(modifier = Modifier.height(5.dp))
OutlinedTextField(
value = password1,
onValueChange = { password1 = it },
shape = RoundedCornerShape(10.dp),
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = colorResource(id = R.color.biru_saku),
unfocusedBorderColor = colorResource(id = R.color.abu_terang)
),
visualTransformation = PasswordVisualTransformation(),
placeholder = {
Text(
text = "******",
style = MaterialTheme.typography.titleSmall,
color = colorResource(id = R.color.abu_gelap)
)
},
modifier = Modifier
.clip(shape = RoundedCornerShape(10.dp))
.background(color = colorResource(id = R.color.white))
.height(50.dp)
)
Spacer(modifier = Modifier.height(15.dp))
Text(
text = "Konfirmasi Password",
style = MaterialTheme.typography.titleSmall,
color = colorResource(id = R.color.abu_gelap),
modifier = Modifier.width(logoSize)
)
Spacer(modifier = Modifier.height(5.dp))
OutlinedTextField(
value = password2,
onValueChange = { password2 = it },
shape = RoundedCornerShape(10.dp),
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = colorResource(id = R.color.biru_saku),
unfocusedBorderColor = colorResource(id = R.color.abu_terang)
),
visualTransformation = PasswordVisualTransformation(),
placeholder = {
Text(
text = "******",
style = MaterialTheme.typography.titleSmall,
color = colorResource(id = R.color.abu_gelap)
)
},
modifier = Modifier
.clip(shape = RoundedCornerShape(10.dp))
.background(color = colorResource(id = R.color.white))
.height(50.dp)
)
Spacer(modifier = Modifier.height(15.dp))
Text(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 50.dp)
.clickable { onBackToLogin() }, // Handle click event
style = MaterialTheme.typography.titleSmall,
textAlign = TextAlign.Start,
text = stringResource(id = R.string.sudah_akun),
color = colorResource(id = R.color.abu_gelap)
)

Spacer(modifier = Modifier.height(30.dp))
Button(
onClick = { onSignupSuccess() },
modifier = Modifier
.height(35.dp)
.width(200.dp),
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.buttonColors(
containerColor = colorResource(id = R.color.biru_saku)
),
border = BorderStroke(width = 0.5.dp, color = colorResource(id = R.color.biru_saku))
) {
Text(
text = "Sign Up",
style = MaterialTheme.typography.titleSmall
)
}
}
}
}

@Composable
fun AppTopBar() {
Row (
modifier = Modifier
.fillMaxWidth()
.background(color = colorResource(id = R.color.white))
.padding(horizontal = 20.dp, vertical = 0.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
){
Image(
modifier = Modifier
.size(width=150.dp, height=200.dp),
alignment = Alignment.Center,
painter = painterResource(id = R.drawable.logo),
contentDescription = stringResource(id = R.string.app_name)
)
}
}

@Preview
@Composable
fun AppTopBarPreview() {
AppTopBar()
}

@Composable
fun HomeScreen(onClickTopup: () -> Unit) {
val configuration = LocalConfiguration.current
val screenWidth = configuration.screenWidthDp.dp
val padding = screenWidth * 0.08F

Surface(
modifier = Modifier
.fillMaxSize(),
color = colorResource(id = R.color.white)
) {
Column (
modifier = Modifier
.fillMaxSize()
) {
AppTopBar()
Row (
modifier = Modifier
.padding(horizontal = padding)
.fillMaxWidth()
) {
Box(
modifier = Modifier
.fillMaxSize()
) {
Column {
Row {
ProfilCard()
}
Spacer(modifier = Modifier.height(10.dp))
Text(
text = "History Transaksi",
color = Color.Black, // Warna hitam (pastikan warna kontras dengan background)
fontWeight = FontWeight.Bold, // Membuat teks bold
fontSize = 18.sp // Mengatur ukuran font
)
Spacer(modifier = Modifier.height(2.dp))
Row {
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(1),
modifier = Modifier
.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalItemSpacing = 0.dp
) {
items(products) { product ->
Column(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
) {
ProductItem()
Spacer(modifier = Modifier.height(20.dp))
Button(
onClick = { onClickTopup()},
modifier = Modifier
.height(35.dp)
.width(300.dp), // Misalnya, lebar 200dp
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.buttonColors(
containerColor = colorResource(id = R.color.biru_saku)
),
border = BorderStroke(width = 0.5.dp, color = colorResource(id = R.color.biru_saku))
) {
Text(
text = "Top Up",
style = MaterialTheme.typography.titleSmall
)
}
}
}
}
}
}
}
}
}
}
}


@Composable
fun ProductItem(
modifier: Modifier = Modifier
) {
Card(
modifier = Modifier
.width(300.dp)
.height(100.dp) // Sesuaikan tinggi kotak jika diperlukan
.border(1.dp, Color.Black, shape = RoundedCornerShape(20.dp)), // Menambahkan border warna hitam
shape = RoundedCornerShape(20.dp),
colors = CardDefaults.cardColors(
containerColor = Color.White // Sesuaikan warna kotak jika diperlukan
)
) {
Box(
modifier = Modifier
.fillMaxSize()
.clip(shape = RoundedCornerShape(20.dp))
) {
Row(
modifier = Modifier
.fillMaxSize()
.padding(8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
// Sebelah kiri
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Topup",
fontWeight = FontWeight.Bold
)
Text(text = "Bank xxx")
Text(text = "John Mole")
}

// Garis pembatas vertikal di tengah
Box(
modifier = Modifier
.height(50.dp)
.width(1.dp)
.background(Color.Black)
)

// Sebelah kanan
Text(
text = "Rp.xx.xxx",
modifier = Modifier.weight(1f),
textAlign = TextAlign.Center
)
}
}
}
}

@Composable
fun ProfilCard() {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxWidth() // Memastikan Box mengisi seluruh lebar layar
.padding(10.dp)
) {
Box(
modifier = Modifier
.width(250.dp)
.height(100.dp)
.clip(RoundedCornerShape(10.dp))
.background(color = colorResource(id = R.color.biru_saku))
.padding(10.dp)
) {
Row(
modifier = Modifier
.fillMaxSize(),
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(id = R.drawable.profil),
contentDescription = stringResource(id = R.string.foto_profil),
contentScale = ContentScale.Crop,
modifier = Modifier
.size(60.dp)
.clip(RoundedCornerShape(40.dp)) // Clip image to have rounded corners
)
Spacer(modifier = Modifier.width(10.dp))
Column(
modifier = Modifier
.fillMaxWidth(),
horizontalAlignment = Alignment.Start, // Rata kiri
verticalArrangement = Arrangement.Center
) {
Text(
text = stringResource(id = R.string.nama_akun),
color = Color.White, // Warna putih
fontWeight = FontWeight.Bold, // Membuat teks bold
fontSize = 16.sp // Mengatur ukuran font
)
Text(
text = "Saldo:",
color = Color.White, // Warna putih
fontSize = 14.sp, // Mengatur ukuran font
modifier = Modifier.padding(top = 8.dp) // Menambahkan padding atas
)

Row(
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = stringResource(id = R.string.saldo_sisa),
color = Color.White, // Warna putih
fontSize = 18.sp // Mengatur ukuran font
)
Spacer(modifier = Modifier.width(8.dp))
}
}
}
}
}
}

@Composable
fun TransaksiScreen(onLoginSuccess: () -> Unit) {
var nominalTopup by remember { mutableStateOf("") }
var pin by remember { mutableStateOf("") }
var errorMessage by remember { mutableStateOf("") }

Column(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
OutlinedTextField(
value = nominalTopup,
onValueChange = { nominalTopup = it },
label = { Text("Nominal Topup") },
singleLine = true,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 8.dp)
)

OutlinedTextField(
value = pin,
onValueChange = { pin = it },
label = { Text("PIN") },
singleLine = true,
visualTransformation = PasswordVisualTransformation(),
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp)
)

Button(
onClick = {
if (nominalTopup.isBlank() || pin.isBlank()) {
errorMessage = "Silahkan isi nominal dan PIN"
} else if (pin != "1234") { // Ganti dengan validasi PIN yang sesuai dengan logika aplikasi Anda
errorMessage = "PIN yang Anda masukkan salah"
} else {
onLoginSuccess()
}
},
modifier = Modifier
.height(50.dp)
.width(200.dp),
shape = RoundedCornerShape(10.dp),
colors = ButtonDefaults.buttonColors(
containerColor = colorResource(id = R.color.biru_saku)
),
border = BorderStroke(width = 0.5.dp, color = colorResource(id = R.color.biru_saku))
) {
Text(
text = "Top Up",
color = Color.White
)
}

if (errorMessage.isNotEmpty()) {
Text(
text = errorMessage,
color = Color.Red,
modifier = Modifier.padding(top = 8.dp)
)
}
}
}


@Preview
@Composable
fun ProfilPreview() {
ProfilCard()
}

@Composable
fun CardProduk() {
val configuration = LocalConfiguration.current
val screenWidth = configuration.screenWidthDp.dp
val cardWidth = screenWidth * 0.35F

Card (
modifier = Modifier
.width(cardWidth)
.height(200.dp),
shape = RoundedCornerShape(20.dp),
colors = CardDefaults.cardColors(
containerColor = Color.Transparent
)
) {
Box (
modifier = Modifier
.fillMaxSize()
.clip(shape = RoundedCornerShape(20.dp))
) {
}
}
}

@Preview
@Composable
fun CardProdukPreview() {
CardProduk()
}


3. Tampilan App Login dan Transaksi


  • Tampilan Login



  • Tampilan sign up




  • Tampilan Menu Utama



  • Tampilan Menu Top Up










Comments

Popular posts from this blog

Tugas 1 PBKK

PBKK B Quiz - Aplikasi Pemesanan Tiket

PBKK B - EAS Aplikasi Presensi