0% found this document useful (0 votes)
3 views75 pages

Appendix 2 - Full Source Code

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views75 pages

Appendix 2 - Full Source Code

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Appendix:

Criterion C - Code of Application

Package Manifests
[Link]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="[Link]
xmlns:tools="[Link]

<!-- Permission for PDF export (legacy support) -->


<uses-permission
android:name="[Link].WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />

<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]">

<!-- Login / Launcher Activity -->


<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name">
<intent-filter>
<action android:name="[Link]" />
<category android:name="[Link]" />
</intent-filter>
</activity>

<!-- Signup -->


<activity
android:name=".SignupActivity"
android:exported="false" />

<!-- Home / Dashboard -->


<activity
android:name=".HomeActivity"
android:exported="false" />
<!-- Add Transaction -->
<activity
android:name=".AddTransactionActivity"
android:exported="false" />

<!-- View Transactions -->


<activity
android:name=".ViewTransactionsActivity"
android:exported="false" />

<!-- Manage Categories -->


<activity
android:name=".ManageCategoriesActivity"
android:exported="false" />

<!-- Add Category -->


<activity
android:name=".AddCategoryActivity"
android:exported="false" />

<!-- Category Summary -->


<activity
android:name=".CategorySummaryActivity"
android:exported="false" />

<!-- Graph Activity -->


<activity
android:name=".GraphActivity"
android:exported="false" />

<!-- Export PDF -->


<activity
android:name=".ExportPdfActivity"
android:exported="false" />

</application>

</manifest>
Package kotlin+java​
[Link]
package [Link]

import [Link]
import [Link].*
import [Link]

class AddCategoryActivity : AppCompatActivity() {

private lateinit var db: DatabaseHelper


private var userId: Int = -1

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_add_category)

// Enable back button in action bar


supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "Add Category"

db = DatabaseHelper(this)

// Get userId from intent


userId = [Link]("USER_ID", -1)
if (userId == -1) {
[Link](this, "Error: User not found",
Toast.LENGTH_SHORT).show()
finish()
return
}

val etName = findViewById<EditText>([Link])


val rgType = findViewById<RadioGroup>([Link])
val btnSave = findViewById<Button>([Link])
val btnBack = findViewById<Button>([Link])

// Back arrow button


findViewById<Button>([Link]).setOnClickListener {
finish()
}

// ================= SAVE CATEGORY =================


[Link] {

val name = [Link]().trim()

if ([Link]()) {
[Link](this, "Category name cannot be empty",
Toast.LENGTH_SHORT).show()
return@setOnClickListener
}

val type = when ([Link]) {


[Link] -> "IN"
[Link] -> "OUT"
else -> null
}

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()
}
}

override fun onSupportNavigateUp(): Boolean {


finish()
return true
}
}

[Link]

package [Link]

import [Link]
import [Link]
import [Link]
import [Link].*
import [Link]
import [Link]
import [Link].*
class AddTransactionActivity : AppCompatActivity() {

private lateinit var db: DatabaseHelper


private var userId: Int = -1
private lateinit var etDate: EditText
private lateinit var spinnerCategory: Spinner
private lateinit var rgType: RadioGroup
private lateinit var rbIncome: RadioButton
private lateinit var rbExpense: RadioButton
private lateinit var etAmount: EditText
private lateinit var etNote: EditText
private lateinit var btnSave: Button
private lateinit var btnManageCategories: Button

private var selectedDate = ""


private val calendar = [Link]()

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_add_transaction)

// Enable back button


supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "Add Transaction"
db = DatabaseHelper(this)

// Get userId from intent


userId = [Link]("USER_ID", -1)
if (userId == -1) {
[Link](this, "Error: User not found",
Toast.LENGTH_SHORT).show()
finish()
return
}
// Initialize views
etDate = findViewById([Link])
spinnerCategory = findViewById([Link])
rgType = findViewById([Link])
rbIncome = findViewById([Link])
rbExpense = findViewById([Link])
etAmount = findViewById([Link])
etNote = findViewById([Link])
btnSave = findViewById([Link])
btnManageCategories = findViewById([Link])

findViewById<Button>([Link]).setOnClickListener {
finish()
}
// Set default date to today
updateDateDisplay()
[Link] {
showDatePicker()
}

// Load categories when type changes


[Link] { _, checkedId ->
val type = if (checkedId == [Link]) "IN" else "OUT"
loadCategories(type)
}

// Load income categories by default


loadCategories("IN")

// Manage categories button


[Link] {
val intent = Intent(this, ManageCategoriesActivity::[Link])
[Link]("USER_ID", userId)
startActivity(intent)
}

// Save button
[Link] {
saveTransaction()
}
}

override fun onResume() {


[Link]()
// Reload categories when returning from ManageCategoriesActivity
val type = if ([Link]) "IN" else "OUT"
loadCategories(type)
}

private fun loadCategories(type: String) {


val categories = [Link](userId, type)

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)
}
}

private fun showDatePicker() {


DatePickerDialog(
this,
{ _, year, month, day ->
[Link](year, month, day)
updateDateDisplay()
},
[Link]([Link]),
[Link]([Link]),
[Link](Calendar.DAY_OF_MONTH)
).show()
}

private fun updateDateDisplay() {


val dateFormat = SimpleDateFormat("yyyy-MM-dd", [Link]())
selectedDate = [Link]([Link])
[Link](selectedDate)
}

private fun saveTransaction() {


val category = [Link]?.toString()
val amountStr = [Link]().trim()
val note = [Link]().trim()

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
}

val amount = [Link]()


if (amount == null || amount <= 0) {
[Link](this, "Please enter valid amount",
Toast.LENGTH_SHORT).show()
return
}
val type = if ([Link]) "IN" else "OUT"

[Link](
userId = userId,
date = selectedDate,
category = category,
type = type,
amount = amount,
note = note
)

[Link](this, "Transaction saved!", Toast.LENGTH_SHORT).show()

[Link]("")
[Link]("")

finish()
}

override fun onSupportNavigateUp(): Boolean {


finish()
return true
}
}

[Link]
package [Link]

data class Category(


val name: String,
val total: Double
)

data class CategorySummary(


val categoryName: String,
val total: Double
)

[Link]
package [Link]

import [Link]
import [Link].*
import [Link]
import [Link]
import [Link].*

class CategorySummaryActivity : AppCompatActivity() {


private lateinit var db: DatabaseHelper
private var userId: Int = -1

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_category_summary)

// Enable back button


supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "Category Summary"

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
}

val listView = findViewById<ListView>([Link])


val radioGroup = findViewById<RadioGroup>([Link])

// Back button
findViewById<Button>([Link]).setOnClickListener {
finish()
}

// Load income summary by default


[Link]([Link])
loadSummary("IN", listView)

// Switch between Income and Expense


[Link] { _, checkedId ->
val type = if (checkedId == [Link]) "IN" else "OUT"
loadSummary(type, listView)
}
}

/**
* Loads category totals and calculates percentage breakdown
*/
private fun loadSummary(type: String, listView: ListView) {

val data = [Link](userId, type)

val formatter = [Link](Locale("id", "ID"))


if ([Link]()) {
[Link] = null
[Link](this, "No data available", Toast.LENGTH_SHORT).show()
return
}

// Calculate overall total


val overallTotal = [Link] { [Link] }

//Create display list with percentage calculation


val displayList = [Link] { item ->

val percentage = if (overallTotal > 0) {


([Link] / overallTotal) * 100
} else {
0.0
}
val formattedPercentage = [Link]("%.1f", percentage)
"${[Link]} : ${[Link]([Link])}
($formattedPercentage%)"
}

//Display results in scrollable ListView


[Link] = ArrayAdapter(
this,
[Link].simple_list_item_1,
displayList
)
}

override fun onSupportNavigateUp(): Boolean {


finish()
return true
}
}

[Link]
package [Link]

import [Link]
import [Link]
import [Link]
import [Link]

class DatabaseHelper(context: Context) :


SQLiteOpenHelper(context, "[Link]", null, 3) {

override fun onCreate(db: SQLiteDatabase) {


// Users table
[Link](
"""
CREATE TABLE users(
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE,
password TEXT
)
"""
)

// Transactions table with userId


[Link](
"""
CREATE TABLE transactions(
id INTEGER PRIMARY KEY AUTOINCREMENT,
userId INTEGER,
date TEXT,
category TEXT,
type TEXT,
amount REAL,
note TEXT,
FOREIGN KEY(userId) REFERENCES users(id)
)
"""
)

// Categories table with userId


[Link](
"""
CREATE TABLE categories(
id INTEGER PRIMARY KEY AUTOINCREMENT,
userId INTEGER,
name TEXT,
type TEXT,
FOREIGN KEY(userId) REFERENCES users(id)
)
"""
)
}

override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int)


{
// Simple upgrade - just recreate tables
// In production, you'd want to preserve user data
if (oldVersion < 3) {
try {
[Link]("DROP TABLE IF EXISTS transactions")
[Link]("DROP TABLE IF EXISTS categories")
[Link]("DROP TABLE IF EXISTS users")
onCreate(db)
} catch (e: Exception) {
[Link]()
}
}
}

// ========== USER METHODS ==========

fun registerUser(username: String, password: String): Boolean {


return try {
val cv = ContentValues()
[Link]("username", username)
[Link]("password", password)
[Link]("users", null, cv) != -1L
} catch (e: Exception) {
false
}
}

fun loginUser(username: String, password: String): Int {


val cursor = [Link](
"SELECT id FROM users WHERE username=? AND password=?",
arrayOf(username, password)
)
var userId = -1
if ([Link]()) {
userId = [Link](0)
}
[Link]()
return userId
}

fun getUserHash(username: String): String? {


val cursor = [Link](
"SELECT password FROM users WHERE username=?",
arrayOf(username)
)
var hash: String? = null
if ([Link]()) {
hash = [Link](0)
}
[Link]()
return hash
}

fun getUserId(username: String): Int? {


val cursor = [Link](
"SELECT id FROM users WHERE username=?",
arrayOf(username)
)
var id: Int? = null
if ([Link]()) {
id = [Link](0)
}
[Link]()
return id
}

fun insertUser(username: String, passwordHash: String): Boolean {


return try {
val cv = ContentValues()
[Link]("username", username)
[Link]("password", passwordHash)
val result = [Link]("users", null, cv)

// If user created successfully, get userId and insert default


categories
if (result != -1L) {
val userId = [Link]()
insertDefaultCategories(userId)
true
} else {
false
}
} catch (e: Exception) {
false
}
}

// ========== TRANSACTION METHODS ==========

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)
}

fun getAllTransactions(userId: Int): List<TransactionExport> {


val list = mutableListOf<TransactionExport>()
try {
val cursor = [Link](
"SELECT date, category, type, amount, note FROM transactions
WHERE userId=? ORDER BY date DESC",
arrayOf([Link]())
)
while ([Link]()) {
[Link](
TransactionExport(
[Link](0),
[Link](1),
[Link](2),
[Link](3),
[Link](4)
)
)
}
[Link]()
} catch (e: Exception) {
[Link]()
}
return list
}

fun getTransactionsByCategory(userId: Int, category: String):


List<TransactionExport> {
val list = mutableListOf<TransactionExport>()
val cursor = [Link](
"SELECT date, category, type, amount, note FROM transactions WHERE
userId=? AND category=? ORDER BY date DESC",
arrayOf([Link](), category)
)
while ([Link]()) {
[Link](
TransactionExport(
[Link](0),
[Link](1),
[Link](2),
[Link](3),
[Link](4)
)
)
}
[Link]()
return list
}

fun getTotalByCategory(userId: Int, type: String): List<CategorySummary> {


val list = mutableListOf<CategorySummary>()
val cursor = [Link](
"""
SELECT category, SUM(amount)
FROM transactions
WHERE userId=? AND type=?
GROUP BY category
""",
arrayOf([Link](), type)
)
while ([Link]()) {
[Link](CategorySummary([Link](0), [Link](1)))
}
[Link]()
return list
}

fun getTotalIncome(userId: Int): Double {


val cursor = [Link](
"SELECT SUM(amount) FROM transactions WHERE userId=? AND type='IN'",
arrayOf([Link]())
)
var total = 0.0
if ([Link]()) {
total = [Link](0)
}
[Link]()
return total
}

fun getTotalExpense(userId: Int): Double {


val cursor = [Link](
"SELECT SUM(amount) FROM transactions WHERE userId=? AND
type='OUT'",
arrayOf([Link]())
)
var total = 0.0
if ([Link]()) {
total = [Link](0)
}
[Link]()
return total
}

// ========== CATEGORY METHODS ==========


fun getCategoriesByType(userId: Int, type: String): List<String> {
val list = mutableListOf<String>()
val cursor = [Link](
"SELECT name FROM categories WHERE userId=? AND type=? ORDER BY
name",
arrayOf([Link](), type)
)
while ([Link]()) {
[Link]([Link](0))
}
[Link]()
return list
}

fun insertCategory(userId: Int, name: String, type: String) {


val cv = ContentValues()
[Link]("userId", userId)
[Link]("name", name)
[Link]("type", type)
[Link]("categories", null, cv)
}

fun deleteCategory(userId: Int, name: String, type: String) {


[Link](
"categories",
"userId=? AND name=? AND type=?",
arrayOf([Link](), name, type)
)
}

fun insertDefaultCategories(userId: Int) {


insertCategory(userId, "Purchase", "IN")
insertCategory(userId, "Bonus", "IN")
insertCategory(userId, "Fuel", "OUT")
insertCategory(userId, "Materials", "OUT")
}
}

[Link]
package [Link]

import [Link]
import [Link]
import [Link]
import [Link]

class ExportPdfActivity : AppCompatActivity() {


private lateinit var db: DatabaseHelper
private var userId: Int = -1

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_export_pdf)

// Enable back button


supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "Export PDF"

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
}

val file = [Link](this, transactions)


[Link](this, "PDF exported to: ${[Link]}",
Toast.LENGTH_LONG).show()
}
}

override fun onSupportNavigateUp(): Boolean {


finish()
return true
}
}
[Link]
package [Link]

import [Link]
import [Link]
import [Link]
import [Link].*
import [Link]
import [Link]

class GraphActivity : AppCompatActivity() {

private lateinit var db: DatabaseHelper


private var userId: Int = -1

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_graph)

// Enable back button


supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "Financial Graphs"

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()
}

private fun loadGraphs() {


val transactions = [Link](userId)

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>()

[Link] { transaction ->


if ([Link] == "IN") {
totalIncome += [Link]
} else {
totalExpense += [Link]
val currentAmount = expenseByCategory[[Link]] ?:
0.0
expenseByCategory[[Link]] = currentAmount +
[Link]
}
}

// Display simple bar representation


displayIncomeExpenseBar(totalIncome, totalExpense)

// Display category breakdown


displayCategoryBreakdown(expenseByCategory, totalExpense)
}

private fun displayIncomeExpenseBar(income: Double, expense: Double) {


val barIncome = findViewById<View>([Link])
val barExpense = findViewById<View>([Link])
val tvIncomeAmount = findViewById<TextView>([Link])
val tvExpenseAmount = findViewById<TextView>([Link])

// Calculate max for scaling


val max = maxOf(income, expense)

if (max > 0) {
val incomeHeight = ((income / max) * 300).toInt()
val expenseHeight = ((expense / max) * 300).toInt()

val incomeParams = [Link]


[Link] = incomeHeight
[Link] = incomeParams

val expenseParams = [Link]


[Link] = expenseHeight
[Link] = expenseParams

[Link]()
[Link]()
}
val formatter =
[Link]([Link]("id", "ID"))
[Link] = [Link](income)
[Link] = [Link](expense)
}

private fun displayCategoryBreakdown(categoryMap: Map<String, Double>,


total: Double) {
val container =
findViewById<LinearLayout>([Link])
[Link]()

if (total == 0.0) {
val emptyText = TextView(this)
[Link] = getString([Link])
[Link]([Link])
[Link](emptyText)
return
}

// Sort by amount descending


val sortedCategories = [Link] { [Link]
}
val formatter =
[Link]([Link]("id", "ID"))

[Link] { (category, amount) ->


val percentage = (amount / total * 100)

// Create category row


val rowLayout = LinearLayout(this).apply {
orientation = [Link]
setPadding(0, 16, 0, 16)
}

// Category name and amount


val infoLayout = LinearLayout(this).apply {
orientation = [Link]
}

val nameText = TextView(this).apply {


text = category
textSize = 16f
setTextColor([Link]("#2C3E50"))
layoutParams = [Link](
0,
[Link].WRAP_CONTENT,
1f
)
}

val amountText = TextView(this).apply {


text = [Link]([Link](), "%s
(%.1f%%)",
[Link](amount), percentage)
textSize = 14f
setTextColor([Link]("#7F8C8D"))
}

[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)
}
}

private fun getColorForCategory(category: String): Int {


val colors = listOf(
[Link]("#3674B5"),
[Link]("#578FCA"),
[Link]("#E74C3C"),
[Link]("#F39C12"),
[Link]("#27AE60"),
[Link]("#8E44AD"),
[Link]("#E67E22")
)
return colors[[Link]().absoluteValue % [Link]]
}

override fun onSupportNavigateUp(): Boolean {


finish()
return true
}
}
[Link]
package [Link]

import [Link]
import [Link]
import [Link].*
import [Link]
import [Link]
import [Link].*

class HomeActivity : AppCompatActivity() {

private lateinit var db: DatabaseHelper


private var userId: Int = -1

private lateinit var tvIncome: TextView


private lateinit var tvExpense: TextView
private lateinit var tvBalance: TextView
private lateinit var btnAddTransaction: Button
private lateinit var btnViewTransactions: Button
private lateinit var btnCategorySummary: Button
private lateinit var btnViewGraphs: Button
private lateinit var btnExport: Button
private lateinit var btnLogout: Button

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_home)

db = DatabaseHelper(this)

// Get userId from intent


userId = [Link]("USER_ID", -1)
if (userId == -1) {
[Link](this, "Error: User not found",
Toast.LENGTH_SHORT).show()
finish()
return
}

// 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()
}
}

override fun onResume() {


[Link]()
loadSummary()
}

private fun loadSummary() {


val income = [Link](userId)
val expense = [Link](userId)
val balance = income - expense

val formatter = [Link](Locale("id", "ID"))

[Link] = "Income: ${[Link](income)}"


[Link] = "Expense: ${[Link](expense)}"
[Link] = "Balance: ${[Link](balance)}"
}
}

[Link]
package [Link]

import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]

class MainActivity : AppCompatActivity() {

private lateinit var db: DatabaseHelper


private lateinit var etUsername: EditText
private lateinit var etPassword: EditText
private lateinit var btnLogin: Button
private lateinit var btnGoToSignup: Button

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)

try {
setContentView([Link].activity_main)

Log.d("MainActivity", "Layout set successfully")

// Bind UI elements FIRST


etUsername = findViewById([Link])
etPassword = findViewById([Link])
btnLogin = findViewById([Link])
btnGoToSignup = findViewById([Link])
Log.d("MainActivity", "UI elements bound successfully")

// Set listeners
[Link] { handleLogin() }
[Link] { navigateToSignup() }

// Initialize database LAST (this is the slow part)


db = DatabaseHelper(this)

Log.d("MainActivity", "Database initialized successfully")

} catch (e: Exception) {


Log.e("MainActivity", "Error in onCreate: ${[Link]}", e)
[Link](this, "Error: ${[Link]}",
Toast.LENGTH_LONG).show()
}
}

private fun handleLogin() {


try {
val username = [Link]().trim()
val password = [Link]()
// Validate input
if ([Link]() || [Link]()) {
[Link](this, "Please fill in all fields",
Toast.LENGTH_SHORT).show()
return
}
Log.d("MainActivity", "Attempting login for user: $username")
// Retrieve stored password hash
val storedHash = [Link](username)
if (storedHash == null) {
[Link](this, "Invalid username or password",
Toast.LENGTH_SHORT).show()
return
}
// Compare hashes
val inputHash = sha256(password)
if (inputHash == storedHash) {
[Link](this, "Login successful!",
Toast.LENGTH_SHORT).show()
val userId = [Link](username)
if (userId == null) {
[Link](this, "Error getting user ID",
Toast.LENGTH_SHORT).show()
return
}

Log.d("MainActivity", "Login successful for userId: $userId")


val intent = Intent(this, HomeActivity::[Link])
[Link]("USER_ID", userId)
[Link]("USERNAME", username)
startActivity(intent)
finish()
} else {
[Link](this, "Invalid username or password",
Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Log.e("MainActivity", "Error in handleLogin: ${[Link]}", e)
[Link](this, "Login error: ${[Link]}",
Toast.LENGTH_LONG).show()
}
}

private fun navigateToSignup() {


try {
startActivity(Intent(this, SignupActivity::[Link]))
} catch (e: Exception) {
Log.e("MainActivity", "Error navigating to signup: ${[Link]}", e)
[Link](this, "Error: ${[Link]}",
Toast.LENGTH_SHORT).show()
}
}

private fun sha256(input: String): String {


return MessageDigest
.getInstance("SHA-256")
.digest([Link]())
.joinToString("") { "%02x".format(it) }
}
}

[Link]
package [Link]

import [Link]
import [Link].*
import [Link]
import [Link]

class ManageCategoriesActivity : AppCompatActivity() {

private lateinit var db: DatabaseHelper


private var userId: Int = -1
private lateinit var rgType: RadioGroup
private lateinit var listView: ListView
private lateinit var btnAdd: Button
private var currentType = "IN"

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_manage_categories)

// Enable back button


supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "Manage Categories"

db = DatabaseHelper(this)

// Get userId from intent


userId = [Link]("USER_ID", -1)
if (userId == -1) {
[Link](this, "Error: User not found",
Toast.LENGTH_SHORT).show()
finish()
return
}
rgType = findViewById([Link])
listView = findViewById([Link])
btnAdd = findViewById([Link])

// Back button
findViewById<Button>([Link]).setOnClickListener {
finish()
}

// Load income categories by default


loadCategories()

// Type selection listener


[Link] { _, checkedId ->
currentType = if (checkedId == [Link]) "IN" else
"OUT"
loadCategories()
}

// Add category button


[Link] {
showAddCategoryDialog()
}

// Delete category on long press


[Link] { _, _, position, _ ->
val category = [Link](position) as String
showDeleteConfirmation(category)
true
}
}

private fun loadCategories() {


val categories = [Link](userId, currentType)
[Link] = ArrayAdapter(
this,
[Link].simple_list_item_1,
categories
)
}

private fun showAddCategoryDialog() {


val input = EditText(this)
[Link] = "Category name"

[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()
}

private fun showDeleteConfirmation(category: String) {


[Link](this)
.setTitle("Delete Category")
.setMessage("Delete '$category'?")
.setPositiveButton("Delete") { _, _ ->
[Link](userId, category, currentType)
loadCategories()
[Link](this, "Category deleted",
Toast.LENGTH_SHORT).show()
}
.setNegativeButton("Cancel", null)
.show()
}

override fun onSupportNavigateUp(): Boolean {


finish()
return true
}
}

[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 {

fun export(context: Context, data: List<TransactionExport>): File {


val pdf = PdfDocument()
val paint = Paint()
val formatter = [Link](Locale("id", "ID"))

[Link] = 12f

var pageNumber = 1
var y = 40

var page = [Link](


[Link](595, 842, pageNumber).create()
)

val canvas = [Link]

[Link] = 18f
[Link]("FinanceMate - Transaction Report", 40f, [Link](),
paint)
y += 30

[Link] = 12f

[Link]("Date", 40f, [Link](), paint)


[Link]("Category", 120f, [Link](), paint)
[Link]("Type", 240f, [Link](), paint)
[Link]("Amount", 320f, [Link](), paint)
[Link]("Note", 420f, [Link](), paint)
y += 20
for (item in data) {

if (y > 800) {
[Link](page)
pageNumber++
page = [Link](
[Link](595, 842, pageNumber).create()
)
y = 40
}

val typeText = if ([Link] == "IN") "Income" else "Expense"

[Link]([Link], 40f, [Link](), paint)


[Link]([Link], 120f, [Link](), paint)
[Link](typeText, 240f, [Link](), paint)
[Link]([Link]([Link]), 320f, [Link](),
paint)
[Link]([Link], 420f, [Link](), paint)

y += 20
}

[Link](page)

// Save to app's external files directory


val file = File([Link](null), "[Link]")
[Link]([Link]())
[Link]()

return file
}

// Alternative method that saves to MediaStore (for user's Documents folder)


fun exportToDocuments(
context: Context,
fileName: String,
data: List<TransactionExport>
): Uri? {
val pdf = PdfDocument()
val paint = Paint()
val formatter = [Link](Locale("id", "ID"))

[Link] = 12f

var pageNumber = 1
var y = 40
var page = [Link](
[Link](595, 842, pageNumber).create()
)

val canvas = [Link]

[Link] = 18f
[Link]("FinanceMate - Transaction Report", 40f, [Link](),
paint)
y += 30

[Link] = 12f

for (item in data) {


if (y > 800) {
[Link](page)
pageNumber++
page = [Link](
[Link](595, 842, pageNumber).create()
)
y = 40
}

val typeText = if ([Link] == "IN") "Income" else "Expense"


[Link](
"${[Link]} | ${[Link]} | $typeText |
${[Link]([Link])}",
40f,
[Link](),
paint
)
y += 20
}

[Link](page)

val uri = savePdfToMediaStore(context, fileName, pdf)


[Link]()
return uri
}

private fun savePdfToMediaStore(context: Context, fileName: String, pdf:


PdfDocument): Uri? {
val resolver = [Link]

val contentValues = ContentValues().apply {


put([Link].DISPLAY_NAME, "$[Link]")
put([Link].MIME_TYPE, "application/pdf")
if ([Link].SDK_INT >= Build.VERSION_CODES.Q) {
put([Link].RELATIVE_PATH,
"Documents/FinanceMate")
}
}

val uri = [Link](


[Link]("external"),
contentValues
) ?: return null

val output: OutputStream? = [Link](uri)


[Link](output)
output?.close()

return uri
}
}

[Link]
package [Link]

import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]

class SignupActivity : AppCompatActivity() {

private lateinit var db: DatabaseHelper

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].signup_activity)

// Enable back button


supportActionBar?.setDisplayHomeAsUpEnabled(true)

db = DatabaseHelper(this)
val etUsername = findViewById<EditText>([Link])
val etPassword = findViewById<EditText>([Link])
val btnSignup = findViewById<Button>([Link])
val btnBackToLogin = findViewById<Button>([Link])

[Link] {

val username = [Link]().trim()


val password = [Link]()
if ([Link]() || [Link]()) {
[Link](this, "Fill all fields",
Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
// HASH PASSWORD
val passwordHash = sha256(password)
val success = [Link](username, passwordHash)

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()
}
}

private fun sha256(input: String): String {


return MessageDigest
.getInstance("SHA-256")
.digest([Link]())
.joinToString("") { "%02x".format(it) }
}

override fun onSupportNavigateUp(): Boolean {


finish()
return true
}
}

[Link]
package [Link]

data class TransactionExport(


val date: String,
val category: String,
val type: String,
val amount: Double,
val note: String
)

[Link]
package [Link]

import [Link]
import [Link].*
import [Link]
import [Link]
import [Link]
import [Link].*

class ViewTransactionsActivity : AppCompatActivity() {

private lateinit var db: DatabaseHelper


private var userId: Int = -1

private lateinit var spinnerFilter: Spinner


private lateinit var spinnerCategory: Spinner
private lateinit var listView: ListView
private lateinit var tvTotal: TextView

private var allTransactions = listOf<TransactionExport>()


private var allCategories = listOf<String>()
private var isInitialLoad = true

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_view_transactions)

supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "All Transactions"

db = DatabaseHelper(this)

userId = [Link]("USER_ID", -1)


if (userId == -1) {
[Link](this, "Error: User not found",
Toast.LENGTH_SHORT).show()
finish()
return
}

spinnerFilter = findViewById([Link])
spinnerCategory = findViewById([Link])
listView = findViewById([Link])
tvTotal = findViewById([Link])
findViewById<Button>([Link]).setOnClickListener {
finish()
}

allTransactions = [Link](userId)

val incomeCategories = [Link](userId, "IN")


val expenseCategories = [Link](userId, "OUT")
allCategories = (listOf("All Categories") + incomeCategories +
expenseCategories).distinct()

if ([Link]()) {
[Link](this, "No transactions yet. Add some first!",
Toast.LENGTH_LONG).show()

} else {
[Link](this, "Found ${[Link]} transactions",
Toast.LENGTH_SHORT).show()
}

val filterOptions = arrayOf("All", "Today", "This Week", "This Month",


"This Year")
val spinnerAdapter = ArrayAdapter(
this,
[Link].simple_spinner_item,
filterOptions
)

[Link]([Link].simple_spinner_dropdown
_item)
[Link] = spinnerAdapter

val categoryAdapter = ArrayAdapter(


this,
[Link].simple_spinner_item,
allCategories
)

[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()
}
}

override fun onNothingSelected(parent: AdapterView<*>) {}


}

[Link] = object :
[Link] {
override fun onItemSelected(parent: AdapterView<*>, view:
[Link]?, position: Int, id: Long) {
if (!isInitialLoad) {
applyFilters()
}
}

override fun onNothingSelected(parent: AdapterView<*>) {}


}

isInitialLoad = false
applyFilters()
}

private fun applyFilters() {


val timeFilter = [Link]()
val categoryFilter = [Link]()

var filtered = when (timeFilter) {


"Today" -> filterByToday()
"This Week" -> filterByWeek()
"This Month" -> filterByMonth()
"This Year" -> filterByYear()
else -> allTransactions
}

// Apply category filter


if (categoryFilter != "All Categories") {
filtered = [Link] { [Link] == categoryFilter }
}

displayTransactions(filtered)
}

private fun filterByToday(): List<TransactionExport> {


val today = SimpleDateFormat("yyyy-MM-dd",
[Link]()).format(Date())
return [Link] { [Link] == today }
}

private fun filterByWeek(): List<TransactionExport> {


val calendar = [Link]()
[Link](Calendar.DAY_OF_WEEK, [Link])
val weekStart = SimpleDateFormat("yyyy-MM-dd",
[Link]()).format([Link])

return [Link] { [Link] >= weekStart }


}

private fun filterByMonth(): List<TransactionExport> {


val calendar = [Link]()
val currentMonth = SimpleDateFormat("yyyy-MM",
[Link]()).format([Link])

return [Link] { [Link](currentMonth) }


}

private fun filterByYear(): List<TransactionExport> {


val calendar = [Link]()
val currentYear = SimpleDateFormat("yyyy",
[Link]()).format([Link])

return [Link] { [Link](currentYear) }


}

private fun displayTransactions(transactions: List<TransactionExport>) {


val formatter = [Link](Locale("id", "ID"))

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)}"
}

override fun onSupportNavigateUp(): Boolean {


finish()
return true
}
}

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"/>

<!-- Form Card -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
android:padding="24dp"
android:elevation="4dp">

<!-- Category Name -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Category Name"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/text_dark"
android:layout_marginBottom="8dp"/>

<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"/>

<!-- Category Type -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Category Type"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/text_dark"
android:layout_marginBottom="12dp"/>

<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>

<!-- Buttons -->


<Button
android:id="@+id/btnSaveCategory"
android:layout_width="match_parent"

💾
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"/>

<!-- Form Card -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
android:padding="20dp"
android:elevation="4dp">

<!-- Transaction Type -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Transaction Type"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/text_dark"
android:layout_marginBottom="12dp"/>

<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>

<!-- Date -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Date"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/text_dark"
android:layout_marginBottom="8dp"/>

<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"/>

<!-- Category -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Category"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/text_dark"
android:layout_marginBottom="8dp"/>

<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>

<!-- Amount -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amount"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/text_dark"
android:layout_marginBottom="8dp"/>

<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"/>

<!-- Note -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Note (Optional)"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/text_dark"
android:layout_marginBottom="8dp"/>

<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"/>

<!-- Save Button -->


<Button
android:id="@+id/btnSave"
android:layout_width="match_parent"

💾
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">

<!-- 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="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"/>

<!-- Card Container -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:background="@color/white"
android:padding="20dp"
android:elevation="4dp">

<!-- Type Selector -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="View Summary For"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/text_dark"
android:layout_marginBottom="12dp"/>

<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>

<!-- Divider -->


<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@color/cream"
android:layout_marginBottom="16dp"/>

<!-- Summary List -->


<ListView
android:id="@+id/listCategory"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@color/cream"
android:dividerHeight="1dp"/>

</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">

<!-- Back Button at Top -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="start"
android:layout_marginBottom="32dp">

<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>

<!-- Icon/Illustration -->


<TextView
android:layout_width="wrap_content"

📄
android:layout_height="wrap_content"
android:text=" "
android:textSize="80sp"
android:layout_marginBottom="24dp"/>

<!-- Title -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Export to PDF"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_marginBottom="12dp"/>

<!-- Description -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Download all your transactions as a PDF report"
android:textSize="14sp"
android:textColor="@color/text_light"
android:textAlignment="center"
android:layout_marginBottom="40dp"
android:paddingHorizontal="40dp"/>

<!-- Export Button Card -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
android:padding="24dp"
android:elevation="4dp">

<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">

<!-- 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="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"/>

<!-- Income vs Expense Card -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
android:padding="20dp"
android:elevation="4dp"
android:layout_marginBottom="20dp">

<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"/>

<!-- Bar Chart Container -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="bottom"
android:layout_marginBottom="16dp">

<!-- Income Bar -->


<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
android:layout_marginEnd="8dp">

<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>

<!-- Expense Bar -->


<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center"
android:layout_marginStart="8dp">

<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>

<!-- Category Breakdown Card -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
android:padding="20dp"
android:elevation="4dp">

<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"/>

<!-- Category Breakdown Container -->


<LinearLayout
android:id="@+id/categoryBreakdownContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>

</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">

<!-- Header with Logout Button -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="8dp">

<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>

<!-- Logout Button (Top Right) -->


<Button
android:id="@+id/btnLogout"
android:layout_width="wrap_content"

🚪
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>

<!-- Summary Card -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
android:padding="20dp"
android:elevation="4dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp">

<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"/>

<!-- Income Row -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="12dp">

<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>

<!-- Expense Row -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="12dp">

<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>

<!-- Divider -->


<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@color/cream"
android:layout_marginVertical="12dp"/>

<!-- Balance Row -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<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>

<!-- Quick Actions Title -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Quick Actions"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_marginBottom="16dp"/>

<!-- Add Transaction Button -->


<Button
android:id="@+id/btnAddTransaction"
android:layout_width="match_parent"


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"/>

<!-- View Transactions Button -->


<Button
android:id="@+id/btnViewTransactions"
android:layout_width="match_parent"

📋
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"/>

<!-- Category Summary Button -->


<Button
android:id="@+id/btnCategorySummary"
android:layout_width="match_parent"

📊
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"/>

<!-- View Graphs Button -->


<Button
android:id="@+id/btnViewGraphs"
android:layout_width="match_parent"

📈
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"/>

<!-- Export PDF Button -->


<Button
android:id="@+id/btnExport"
android:layout_width="match_parent"

📄
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">

<!-- Centered Card Container -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical"
android:padding="32dp">

<!-- App Logo/Title -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="8dp"
android:text="FinanceMate"
android:textColor="@color/primary_blue"
android:textSize="36sp"
android:textStyle="bold"/>

<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"/>

<!-- Login Card -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:elevation="4dp"
android:orientation="vertical"
android:padding="24dp">

<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"/>

<!-- Password Input -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="Password"
android:textColor="@color/text_dark"
android:textStyle="bold"/>

<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"/>

<!-- Login Button -->


<Button
android:id="@+id/btnLogin"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginBottom="16dp"
android:backgroundTint="@color/primary_blue"
android:text="Login"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"/>

<!-- Divider -->


<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginVertical="16dp"
android:background="@color/cream"/>

<!-- Sign Up Link -->


<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal">

<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">

<!-- 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="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"/>

<!-- Card Container -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:background="@color/white"
android:padding="20dp"
android:elevation="4dp">
<!-- Type Selector -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Category Type"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/text_dark"
android:layout_marginBottom="12dp"/>

<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>

<!-- Add Category Button -->


<Button
android:id="@+id/btnAddCategory"
android:layout_width="match_parent"


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"/>

<!-- Info Text -->


<TextView
android:layout_width="wrap_content"

📌
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"/>

<!-- Categories List -->


<ListView
android:id="@+id/listCategories"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@color/cream"
android:dividerHeight="1dp"/>

</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">

<!-- 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="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"/>

<!-- Filter Card -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
android:padding="16dp"
android:elevation="4dp"
android:layout_marginBottom="16dp">

<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>

<!-- Summary Total -->


<TextView
android:id="@+id/tvTotal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Loading..."
android:textSize="13sp"
android:textColor="@color/text_dark"
android:textStyle="bold"
android:padding="12dp"
android:background="@color/yellow"
android:layout_marginBottom="16dp"/>

<!-- Transactions List -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
android:background="@color/white"
android:padding="16dp"
android:elevation="4dp">

<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">

<!-- Centered Card Container -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical"
android:padding="32dp">

<!-- App Logo/Title -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="FinanceMate"
android:textSize="36sp"
android:textStyle="bold"
android:textColor="@color/primary_blue"
android:layout_gravity="center"
android:layout_marginBottom="8dp"/>

<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"/>

<!-- Signup Card -->


<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white"
android:padding="24dp"
android:elevation="4dp">

<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"/>

<!-- Username Input -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Username"
android:textColor="@color/text_dark"
android:textStyle="bold"
android:layout_marginBottom="8dp"/>

<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"/>

<!-- Password Input -->


<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Password"
android:textColor="@color/text_dark"
android:textStyle="bold"
android:layout_marginBottom="8dp"/>

<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"/>

<!-- Signup Button -->


<Button
android:id="@+id/btnSignup"
android:layout_width="match_parent"
android:layout_height="56dp"
android:text="Create Account"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
android:backgroundTint="@color/light_blue"
android:layout_marginBottom="16dp"/>

<!-- Divider -->


<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/cream"
android:layout_marginVertical="16dp"/>

<!-- Back to Login Link -->


<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center">

<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>

<!-- Text colors -->


<item name="android:textColor">@color/text_dark</item>
<item name="android:textColorPrimary">@color/text_dark</item>
<item name="android:textColorSecondary">@color/text_light</item>

<!-- Background -->


<item name="android:windowBackground">@color/cream</item>

<!-- Action bar -->


<item name="actionBarStyle">@style/CustomActionBarStyle</item>
</style>

<!-- Custom ActionBar Style -->


<style name="CustomActionBarStyle" parent="[Link]">
<item name="background">@color/primary_blue</item>
<item name="titleTextStyle">@style/CustomActionBarTitle</item>
</style>
<!-- ActionBar Title Style -->
<style name="CustomActionBarTitle"
parent="[Link]">
<item name="android:textColor">@color/white</item>
<item name="android:textSize">20sp</item>
<item name="android:textStyle">bold</item>
</style>
</resources>

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])
}

[Link] (Version Catalog “libs”)


[versions]
agp = "8.13.2"
kotlin = "2.0.21"
coreKtx = "1.17.0"
junit = "4.13.2"
junitVersion = "1.3.0"
espressoCore = "3.7.0"
lifecycleRuntimeKtx = "2.10.0"
activityCompose = "1.12.1"
composeBom = "2024.09.00"

[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]
}
}
}

[Link] = "Finance Mate"


include(":app")

You might also like