Appendix 2 - Full Source Code
Appendix 2 - Full Source Code
Package Manifests
[Link]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="[Link]
xmlns:tools="[Link]
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/[Link]">
</application>
</manifest>
Package kotlin+java
[Link]
package [Link]
import [Link]
import [Link].*
import [Link]
db = DatabaseHelper(this)
if ([Link]()) {
[Link](this, "Category name cannot be empty",
Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
if (type == null) {
[Link](this, "Select category type",
Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
try {
[Link](userId, name, type)
[Link](this, "Category added",
Toast.LENGTH_SHORT).show()
finish()
} catch (e: Exception) {
[Link](this, "Failed to add category",
Toast.LENGTH_SHORT).show()
}
}
[Link] {
finish()
}
}
[Link]
package [Link]
import [Link]
import [Link]
import [Link]
import [Link].*
import [Link]
import [Link]
import [Link].*
class AddTransactionActivity : AppCompatActivity() {
findViewById<Button>([Link]).setOnClickListener {
finish()
}
// Set default date to today
updateDateDisplay()
[Link] {
showDatePicker()
}
// Save button
[Link] {
saveTransaction()
}
}
if ([Link]()) {
[Link](this, "No categories found. Add one first!",
Toast.LENGTH_SHORT).show()
[Link] = null
return
}
[Link] = ArrayAdapter(
this,
[Link].simple_spinner_item,
categories
).apply {
setDropDownViewResource([Link].simple_spinner_dropdown_item)
}
}
if (category == null) {
[Link](this, "Please select a category",
Toast.LENGTH_SHORT).show()
return
}
if ([Link]()) {
[Link](this, "Please enter amount",
Toast.LENGTH_SHORT).show()
return
}
[Link](
userId = userId,
date = selectedDate,
category = category,
type = type,
amount = amount,
note = note
)
[Link]("")
[Link]("")
finish()
}
[Link]
package [Link]
[Link]
package [Link]
import [Link]
import [Link].*
import [Link]
import [Link]
import [Link].*
db = DatabaseHelper(this)
// Get userId
userId = [Link]("USER_ID", -1)
if (userId == -1) {
[Link](this, "Error: User not found",
Toast.LENGTH_SHORT).show()
finish()
return
}
// Back button
findViewById<Button>([Link]).setOnClickListener {
finish()
}
/**
* Loads category totals and calculates percentage breakdown
*/
private fun loadSummary(type: String, listView: ListView) {
[Link]
package [Link]
import [Link]
import [Link]
import [Link]
import [Link]
fun insertTransaction(
userId: Int,
date: String,
category: String,
type: String,
amount: Double,
note: String
) {
val cv = ContentValues()
[Link]("userId", userId)
[Link]("date", date)
[Link]("category", category)
[Link]("type", type)
[Link]("amount", amount)
[Link]("note", note)
[Link]("transactions", null, cv)
}
[Link]
package [Link]
import [Link]
import [Link]
import [Link]
import [Link]
db = DatabaseHelper(this)
// Get userId
userId = [Link]("USER_ID", -1)
if (userId == -1) {
[Link](this, "Error: User not found",
Toast.LENGTH_SHORT).show()
finish()
return
}
// Back button
findViewById<Button>([Link]).setOnClickListener {
finish()
}
findViewById<Button>([Link]).setOnClickListener {
val transactions = [Link](userId)
if ([Link]()) {
[Link](this, "No transactions to export",
Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
import [Link]
import [Link]
import [Link]
import [Link].*
import [Link]
import [Link]
db = DatabaseHelper(this)
// Get userId
userId = [Link]("USER_ID", -1)
if (userId == -1) {
[Link](this, "Error: User not found",
Toast.LENGTH_SHORT).show()
finish()
return
}
// Back button
findViewById<Button>([Link]).setOnClickListener {
finish()
}
// Load data and create graphs
loadGraphs()
}
if ([Link]()) {
[Link](this, "No data to display. Add transactions first!",
Toast.LENGTH_LONG).show()
return
}
// Calculate totals
var totalIncome = 0.0
var totalExpense = 0.0
val expenseByCategory = mutableMapOf<String, Double>()
if (max > 0) {
val incomeHeight = ((income / max) * 300).toInt()
val expenseHeight = ((expense / max) * 300).toInt()
[Link]()
[Link]()
}
val formatter =
[Link]([Link]("id", "ID"))
[Link] = [Link](income)
[Link] = [Link](expense)
}
if (total == 0.0) {
val emptyText = TextView(this)
[Link] = getString([Link])
[Link]([Link])
[Link](emptyText)
return
}
[Link](nameText)
[Link](amountText)
// Progress bar
val progressBar = View(this).apply {
setBackgroundColor(getColorForCategory(category))
layoutParams = [Link](
(percentage * 3).toInt().coerceAtLeast(10),
20
)
}
[Link](infoLayout)
[Link](progressBar)
[Link](rowLayout)
}
}
import [Link]
import [Link]
import [Link].*
import [Link]
import [Link]
import [Link].*
db = DatabaseHelper(this)
// Initialize views
tvIncome = findViewById([Link])
tvExpense = findViewById([Link])
tvBalance = findViewById([Link])
btnAddTransaction = findViewById([Link])
btnViewTransactions = findViewById([Link])
btnCategorySummary = findViewById([Link])
btnViewGraphs = findViewById([Link])
btnExport = findViewById([Link])
btnLogout = findViewById([Link])
// Load summary
loadSummary()
// Button listeners
[Link] {
val intent = Intent(this, AddTransactionActivity::[Link])
[Link]("USER_ID", userId)
startActivity(intent)
}
[Link] {
val intent = Intent(this, ViewTransactionsActivity::[Link])
[Link]("USER_ID", userId)
startActivity(intent)
}
[Link] {
val intent = Intent(this, CategorySummaryActivity::[Link])
[Link]("USER_ID", userId)
startActivity(intent)
}
[Link] {
val intent = Intent(this, GraphActivity::[Link])
[Link]("USER_ID", userId)
startActivity(intent)
}
[Link] {
val intent = Intent(this, ExportPdfActivity::[Link])
[Link]("USER_ID", userId)
startActivity(intent)
}
[Link] {
// Clear any session data if needed
val intent = Intent(this, MainActivity::[Link])
[Link] = Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
finish()
}
}
[Link]
package [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
try {
setContentView([Link].activity_main)
// Set listeners
[Link] { handleLogin() }
[Link] { navigateToSignup() }
[Link]
package [Link]
import [Link]
import [Link].*
import [Link]
import [Link]
db = DatabaseHelper(this)
// Back button
findViewById<Button>([Link]).setOnClickListener {
finish()
}
[Link](this)
.setTitle("Add Category")
.setView(input)
.setPositiveButton("Add") { _, _ ->
val name = [Link]().trim()
if ([Link]()) {
[Link](userId, name, currentType)
loadCategories()
[Link](this, "Category added",
Toast.LENGTH_SHORT).show()
}
}
.setNegativeButton("Cancel", null)
.show()
}
[Link]
package [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link].*
object PdfExporter {
[Link] = 12f
var pageNumber = 1
var y = 40
[Link] = 18f
[Link]("FinanceMate - Transaction Report", 40f, [Link](),
paint)
y += 30
[Link] = 12f
if (y > 800) {
[Link](page)
pageNumber++
page = [Link](
[Link](595, 842, pageNumber).create()
)
y = 40
}
y += 20
}
[Link](page)
return file
}
[Link] = 12f
var pageNumber = 1
var y = 40
var page = [Link](
[Link](595, 842, pageNumber).create()
)
[Link] = 18f
[Link]("FinanceMate - Transaction Report", 40f, [Link](),
paint)
y += 30
[Link] = 12f
[Link](page)
return uri
}
}
[Link]
package [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
db = DatabaseHelper(this)
val etUsername = findViewById<EditText>([Link])
val etPassword = findViewById<EditText>([Link])
val btnSignup = findViewById<Button>([Link])
val btnBackToLogin = findViewById<Button>([Link])
[Link] {
if (success) {
[Link](this, "Account created",
Toast.LENGTH_SHORT).show()
// BACK TO LOGIN
val intent = Intent(this, MainActivity::[Link])
startActivity(intent)
finish()
} else {
[Link](this, "Username already exists",
Toast.LENGTH_SHORT).show()
}
}
[Link] {
finish()
}
}
[Link]
package [Link]
[Link]
package [Link]
import [Link]
import [Link].*
import [Link]
import [Link]
import [Link]
import [Link].*
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "All Transactions"
db = DatabaseHelper(this)
spinnerFilter = findViewById([Link])
spinnerCategory = findViewById([Link])
listView = findViewById([Link])
tvTotal = findViewById([Link])
findViewById<Button>([Link]).setOnClickListener {
finish()
}
allTransactions = [Link](userId)
if ([Link]()) {
[Link](this, "No transactions yet. Add some first!",
Toast.LENGTH_LONG).show()
} else {
[Link](this, "Found ${[Link]} transactions",
Toast.LENGTH_SHORT).show()
}
[Link]([Link].simple_spinner_dropdown
_item)
[Link] = spinnerAdapter
[Link]([Link].simple_spinner_dropdow
n_item)
[Link] = categoryAdapter
[Link] = object :
[Link] {
override fun onItemSelected(parent: AdapterView<*>, view:
[Link]?, position: Int, id: Long) {
if (!isInitialLoad) {
applyFilters()
}
}
[Link] = object :
[Link] {
override fun onItemSelected(parent: AdapterView<*>, view:
[Link]?, position: Int, id: Long) {
if (!isInitialLoad) {
applyFilters()
}
}
isInitialLoad = false
applyFilters()
}
displayTransactions(filtered)
}
if ([Link]()) {
[Link] = null
[Link] = "No transactions found"
return
}
// Calculate totals
var totalIncome = 0.0
var totalExpense = 0.0
💰 💸
val displayList = [Link] { transaction ->
val typeIcon = if ([Link] == "IN") " " else " "
val typeText = if ([Link] == "IN") "Income" else "Expense"
if ([Link] == "IN") {
totalIncome += [Link]
} else {
totalExpense += [Link]
}
"$typeIcon ${[Link]}\n${[Link]} -
$typeText\n${[Link]([Link])}\nNote: ${[Link]}"
}
[Link] = ArrayAdapter(
this,
[Link].simple_list_item_1,
displayList
)
// Display total
val balance = totalIncome - totalExpense
[Link] = "Income: ${[Link](totalIncome)} | Expense:
${[Link](totalExpense)} " +
"| Balance: ${[Link](balance)}"
}
Package layout
activity_add_category.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/cream"
android:padding="20dp"
android:gravity="center">
<!-- Header with Back Button -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="8dp">
<Button
android:id="@+id/btnBackArrow"
android:layout_width="40dp"
android:layout_height="40dp"
android:text="←"
android:textSize="24sp"
android:textColor="@color/primary_blue"
android:background="@android:color/transparent"
android:padding="0dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Add Category"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_marginStart="8dp"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Create a new transaction category"
android:textSize="14sp"
android:textColor="@color/text_light"
android:layout_marginBottom="40dp"/>
<EditText
android:id="@+id/etCategoryName"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="e.g., Food, Transport, Salary"
android:padding="12dp"
android:background="@color/cream"
android:textColor="@color/text_dark"
android:layout_marginBottom="20dp"/>
<RadioGroup
android:id="@+id/rgCategoryType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="24dp">
<RadioButton
android:id="@+id/rbIncome"
android:layout_width="0dp"
android:layout_height="wrap_content"
💰
android:layout_weight="1"
android:text=" Income"
android:textSize="15sp"
android:buttonTint="@color/primary_blue"
android:checked="true"
android:padding="8dp"/>
<RadioButton
android:id="@+id/rbExpense"
android:layout_width="0dp"
android:layout_height="wrap_content"
💸
android:layout_weight="1"
android:text=" Expense"
android:textSize="15sp"
android:buttonTint="@color/primary_blue"
android:padding="8dp"/>
</RadioGroup>
💾
android:layout_height="56dp"
android:text=" Save Category"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
android:backgroundTint="@color/primary_blue"
android:elevation="2dp"
android:layout_marginBottom="12dp"/>
<Button
android:id="@+id/btnBack"
android:layout_width="match_parent"
android:layout_height="56dp"
android:text="Cancel"
android:textColor="@color/primary_blue"
android:textSize="16sp"
android:backgroundTint="@color/cream"
android:elevation="2dp"/>
</LinearLayout>
</LinearLayout>
activity_add_transaction.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/cream"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<!-- Header with Back Button -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="8dp">
<Button
android:id="@+id/btnBackArrow"
android:layout_width="40dp"
android:layout_height="40dp"
android:text="←"
android:textSize="24sp"
android:textColor="@color/primary_blue"
android:background="@android:color/transparent"
android:padding="0dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Add Transaction"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_marginStart="8dp"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Record your income or expense"
android:textSize="14sp"
android:textColor="@color/text_light"
android:layout_marginBottom="24dp"/>
<RadioGroup
android:id="@+id/rgTransactionType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="20dp">
<RadioButton
android:id="@+id/rbIncome"
android:layout_width="0dp"
android:layout_height="wrap_content"
💰
android:layout_weight="1"
android:text=" Income"
android:textSize="15sp"
android:buttonTint="@color/primary_blue"
android:checked="true"
android:padding="8dp"/>
<RadioButton
android:id="@+id/rbExpense"
android:layout_width="0dp"
android:layout_height="wrap_content"
💸
android:layout_weight="1"
android:text=" Expense"
android:textSize="15sp"
android:buttonTint="@color/primary_blue"
android:padding="8dp"/>
</RadioGroup>
<EditText
android:id="@+id/etDate"
android:layout_width="match_parent"
android:layout_height="50dp"
android:focusable="false"
📅
android:clickable="true"
android:hint=" Select date"
android:padding="12dp"
android:background="@color/cream"
android:textColor="@color/text_dark"
android:inputType="none"
android:drawableEnd="@android:drawable/ic_menu_my_calendar"
android:layout_marginBottom="20dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="20dp">
<Spinner
android:id="@+id/spinnerCategory"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:background="@color/cream"
android:padding="12dp"/>
<Button
android:id="@+id/btnManageCategories"
android:layout_width="50dp"
android:layout_height="50dp"
android:text="+"
android:textSize="24sp"
android:textColor="@color/white"
android:backgroundTint="@color/light_blue"
android:layout_marginStart="8dp"/>
</LinearLayout>
<EditText
android:id="@+id/etAmount"
android:layout_width="match_parent"
💵
android:layout_height="50dp"
android:hint=" Enter amount"
android:padding="12dp"
android:background="@color/cream"
android:inputType="numberDecimal"
android:textColor="@color/text_dark"
android:layout_marginBottom="20dp"/>
<EditText
android:id="@+id/etNote"
android:layout_width="match_parent"
📝
android:layout_height="100dp"
android:hint=" Add a note..."
android:padding="12dp"
android:background="@color/cream"
android:gravity="top|start"
android:inputType="textMultiLine"
android:textColor="@color/text_dark"
android:layout_marginBottom="24dp"/>
💾
android:layout_height="56dp"
android:text=" Save Transaction"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
android:backgroundTint="@color/primary_blue"
android:elevation="2dp"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
activity_category_summary.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/cream"
android:padding="20dp">
<Button
android:id="@+id/btnBackArrow"
android:layout_width="40dp"
android:layout_height="40dp"
android:text="←"
android:textSize="24sp"
android:textColor="@color/primary_blue"
android:background="@android:color/transparent"
android:padding="0dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Category Summary"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_marginStart="8dp"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="View totals by category"
android:textSize="14sp"
android:textColor="@color/text_light"
android:layout_marginBottom="24dp"/>
<RadioGroup
android:id="@+id/rgType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="24dp">
<RadioButton
android:id="@+id/rbIn"
android:layout_width="0dp"
android:layout_height="wrap_content"
💰
android:layout_weight="1"
android:text=" Income"
android:textSize="15sp"
android:buttonTint="@color/primary_blue"
android:checked="true"
android:padding="8dp"/>
<RadioButton
android:id="@+id/rbOut"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
💸
android:text=" Expense"
android:textSize="15sp"
android:buttonTint="@color/primary_blue"
android:padding="8dp"/>
</RadioGroup>
</LinearLayout>
</LinearLayout>
activity_export_pdf.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/cream"
android:padding="20dp"
android:gravity="center">
<Button
android:id="@+id/btnBackArrow"
android:layout_width="40dp"
android:layout_height="40dp"
android:text="←"
android:textSize="24sp"
android:textColor="@color/primary_blue"
android:background="@android:color/transparent"
android:padding="0dp"/>
</LinearLayout>
📄
android:layout_height="wrap_content"
android:text=" "
android:textSize="80sp"
android:layout_marginBottom="24dp"/>
<Button
android:id="@+id/btnExportPdf"
android:layout_width="match_parent"
📥
android:layout_height="60dp"
android:text=" Export Now"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold"
android:backgroundTint="@color/primary_blue"
android:elevation="2dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="The PDF will be saved to your device"
android:textSize="12sp"
android:textColor="@color/text_light"
android:layout_gravity="center"
android:layout_marginTop="16dp"/>
</LinearLayout>
</LinearLayout>
activity_graph.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/cream"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<Button
android:id="@+id/btnBackArrow"
android:layout_width="40dp"
android:layout_height="40dp"
android:text="←"
android:textSize="24sp"
android:textColor="@color/primary_blue"
android:background="@android:color/transparent"
android:padding="0dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Financial Graphs"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_marginStart="8dp"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Visualize your financial data"
android:textSize="14sp"
android:textColor="@color/text_light"
android:layout_marginBottom="24dp"/>
<TextView
android:layout_width="wrap_content"
📊
android:layout_height="wrap_content"
android:text=" Income vs Expense"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_marginBottom="24dp"/>
<View
android:id="@+id/barIncome"
android:layout_width="60dp"
android:layout_height="200dp"
android:background="#27AE60"
android:layout_marginBottom="8dp"/>
<TextView
android:layout_width="wrap_content"
💰
android:layout_height="wrap_content"
android:text=" Income"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/text_dark"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/tvIncomeAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rp 0"
android:textSize="12sp"
android:textColor="@color/text_light"/>
</LinearLayout>
<View
android:id="@+id/barExpense"
android:layout_width="60dp"
android:layout_height="200dp"
android:background="#E74C3C"
android:layout_marginBottom="8dp"/>
<TextView
android:layout_width="wrap_content"
💸
android:layout_height="wrap_content"
android:text=" Expense"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/text_dark"
android:layout_marginBottom="4dp"/>
<TextView
android:id="@+id/tvExpenseAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rp 0"
android:textSize="12sp"
android:textColor="@color/text_light"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
📈
android:layout_height="wrap_content"
android:text=" Expense by Category"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_marginBottom="16dp"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
activity_home.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/cream"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="FinanceMate"
android:textSize="32sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Your Financial Overview"
android:textSize="14sp"
android:textColor="@color/text_light"/>
</LinearLayout>
🚪
android:layout_height="40dp"
android:text=" Logout"
android:textColor="@color/white"
android:textSize="14sp"
android:textStyle="bold"
android:backgroundTint="#E74C3C"
android:paddingHorizontal="16dp"
android:elevation="2dp"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Financial Summary"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_marginBottom="16dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
💰
android:layout_weight="1"
android:text=" Income"
android:textSize="16sp"
android:textColor="@color/text_dark"/>
<TextView
android:id="@+id/tvIncome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rp 0"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="#27AE60"/>
</LinearLayout>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
💸
android:layout_weight="1"
android:text=" Expense"
android:textSize="16sp"
android:textColor="@color/text_dark"/>
<TextView
android:id="@+id/tvExpense"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rp 0"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="#E74C3C"/>
</LinearLayout>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
📊
android:layout_weight="1"
android:text=" Balance"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@color/text_dark"/>
<TextView
android:id="@+id/tvBalance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Rp 0"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"/>
</LinearLayout>
</LinearLayout>
➕
android:layout_height="56dp"
android:text=" Add Transaction"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
android:backgroundTint="@color/primary_blue"
android:elevation="2dp"
android:layout_marginBottom="12dp"/>
📋
android:layout_height="56dp"
android:text=" View All Transactions"
android:textColor="@color/primary_blue"
android:textSize="16sp"
android:textStyle="bold"
android:backgroundTint="@color/yellow"
android:elevation="2dp"
android:layout_marginBottom="12dp"/>
📊
android:layout_height="56dp"
android:text=" Category Summary"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
android:backgroundTint="@color/light_blue"
android:elevation="2dp"
android:layout_marginBottom="12dp"/>
📈
android:layout_height="56dp"
android:text=" View Graphs"
android:textColor="@color/primary_blue"
android:textSize="16sp"
android:textStyle="bold"
android:backgroundTint="@color/yellow"
android:elevation="2dp"
android:layout_marginBottom="12dp"/>
📄
android:layout_height="56dp"
android:text=" Export to PDF"
android:textColor="@color/text_dark"
android:textSize="16sp"
android:textStyle="bold"
android:backgroundTint="@color/white"
android:elevation="2dp"/>
</LinearLayout>
</ScrollView>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/cream">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="40dp"
android:text="Manage your money wisely"
android:textColor="@color/text_light"
android:textSize="14sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:text="Welcome Back!"
android:textColor="@color/primary_blue"
android:textSize="24sp"
android:textStyle="bold"/>
<!-- Username Input -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="Username"
android:textColor="@color/text_dark"
android:textStyle="bold"/>
<EditText
android:id="@+id/etUsername"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginBottom="16dp"
android:background="@color/cream"
android:hint="Enter your username"
android:padding="12dp"
android:textColor="@color/text_dark"/>
<EditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginBottom="24dp"
android:background="@color/cream"
android:hint="Enter your password"
android:inputType="textPassword"
android:padding="12dp"
android:textColor="@color/text_dark"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Don't have an account? "
android:textColor="@color/text_light"/>
<Button
android:id="@+id/btnGoToSignup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:minWidth="0dp"
android:minHeight="0dp"
android:padding="0dp"
android:text="Sign Up"
android:textColor="@color/light_blue"
android:textStyle="bold"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
activity_manages_categories.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/cream"
android:padding="20dp">
<Button
android:id="@+id/btnBackArrow"
android:layout_width="40dp"
android:layout_height="40dp"
android:text="←"
android:textSize="24sp"
android:textColor="@color/primary_blue"
android:background="@android:color/transparent"
android:padding="0dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Manage Categories"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_marginStart="8dp"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add or remove transaction categories"
android:textSize="14sp"
android:textColor="@color/text_light"
android:layout_marginBottom="24dp"/>
<RadioGroup
android:id="@+id/rgCategoryType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="20dp">
<RadioButton
android:id="@+id/rbIncomeCategory"
android:layout_width="0dp"
android:layout_height="wrap_content"
💰
android:layout_weight="1"
android:text=" Income"
android:textSize="15sp"
android:buttonTint="@color/primary_blue"
android:checked="true"
android:padding="8dp"/>
<RadioButton
android:id="@+id/rbExpenseCategory"
android:layout_width="0dp"
android:layout_height="wrap_content"
💸
android:layout_weight="1"
android:text=" Expense"
android:textSize="15sp"
android:buttonTint="@color/primary_blue"
android:padding="8dp"/>
</RadioGroup>
➕
android:layout_height="56dp"
android:text=" Add New Category"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
android:backgroundTint="@color/light_blue"
android:elevation="2dp"
android:layout_marginBottom="20dp"/>
📌
android:layout_height="wrap_content"
android:text=" Long press to delete a category"
android:textSize="13sp"
android:textStyle="italic"
android:textColor="@color/text_light"
android:layout_marginBottom="12dp"/>
</LinearLayout>
</LinearLayout>
activity_view_transaction.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/cream"
android:padding="20dp">
<Button
android:id="@+id/btnBackArrow"
android:layout_width="40dp"
android:layout_height="40dp"
android:text="←"
android:textSize="24sp"
android:textColor="@color/primary_blue"
android:background="@android:color/transparent"
android:padding="0dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="All Transactions"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_marginStart="8dp"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="View and filter your transactions"
android:textSize="14sp"
android:textColor="@color/text_light"
android:layout_marginBottom="24dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Filter by Period"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/text_dark"
android:layout_marginBottom="8dp"/>
<Spinner
android:id="@+id/spinnerFilter"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/cream"
android:padding="12dp"
android:layout_marginBottom="16dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Filter by Category"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/text_dark"
android:layout_marginBottom="8dp"/>
<Spinner
android:id="@+id/spinnerCategory"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/cream"
android:padding="12dp"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Transactions"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/text_dark"
android:layout_marginBottom="12dp"/>
<ListView
android:id="@+id/listTransactions"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@color/cream"
android:dividerHeight="2dp"/>
</LinearLayout>
</LinearLayout>
signup_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/cream">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start your financial journey"
android:textSize="14sp"
android:textColor="@color/text_light"
android:layout_gravity="center"
android:layout_marginBottom="40dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Create Account"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_marginBottom="24dp"/>
<EditText
android:id="@+id/etUsername"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="Choose a username"
android:padding="12dp"
android:background="@color/cream"
android:textColor="@color/text_dark"
android:layout_marginBottom="16dp"/>
<EditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="Create a strong password"
android:padding="12dp"
android:background="@color/cream"
android:inputType="textPassword"
android:textColor="@color/text_dark"
android:layout_marginBottom="24dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Already have an account? "
android:textColor="@color/text_light"/>
<Button
android:id="@+id/btnBackToLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Login"
android:textColor="@color/primary_blue"
android:textStyle="bold"
android:background="@android:color/transparent"
android:minWidth="0dp"
android:minHeight="0dp"
android:padding="0dp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
Package values
[Link]
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="primary_blue">#3674B5</color>
<color name="light_blue">#578FCA</color>
<color name="cream">#F5F0CD</color>
<color name="yellow">#FADA7A</color>
<color name="text_dark">#2C3E50</color>
<color name="text_light">#7F8C8D</color>
<color name="green">#27AE60</color>
<color name="red">#E74C3C</color>
<color name="orange">#F39C12</color>
<color name="purple">#8E44AD</color>
</resources>
ic_launcher_background.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#3674B5</color>
</resources>
[Link]
<resources>
<string name="app_name">Finance Mate</string>
</resources>
[Link]
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Base application theme -->
<style name="[Link]"
parent="[Link]">
<!-- Primary brand color -->
<item name="colorPrimary">@color/primary_blue</item>
<item name="colorPrimaryDark">@color/primary_blue</item>
<item name="colorAccent">@color/light_blue</item>
Gradle Scripts
[Link] (Finance Mate)
// Top-level build file where you can add configuration options common to all
sub-projects/modules.
plugins {
alias([Link]) apply false
alias([Link]) apply false
alias([Link]) apply false
}
[Link] (:app)
plugins {
alias([Link])
alias([Link])
alias([Link])
}
android {
namespace = "[Link]"
compileSdk = 36
defaultConfig {
applicationId = "[Link]"
minSdk = 23
targetSdk = 36
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "[Link]"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("[Link]"),
"[Link]"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
compose = true
}
}
dependencies {
implementation([Link])
implementation([Link])
implementation([Link])
implementation(platform([Link]))
implementation([Link])
implementation([Link])
implementation([Link])
implementation([Link].material3)
implementation("[Link]:appcompat:1.6.1")
implementation("[Link]:MPAndroidChart:v3.1.0")
testImplementation([Link])
androidTestImplementation([Link])
androidTestImplementation([Link])
androidTestImplementation(platform([Link]))
androidTestImplementation([Link].junit4)
debugImplementation([Link])
debugImplementation([Link])
}
[libraries]
androidx-core-ktx = { group = "[Link]", name = "core-ktx", [Link] =
"coreKtx" }
junit = { group = "junit", name = "junit", [Link] = "junit" }
androidx-junit = { group = "[Link]", name = "junit", [Link] =
"junitVersion" }
androidx-espresso-core = { group = "[Link]", name =
"espresso-core", [Link] = "espressoCore" }
androidx-lifecycle-runtime-ktx = { group = "[Link]", name =
"lifecycle-runtime-ktx", [Link] = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "[Link]", name =
"activity-compose", [Link] = "activityCompose" }
androidx-compose-bom = { group = "[Link]", name = "compose-bom",
[Link] = "composeBom" }
androidx-compose-ui = { group = "[Link]", name = "ui" }
androidx-compose-ui-graphics = { group = "[Link]", name =
"ui-graphics" }
androidx-compose-ui-tooling = { group = "[Link]", name =
"ui-tooling" }
androidx-compose-ui-tooling-preview = { group = "[Link]", name =
"ui-tooling-preview" }
androidx-compose-ui-test-manifest = { group = "[Link]", name =
"ui-test-manifest" }
androidx-compose-ui-test-junit4 = { group = "[Link]", name =
"ui-test-junit4" }
androidx-compose-material3 = { group = "[Link].material3", name =
"material3" }
[plugins]
android-application = { id = "[Link]", [Link] = "agp" }
kotlin-android = { id = "[Link]", [Link] = "kotlin"
}
kotlin-compose = { id = "[Link]", [Link] =
"kotlin" }
[Link]
pluginManagement {
repositories {
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
}
}
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
[Link](RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url = uri("[Link]
}
}
}