diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4e85d3014f8ad9f010065335c49692f800f7b6de
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
+env
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..26d33521af10bcc7fd8cea344038eaaeb78d0ef5
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/README.md b/README.md
index 8c4d5970cb5e5233afb1ebd385b9dde5efc88348..7caec594824b0022bd77787de43af13b2a67ae72 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,43 @@
-# IF3210-2024-Android-AMW
\ No newline at end of file
+# 👨🏽 Bondoman
+
+Bandung Bondowoso merupakan seorang kepala proyek pembangunan seribu candi. Proyek tersebut dia dapatkan dari Roro yang tidak memahami segitiga manajemen proyek, yaitu budget, deadline, dan quality. Proyek ini memiliki budget yang sedikit, deadline yang hanya satu malam, dan Roro meminta kualitas candi yang bagus.
+
+Bondowoso merasa pusing ketika mengerjakan proyek seribu candi dalam satu malam ini. Dalam pengerjaannya, terjadi banyak sekali transaksi pembelian bahan baku. Tentu saja dia harus berhati-hati dalam melakukan perhitungan biaya, sebab jika tidak seusai dengan RAB (Rancangan Anggaran Biaya) semula, Roro tidak ingin membayarnya. 
+
+Awalnya, Bondowoso menuliskan segala transaksi jual beli bahan baku di atas prasasti berbentuk batu. Namun, dengan skala proyek yang sangat besar ini, ia kewalahan dan meminta bantuan kalian, para jin yang saat ini berkuliah di Institut Jin semester 6, untuk membuat aplikasi manajemen keuangan. Ia percaya kalian bukanlah jin yang pandir sehingga dapat menyelesaikan aplikasi tersebut.
+
+Saat ini, Bondowoso menginginkan aplikasi tersebut dapat berjalan di gawai yang ia miliki. Karena ia tidak suka buah apel, ia meminta aplikasi dibuat untuk sistem operasi Android. Bantulan Bondowoso memanajemen uangnya agar pembangunan candi berjalan lancar!
+
+## âš¡ Main Features
+
+| Feature            | Screenshot                                                                                                                                   |
+|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------|
+| Login              | <img src="screenshot/login.png" alt="drawing" width="200"/>                                                                                  |
+| Transaction List   | <img src="screenshot/daftar_transaksi.png" alt="drawing" width="200"/>                                                                       |
+| Add Transaction    | <img src="screenshot/penambahan_transaksi.png" alt="drawing" width="200"/>                                                                   |
+| Update Transaction | <img src="screenshot/pembaruan_transaksi.png" alt="drawing" width="200"/>                                                                    | 
+| Scan               | <img src="screenshot/scan.png" alt="drawing" width="200"/>                                                                                   |
+| Scan Result        | <img src="screenshot/hasil_scan.png" alt="drawing" width="200"/>                                                                             |
+| Twibbon            | <img src="screenshot/twibbon.png" alt="drawing" width="200"/>                                                                                | 
+| Graph              | <img src="screenshot/graph_vertical.png" alt="drawing" width="200"/> <img src="screenshot/graph_horizontal.png" alt="drawing" height="200"/> |
+| Settings           | <img src="screenshot/pengaturan.png" alt="drawing" width="200"/>                                                                             |
+| Network Sensing    | <img src="screenshot/pendeteksi_jaringan.png" alt="drawing" width="200"/>                                                                    |
+
+## 🕹️ Library
+
+* room
+* retrofit2
+* Moshi
+* dotenv
+* cameraX
+* okhttp3
+* Apache POI
+
+## 💻 Developers
+
+| Name                                              | Features                                                                         | Exploration hours | Working Hours |
+|---------------------------------------------------|----------------------------------------------------------------------------------|-------------------|---------------|
+| [Yudi Kurniawan](https://github.com/frankiehuangg)| Login                                                                            |                   |               |
+| [Wilson Tansil](https://github.com/Tansil011019)  | Login; Logout; JWT Service; Graph; Network Sensing; Twibbon                      | 5                 | 20            |
+| [Farizki Kurniawan](https://github.com/farizkik)  | Header and Navbar; Transaction CRUD; Transaction List; Broadcast Receiver        | 5                 | 20            |
+| [Frankie Huang](https://github.com/frankiehuangg) | Note Scanning; Export Transaction to Spreadsheets; Send Transaction with Gmail   | 8                 | 8             |
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..42afabfd2abebf31384ca7797186a27a4b7dbee8
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
new file mode 100644
index 0000000000000000000000000000000000000000..c2372a42139987be686f0f4b8ca5e61a74bdcb81
--- /dev/null
+++ b/app/build.gradle.kts
@@ -0,0 +1,111 @@
+plugins {
+    id("com.android.application")
+    id("org.jetbrains.kotlin.android")
+    id("kotlin-kapt")
+    id("androidx.navigation.safeargs.kotlin")
+
+}
+
+android {
+    namespace = "com.example.bondoman"
+    compileSdk = 34
+
+    defaultConfig {
+        applicationId = "com.example.bondoman"
+        minSdk = 29
+        targetSdk = 34
+        versionCode = 1
+        versionName = "1.0"
+        multiDexEnabled = true
+        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+    }
+
+    buildTypes {
+        release {
+            isMinifyEnabled = false
+            proguardFiles(
+                getDefaultProguardFile("proguard-android-optimize.txt"),
+                "proguard-rules.pro"
+            )
+        }
+    }
+    compileOptions {
+        sourceCompatibility = JavaVersion.VERSION_1_8
+        targetCompatibility = JavaVersion.VERSION_1_8
+    }
+    kotlinOptions {
+        jvmTarget = "1.8"
+    }
+    buildFeatures {
+        viewBinding = true
+    }
+}
+
+dependencies {
+
+    implementation("androidx.core:core-ktx:1.9.0")
+    implementation("androidx.appcompat:appcompat:1.6.1")
+    implementation("com.google.android.material:material:1.8.0")
+    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
+    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2")
+    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
+    implementation("androidx.navigation:navigation-fragment-ktx:2.5.3")
+    implementation("androidx.navigation:navigation-ui-ktx:2.5.3")
+
+    implementation("androidx.navigation:navigation-ui-ktx:2.5.3")
+    implementation("com.squareup.retrofit2:converter-gson:2.9.0")
+    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2")
+    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
+
+    implementation("androidx.legacy:legacy-support-v4:1.0.0")
+    testImplementation("junit:junit:4.13.2")
+    androidTestImplementation("androidx.test.ext:junit:1.1.5")
+    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
+
+    implementation ("androidx.room:room-runtime:2.5.0")
+    annotationProcessor("androidx.room:room-compiler:2.5.0")
+    // To use Kotlin annotation processing tool (kapt)
+    kapt ("androidx.room:room-compiler:2.5.0")
+    implementation ("androidx.room:room-ktx:2.5.0")
+
+    // To use Kotlin Symbol Processing (KSP)
+    // ksp "androidx.room:room-compiler:$room_version"
+    // optional - RxJava2 support for Room
+    implementation ("androidx.room:room-rxjava2:2.5.0")
+    implementation ("androidx.room:room-rxjava3:2.5.0")
+    implementation ("androidx.room:room-guava:2.5.0")
+    testImplementation ("androidx.room:room-testing:2.5.0")
+    implementation ("androidx.room:room-paging:2.5.0")
+    implementation ("com.github.AnyChart:AnyChart-Android:1.1.5")
+    implementation ("androidx.multidex:multidex:2.0.1")
+
+    // To use Retrofit
+    implementation ("com.squareup.retrofit2:retrofit:2.9.0")
+    implementation ("com.squareup.retrofit2:converter-moshi:2.9.0")
+
+    // To use moshi
+    implementation ("com.squareup.moshi:moshi:1.15.0")
+    implementation ("com.squareup.moshi:moshi-kotlin:1.15.0")
+    implementation ("com.squareup.moshi:moshi-kotlin-codegen:1.15.0")
+
+    // To use dotenv
+    implementation ("io.github.cdimascio:dotenv-kotlin:6.4.1")
+
+    // Use camera
+    implementation("com.google.guava:guava:31.0.1-android")
+
+    val cameraXVersion = "1.3.2"
+    implementation("androidx.camera:camera-core:${cameraXVersion}")
+    implementation("androidx.camera:camera-camera2:${cameraXVersion}")
+    implementation("androidx.camera:camera-lifecycle:${cameraXVersion}")
+    implementation("androidx.camera:camera-video:${cameraXVersion}")
+    implementation("androidx.camera:camera-view:${cameraXVersion}")
+    implementation("androidx.camera:camera-extensions:${cameraXVersion}")
+
+    // Use okhttp3
+    implementation("com.squareup.okhttp3:okhttp:4.7.2")
+
+    // Use Apache POI
+    implementation("com.github.SUPERCILEX.poi-android:poi:3.17")
+
+}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000000000000000000000000000000000000..481bb434814107eb79d7a30b676d344b0df2f8ce
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/example/bondoman/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/example/bondoman/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4985d8b5c32e726edb0cc805fc4df1f44bfad035
--- /dev/null
+++ b/app/src/androidTest/java/com/example/bondoman/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.example.bondoman
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+    @Test
+    fun useAppContext() {
+        // Context of the app under test.
+        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+        assertEquals("com.example.bondoman", appContext.packageName)
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e97a4ac8755306d301b700ca90f8c768434ebd1b
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <uses-feature android:name="android.hardware.camera.any" />
+
+
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
+
+    <application
+        android:allowBackup="true"
+        android:dataExtractionRules="@xml/data_extraction_rules"
+        android:enableOnBackInvokedCallback="true"
+        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/Theme.BondoMan"
+        tools:targetApi="31">
+        <activity
+            android:name=".ui.login.LoginActivity"
+            android:exported="false"
+            android:label="@string/login">
+
+        </activity>
+
+        <receiver
+            android:name=".receiver.MyBroadcastReceiver"
+            android:enabled="true"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="com.example.bondoman.action" />
+            </intent-filter>
+        </receiver>
+
+        <activity
+            android:name=".MainActivity"
+            android:enabled="true"
+            android:exported="true"
+            android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <service
+            android:name=".service.auth.TokenExpService" />
+
+        <provider
+            android:authorities="com.example.counter"
+            android:name="androidx.core.content.FileProvider"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/provider_paths"
+                />
+        </provider>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/app/src/main/assets/env.example b/app/src/main/assets/env.example
new file mode 100644
index 0000000000000000000000000000000000000000..52de4c647fd47a8f3f3cb465216f21d71ef38a12
--- /dev/null
+++ b/app/src/main/assets/env.example
@@ -0,0 +1 @@
+BASE_URL = "https://pbd-backend-2024.vercel.app/"
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/MainActivity.kt b/app/src/main/java/com/example/bondoman/MainActivity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9850c99708d27726535b7d135bccd70ae0c80b37
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/MainActivity.kt
@@ -0,0 +1,103 @@
+package com.example.bondoman
+
+import android.content.BroadcastReceiver
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.findNavController
+import androidx.navigation.ui.AppBarConfiguration
+import androidx.navigation.ui.setupActionBarWithNavController
+import androidx.navigation.ui.setupWithNavController
+import com.example.bondoman.databinding.ActivityMainBinding
+import com.example.bondoman.network.ConnectivityObserver
+import com.example.bondoman.network.NetworkConnectivityObserver
+import com.example.bondoman.receiver.MyBroadcastListener
+import com.example.bondoman.share_preference.PreferenceManager
+import com.example.bondoman.ui.login.LoginActivity
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class MainActivity : AppCompatActivity(), MyBroadcastListener {
+
+    private lateinit var binding: ActivityMainBinding
+    private lateinit var receiver: BroadcastReceiver
+    private lateinit var  connectivityObserver: ConnectivityObserver
+    private lateinit var preferenceManager: PreferenceManager
+    private var alertDialog: AlertDialog? = null
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        binding = ActivityMainBinding.inflate(layoutInflater)
+        setContentView(binding.root)
+
+        connectivityObserver = NetworkConnectivityObserver(applicationContext)
+
+        preferenceManager = PreferenceManager(this)
+
+        if (preferenceManager.getToken().isNullOrEmpty()) {
+            startActivity(Intent(this, LoginActivity::class.java))
+            finish()
+        }
+
+        val navView: BottomNavigationView = binding.navView
+
+        val navController = findNavController(R.id.nav_host_fragment_activity_main)
+        // Passing each menu ID as a set of Ids because each
+        // menu should be considered as top level destinations.
+        val appBarConfiguration = AppBarConfiguration(
+            setOf(
+                R.id.navigation_home, R.id.navigation_transactions, R.id.navigation_graph, R.id.navigation_settings, R.id.transactionFragment, R.id.resultFragment, R.id.navigation_twibbon
+            )
+        )
+
+        setupActionBarWithNavController(navController, appBarConfiguration)
+        navView.setupWithNavController(navController)
+    }
+
+    override fun onStart() {
+        super.onStart()
+        lifecycleScope.launch {
+            observeConnectivity()
+        }
+    }
+
+    private fun observeConnectivity() {
+        val scope = CoroutineScope(Dispatchers.Main)
+        scope.launch {
+            connectivityObserver.observe().collect { status ->
+                if (status == ConnectivityObserver.Status.Unavailable || status == ConnectivityObserver.Status.Lost) {
+                    showNoInternetPopUp()
+                } else {
+                    hideNoInternetPopup()
+                }
+            }
+        }
+    }
+
+    private fun showNoInternetPopUp() {
+        if (!isFinishing && alertDialog == null) {
+            alertDialog = AlertDialog.Builder(this)
+                .setTitle("No Internet Connection")
+                .setMessage("Please check your internet connection and try again.")
+                .setCancelable(false)
+                .setPositiveButton("OK") { dialog, _ ->
+                    dialog.dismiss()
+                }
+                .show()
+        }
+    }
+
+    private fun hideNoInternetPopup() {
+        alertDialog?.dismiss()
+        alertDialog = null
+    }
+
+    override fun onBroadcastReceived(value: String?) {
+        Log.d("adsadas", "asdasd")
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/api/APIClient.kt b/app/src/main/java/com/example/bondoman/api/APIClient.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4d6d38d51597a0c2028b107a7be689c8a4198c06
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/api/APIClient.kt
@@ -0,0 +1,29 @@
+package com.example.bondoman.api
+
+import com.example.bondoman.api.auth.login.LoginService
+import com.example.bondoman.api.auth.token.TokenService
+import com.example.bondoman.api.scan.UploadService
+import com.example.bondoman.common.Constant
+import com.squareup.moshi.Moshi
+import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
+import retrofit2.Retrofit
+import retrofit2.converter.moshi.MoshiConverterFactory
+
+object APIClient {
+    private val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
+
+    private val retrofit: Retrofit by lazy { Retrofit.Builder().baseUrl(Constant.BASE_URL).addConverterFactory(
+        MoshiConverterFactory.create(moshi)).build() }
+
+    val loginService: LoginService by lazy {
+        retrofit.create(LoginService::class.java)
+    }
+
+    val tokenService: TokenService by lazy {
+        retrofit.create(TokenService::class.java)
+    }
+
+    val uploadService: UploadService by lazy {
+        retrofit.create(UploadService::class.java)
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/api/auth/login/LoginService.kt b/app/src/main/java/com/example/bondoman/api/auth/login/LoginService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ae0179a24b77856018c15ffad7172c456a54aef9
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/api/auth/login/LoginService.kt
@@ -0,0 +1,13 @@
+package com.example.bondoman.api.auth.login
+
+import com.example.bondoman.api.auth.login.dto.LoginRequest
+import com.example.bondoman.api.auth.login.dto.LoginResponse
+import retrofit2.Call
+import retrofit2.Response
+import retrofit2.http.Body
+import retrofit2.http.POST
+
+interface LoginService {
+    @POST("api/auth/login")
+    fun login(@Body req: LoginRequest): Call<LoginResponse>
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/api/auth/login/dto/LoginRequest.kt b/app/src/main/java/com/example/bondoman/api/auth/login/dto/LoginRequest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f3ece7581f431fa940fb9234ca0362d46419ec26
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/api/auth/login/dto/LoginRequest.kt
@@ -0,0 +1,11 @@
+package com.example.bondoman.api.auth.login.dto
+
+import com.squareup.moshi.Json
+
+data class LoginRequest(
+    @Json(name= "email")
+    val email: String,
+
+    @Json(name= "password")
+    val password: String
+)
diff --git a/app/src/main/java/com/example/bondoman/api/auth/login/dto/LoginResponse.kt b/app/src/main/java/com/example/bondoman/api/auth/login/dto/LoginResponse.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6225c0707b0a2b8f64097656f5928825538b07a9
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/api/auth/login/dto/LoginResponse.kt
@@ -0,0 +1,8 @@
+package com.example.bondoman.api.auth.login.dto
+
+import com.squareup.moshi.Json
+
+data class LoginResponse(
+    @Json(name="token")
+    val token: String
+)
diff --git a/app/src/main/java/com/example/bondoman/api/auth/token/TokenService.kt b/app/src/main/java/com/example/bondoman/api/auth/token/TokenService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7a5492505a568379fd8dfc30a1e1fa8f90ef15d6
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/api/auth/token/TokenService.kt
@@ -0,0 +1,13 @@
+package com.example.bondoman.api.auth.token
+
+import com.example.bondoman.api.auth.token.dto.TokenResponse
+import retrofit2.Call
+import retrofit2.http.Header
+import retrofit2.http.POST
+
+interface TokenService {
+    @POST("api/auth/token")
+    fun getToken (
+        @Header("Authorization") token: String?
+    ) : Call<TokenResponse>
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/api/auth/token/dto/TokenResponse.kt b/app/src/main/java/com/example/bondoman/api/auth/token/dto/TokenResponse.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d9334f120da381ae0d6ad29b1fec9dcc20365356
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/api/auth/token/dto/TokenResponse.kt
@@ -0,0 +1,14 @@
+package com.example.bondoman.api.auth.token.dto
+
+import com.squareup.moshi.Json
+
+data class TokenResponse(
+    @Json(name = "nim")
+    val nim: String,
+
+    @Json(name="iat")
+    val iat: Long,
+
+    @Json(name="exp")
+    val exp: Long
+)
diff --git a/app/src/main/java/com/example/bondoman/api/scan/UploadService.kt b/app/src/main/java/com/example/bondoman/api/scan/UploadService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4927ab85cc7980d77c72c6b87eee47050f7fa147
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/api/scan/UploadService.kt
@@ -0,0 +1,18 @@
+package com.example.bondoman.api.scan
+
+import com.example.bondoman.api.scan.dto.UploadResponse
+import okhttp3.MultipartBody
+import retrofit2.Call
+import retrofit2.http.Header
+import retrofit2.http.Multipart
+import retrofit2.http.POST
+import retrofit2.http.Part
+
+interface UploadService {
+    @Multipart
+    @POST("api/bill/upload")
+    fun upload(
+        @Header("Authorization") token: String,
+        @Part file: MultipartBody.Part
+    ): Call<UploadResponse>
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/api/scan/dto/UploadResponse.kt b/app/src/main/java/com/example/bondoman/api/scan/dto/UploadResponse.kt
new file mode 100644
index 0000000000000000000000000000000000000000..dd93c3ff4816a3a6a184fb6e68d0b20c41eeed98
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/api/scan/dto/UploadResponse.kt
@@ -0,0 +1,9 @@
+package com.example.bondoman.api.scan.dto
+
+import com.example.bondoman.core.data.Items
+import com.squareup.moshi.Json
+
+data class UploadResponse(
+    @Json(name = "items")
+    val items: Items
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/common/config.kt b/app/src/main/java/com/example/bondoman/common/config.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7c8c49d24eec156e33c2a4da7f2dd944232caa90
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/common/config.kt
@@ -0,0 +1,19 @@
+package com.example.bondoman.common
+import io.github.cdimascio.dotenv.dotenv
+
+
+object Constant {
+    lateinit var BASE_URL: String
+    init {
+        try {
+            val dotenv = dotenv {
+                directory = "/assets"
+                filename = "env"
+            }
+            BASE_URL = dotenv["BASE_URL"] ?: ""
+        } catch (e: Exception) {
+            e.printStackTrace()
+            BASE_URL = ""
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/common/response/ResponseContract.kt b/app/src/main/java/com/example/bondoman/common/response/ResponseContract.kt
new file mode 100644
index 0000000000000000000000000000000000000000..64de0031d7799c7c532b5769a3d1090a64f1e6a3
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/common/response/ResponseContract.kt
@@ -0,0 +1,6 @@
+package com.example.bondoman.common.response
+
+sealed class ResponseContract {
+    data class Success<T>(val response: T) : ResponseContract()
+    data class Error(val response: String) : ResponseContract()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/core/data/Item.kt b/app/src/main/java/com/example/bondoman/core/data/Item.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2f9cbde8b48fb9cfbc5dcf6689d1ad675f842f50
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/data/Item.kt
@@ -0,0 +1,14 @@
+package com.example.bondoman.core.data
+
+data class Item(
+    val name: String,
+    val qty: Int,
+    val price: Float
+){
+    constructor(parcelableItem: ParcelableItem) : this(
+        parcelableItem.name,
+        parcelableItem.qty,
+        parcelableItem.price
+    )
+}
+
diff --git a/app/src/main/java/com/example/bondoman/core/data/Items.kt b/app/src/main/java/com/example/bondoman/core/data/Items.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f7e12b7500d0466b63cbde2a844c2f7ee880aac6
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/data/Items.kt
@@ -0,0 +1,5 @@
+package com.example.bondoman.core.data
+
+data class Items(
+    var items: List<Item>
+)
diff --git a/app/src/main/java/com/example/bondoman/core/data/ParcelableItem.kt b/app/src/main/java/com/example/bondoman/core/data/ParcelableItem.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0942faf8ac786199fcf28ecf4d20f7c9d9f65517
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/data/ParcelableItem.kt
@@ -0,0 +1,37 @@
+package com.example.bondoman.core.data
+
+import android.os.Parcel
+import android.os.Parcelable
+
+data class ParcelableItem(
+    val name: String,
+    val qty: Int,
+    val price: Float
+) : Parcelable {
+    constructor(parcel: Parcel) : this(
+        parcel.readString()!!,
+        parcel.readInt(),
+        parcel.readFloat()
+    ) {
+    }
+
+    override fun writeToParcel(parcel: Parcel, flags: Int) {
+        parcel.writeString(name)
+        parcel.writeInt(qty)
+        parcel.writeFloat(price)
+    }
+
+    override fun describeContents(): Int {
+        return 0
+    }
+
+    companion object CREATOR : Parcelable.Creator<ParcelableItem> {
+        override fun createFromParcel(parcel: Parcel): ParcelableItem {
+            return ParcelableItem(parcel)
+        }
+
+        override fun newArray(size: Int): Array<ParcelableItem?> {
+            return arrayOfNulls(size)
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/core/data/Transaction.kt b/app/src/main/java/com/example/bondoman/core/data/Transaction.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0f86401c2dc6d55b25a1014c2141640c0448b34d
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/data/Transaction.kt
@@ -0,0 +1,12 @@
+package com.example.bondoman.core.data
+
+data class Transaction (
+    var title: String,
+    var type: String,
+    var nominal: Long,
+    var creationTime: Long,
+    var location: String,
+    var latitude: Double,
+    var longitude: Double,
+    var id: Long = 0
+)
diff --git a/app/src/main/java/com/example/bondoman/core/repository/TransactionDataSource.kt b/app/src/main/java/com/example/bondoman/core/repository/TransactionDataSource.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a68271cdfde83105a30f6650e34d9bf65cf8d48a
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/repository/TransactionDataSource.kt
@@ -0,0 +1,17 @@
+package com.example.bondoman.core.repository
+
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.lib.transaction.TRANSACTION_TYPE
+
+
+interface TransactionDataSource {
+    suspend fun add(transaction: Transaction)
+
+    suspend fun get(id:Long): Transaction?
+
+    suspend fun getAll(): List<Transaction>
+
+    suspend fun getTransactionTypeCount(type: TRANSACTION_TYPE): Int
+
+    suspend fun remove(transaction: Transaction)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/core/repository/TransactionRepository.kt b/app/src/main/java/com/example/bondoman/core/repository/TransactionRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..db3466743a205f233e968d2b39bbdd7541fecc6a
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/repository/TransactionRepository.kt
@@ -0,0 +1,16 @@
+package com.example.bondoman.core.repository
+
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.lib.transaction.TRANSACTION_TYPE
+
+class TransactionRepository(private val dataSource: TransactionDataSource) {
+    suspend fun  addTransaction(transaction: Transaction) = dataSource.add(transaction)
+
+    suspend fun getTransaction(id: Long) = dataSource.get(id)
+
+    suspend fun getAllTransactions() = dataSource.getAll()
+
+    suspend fun getTransactionTypeCount(type: TRANSACTION_TYPE) = dataSource.getTransactionTypeCount(type)
+
+    suspend fun removeTransaction(transaction: Transaction) = dataSource.remove(transaction)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/core/repository/auth/login/LoginRepository.kt b/app/src/main/java/com/example/bondoman/core/repository/auth/login/LoginRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2a4f0d794e5227d291d50eb6f16ed3441dfe59fc
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/repository/auth/login/LoginRepository.kt
@@ -0,0 +1,31 @@
+package com.example.bondoman.core.repository.auth.login
+
+import android.util.Log
+import com.example.bondoman.api.APIClient
+import com.example.bondoman.api.auth.login.dto.LoginRequest
+import com.example.bondoman.api.auth.login.dto.LoginResponse
+import com.example.bondoman.common.response.ResponseContract
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import retrofit2.Response
+
+class LoginRepository {
+    suspend fun login(req: LoginRequest) : ResponseContract {
+        return withContext(Dispatchers.IO) {
+            try {
+                val response: Response<LoginResponse> = APIClient.loginService.login(req).execute()
+                if (response.isSuccessful) {
+                    ResponseContract.Success(response.body()!!)
+                } else {
+                    val errorBody = response.errorBody()?.string()
+                    Log.d("Login Repository", "This is message: $errorBody")
+                    ResponseContract.Error(errorBody!!)
+                }
+            } catch (e: Exception) {
+                Log.e("Login Repository", "Login Failed", e)
+                ResponseContract.Error(e.toString())
+            }
+        }
+
+    }
+}
diff --git a/app/src/main/java/com/example/bondoman/core/repository/auth/token/TokenRepository.kt b/app/src/main/java/com/example/bondoman/core/repository/auth/token/TokenRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ca5f222a6da8e9810be5b0709d888a20306d8641
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/repository/auth/token/TokenRepository.kt
@@ -0,0 +1,31 @@
+package com.example.bondoman.core.repository.auth.token
+
+import android.util.Log
+import com.example.bondoman.api.APIClient
+import com.example.bondoman.api.auth.token.dto.TokenResponse
+import com.example.bondoman.common.response.ResponseContract
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import retrofit2.Response
+
+class TokenRepository {
+
+    suspend fun getToken(headerAuth: String?): ResponseContract{
+        return withContext(Dispatchers.IO) {
+            try {
+                Log.d("Token Repository", "This is header $headerAuth")
+                val response: Response<TokenResponse> = APIClient.tokenService.getToken(headerAuth).execute()
+                if (response.isSuccessful) {
+                    ResponseContract.Success(response.body()!!)
+                } else {
+                    val errorBody = response.errorBody()?.string()
+                    Log.d("Token Repository", "This is message: $errorBody")
+                    ResponseContract.Error(errorBody!!)
+                }
+            } catch (e: Exception) {
+                Log.e("Token Repository", "Failed to get token", e)
+                ResponseContract.Error(e.toString())
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/core/repository/scan/UploadRepository.kt b/app/src/main/java/com/example/bondoman/core/repository/scan/UploadRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1be01a56fbbf5edee48a9ad845ea667204ab07c0
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/repository/scan/UploadRepository.kt
@@ -0,0 +1,33 @@
+package com.example.bondoman.core.repository.scan
+
+import android.util.Log
+import com.example.bondoman.api.APIClient
+import com.example.bondoman.api.scan.dto.UploadResponse
+import com.example.bondoman.common.response.ResponseContract
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import okhttp3.MultipartBody
+import retrofit2.Response
+
+class UploadRepository {
+    suspend fun upload(token: String?, part: MultipartBody.Part): ResponseContract {
+        return withContext(Dispatchers.IO) {
+            try {
+                Log.d("Upload Repository", "Header: Bearer $token")
+                val response: Response<UploadResponse> = APIClient.uploadService.upload("Bearer " + token!!, part).execute()
+
+                if (response.isSuccessful) {
+                    Log.d("Upload Repository", "Upload Succeeded")
+                    ResponseContract.Success(response.body())
+                } else {
+                    val errorBody = response.errorBody()?.string()
+                    Log.d("Upload Repository", "Upload Failed: $errorBody")
+                    ResponseContract.Error(errorBody!!)
+                }
+            } catch (e: Exception) {
+                Log.e("Upload Repository", "Upload Failed: $e")
+                ResponseContract.Error(e.toString())
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/core/usecase/AddTransaction.kt b/app/src/main/java/com/example/bondoman/core/usecase/AddTransaction.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8f0343ec1f7eab26bcb0a82a3126231e91724d5c
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/usecase/AddTransaction.kt
@@ -0,0 +1,8 @@
+package com.example.bondoman.core.usecase
+
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.core.repository.TransactionRepository
+
+class AddTransaction(private val transactionRepository: TransactionRepository) {
+    suspend operator fun invoke(transaction: Transaction) = transactionRepository.addTransaction(transaction)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/core/usecase/GetAllTransaction.kt b/app/src/main/java/com/example/bondoman/core/usecase/GetAllTransaction.kt
new file mode 100644
index 0000000000000000000000000000000000000000..159cc17f821b9a30997bca70368f66067569ace0
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/usecase/GetAllTransaction.kt
@@ -0,0 +1,7 @@
+package com.example.bondoman.core.usecase
+
+import com.example.bondoman.core.repository.TransactionRepository
+
+class GetAllTransaction (private val transactionRepository: TransactionRepository){
+    suspend operator fun invoke() = transactionRepository.getAllTransactions()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/core/usecase/GetTransaction.kt b/app/src/main/java/com/example/bondoman/core/usecase/GetTransaction.kt
new file mode 100644
index 0000000000000000000000000000000000000000..99337b4100b5aae5cb9970f10dd6c8638615695c
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/usecase/GetTransaction.kt
@@ -0,0 +1,7 @@
+package com.example.bondoman.core.usecase
+
+import com.example.bondoman.core.repository.TransactionRepository
+
+class GetTransaction (private val transactionRepository: TransactionRepository){
+    suspend operator fun invoke(id:Long) = transactionRepository.getTransaction(id)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/core/usecase/GetTransactionTypeCount.kt b/app/src/main/java/com/example/bondoman/core/usecase/GetTransactionTypeCount.kt
new file mode 100644
index 0000000000000000000000000000000000000000..171f86ebe5840e0215d27fee810ddb32c2110509
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/usecase/GetTransactionTypeCount.kt
@@ -0,0 +1,8 @@
+package com.example.bondoman.core.usecase
+
+import com.example.bondoman.core.repository.TransactionRepository
+import com.example.bondoman.lib.transaction.TRANSACTION_TYPE
+
+class GetTransactionTypeCount(private val transactionRepository: TransactionRepository) {
+    suspend operator fun invoke (transactionType: TRANSACTION_TYPE) = transactionRepository.getTransactionTypeCount(transactionType)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/core/usecase/RemoveTransaction.kt b/app/src/main/java/com/example/bondoman/core/usecase/RemoveTransaction.kt
new file mode 100644
index 0000000000000000000000000000000000000000..89494a638a20c6223550857bc447d19766ddd7cc
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/core/usecase/RemoveTransaction.kt
@@ -0,0 +1,8 @@
+package com.example.bondoman.core.usecase
+
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.core.repository.TransactionRepository
+
+class RemoveTransaction(private val transactionRepository: TransactionRepository) {
+    suspend operator fun invoke(transaction: Transaction) = transactionRepository.removeTransaction(transaction)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/framework/RoomTransactionDataSource.kt b/app/src/main/java/com/example/bondoman/framework/RoomTransactionDataSource.kt
new file mode 100644
index 0000000000000000000000000000000000000000..77243e2df528b63f9d5aee89dc259547b670959d
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/framework/RoomTransactionDataSource.kt
@@ -0,0 +1,47 @@
+package com.example.bondoman.framework
+
+import android.content.Context
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.core.repository.TransactionDataSource
+import com.example.bondoman.framework.db.DatabaseService
+import com.example.bondoman.framework.db.TransactionEntity
+import com.example.bondoman.lib.transaction.TRANSACTION_TYPE
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class RoomTransactionDataSource(context: Context) : TransactionDataSource {
+    val transactionDao = DatabaseService.getInstance(context).transactionDao()
+    init {
+        CoroutineScope(Dispatchers.IO).launch {
+        }
+    }
+
+    private suspend fun seedDatabase(context: Context) {
+        if (transactionDao.getAllTransactionEntities().isEmpty()) {
+            val transactions = listOf(
+                TransactionEntity("Transaction 1", TRANSACTION_TYPE.PEMASUKAN, 100, System.currentTimeMillis(), "Location 1",0.0,0.0, ),
+                TransactionEntity("Transaction 2", TRANSACTION_TYPE.PEMBELIAN, 200, System.currentTimeMillis(), "Location 2", 0.0 , 0.0)
+            )
+
+            transactions.forEach { transaction ->
+                transactionDao.addTransactionEntity(transaction)
+            }
+        }
+    }
+
+
+    override suspend fun add(transaction: Transaction) = transactionDao.addTransactionEntity(
+        TransactionEntity.fromTransaction(transaction)
+    )
+
+    override suspend fun get(id: Long) = transactionDao.getTransactionEntity(id)?.toTransaction()
+
+
+    override suspend fun getAll() = transactionDao.getAllTransactionEntities().map{it.toTransaction()}
+
+    override suspend fun getTransactionTypeCount(type: TRANSACTION_TYPE) = transactionDao.getTransactionTypeCount(type)
+
+    override suspend fun remove(transaction: Transaction) = transactionDao.deleteTransactionEntity(
+        TransactionEntity.fromTransaction(transaction))
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/framework/UseCases.kt b/app/src/main/java/com/example/bondoman/framework/UseCases.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d0fa3d83f5feb249b892030ebabb552bd765b5ce
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/framework/UseCases.kt
@@ -0,0 +1,15 @@
+package com.example.bondoman.framework
+
+import com.example.bondoman.core.usecase.AddTransaction
+import com.example.bondoman.core.usecase.GetAllTransaction
+import com.example.bondoman.core.usecase.GetTransaction
+import com.example.bondoman.core.usecase.GetTransactionTypeCount
+import com.example.bondoman.core.usecase.RemoveTransaction
+
+data class UseCases(
+    val addTransaction: AddTransaction,
+    val getTransaction: GetTransaction,
+    val getAllTransaction: GetAllTransaction,
+    val removeTransaction: RemoveTransaction,
+    val getTransactionTypeCount: GetTransactionTypeCount
+)
diff --git a/app/src/main/java/com/example/bondoman/framework/db/DatabaseService.kt b/app/src/main/java/com/example/bondoman/framework/db/DatabaseService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..fb1f8220224633c206e003ac3916dbc0cc8cb48a
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/framework/db/DatabaseService.kt
@@ -0,0 +1,26 @@
+package com.example.bondoman.framework.db
+
+import android.content.Context
+import androidx.room.Database
+import androidx.room.Room
+import androidx.room.RoomDatabase
+
+@Database(entities = [TransactionEntity::class], version = 1)
+abstract class DatabaseService: RoomDatabase() {
+    companion object {
+
+        private const val DATABASE_NAME = "note.db"
+
+        private var instance: DatabaseService? = null
+
+        private fun create(context: Context): DatabaseService =
+            Room.databaseBuilder(context, DatabaseService::class.java, DATABASE_NAME)
+                .fallbackToDestructiveMigration()
+                .build()
+
+        fun getInstance(context: Context): DatabaseService =
+            (instance ?: create(context)).also { instance = it }
+    }
+
+    abstract fun transactionDao(): TransactionDao
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/framework/db/TransactionDao.kt b/app/src/main/java/com/example/bondoman/framework/db/TransactionDao.kt
new file mode 100644
index 0000000000000000000000000000000000000000..903a3ed716fe16e15ee6b295c9f88e42221b18d5
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/framework/db/TransactionDao.kt
@@ -0,0 +1,26 @@
+package com.example.bondoman.framework.db
+
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.Query
+import com.example.bondoman.lib.transaction.TRANSACTION_TYPE
+
+@Dao
+
+interface TransactionDao {
+    @Insert(onConflict = 1)
+     fun addTransactionEntity(transactionEntity: TransactionEntity)
+
+    @Query("SELECT * FROM `transaction` WHERE id = :id")
+     fun getTransactionEntity(id: Long): TransactionEntity?
+
+    @Query("SELECT * FROM `transaction`")
+     fun getAllTransactionEntities(): List<TransactionEntity>
+
+     @Query("SELECT COUNT(*) FROM `transaction` WHERE type = :type")
+     fun getTransactionTypeCount(type: TRANSACTION_TYPE): Int
+
+    @Delete
+     fun deleteTransactionEntity(transactionEntity: TransactionEntity)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/framework/db/TransactionEntity.kt b/app/src/main/java/com/example/bondoman/framework/db/TransactionEntity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2de08f6806a9b2d8be109a0ae32f9d7af6460b05
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/framework/db/TransactionEntity.kt
@@ -0,0 +1,45 @@
+package com.example.bondoman.framework.db
+
+import android.util.Log
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.lib.transaction.TRANSACTION_TYPE
+
+@Entity(tableName = "transaction")
+data class TransactionEntity(
+    val title: String,
+    val type: TRANSACTION_TYPE,
+    val nominal: Long,
+
+    @ColumnInfo(name = "creation_time")
+    val creationTime: Long,
+    val location: String,
+    val latitude: Double,
+    val longitude: Double,
+    @PrimaryKey(autoGenerate = true)
+    val id: Long = 0L
+) {
+    companion object {
+        fun fromTransaction(transaction: Transaction): TransactionEntity {
+            val entity = TransactionEntity(
+                title = transaction.title,
+                type = TRANSACTION_TYPE.valueOf(transaction.type),
+                nominal = transaction.nominal,
+                creationTime = transaction.creationTime,
+                location = transaction.location,
+                latitude = transaction.latitude,
+                longitude = transaction.longitude,
+                id = transaction.id
+            )
+
+            // Log the data before returning the entity
+            Log.d("TransactionEntity", "Converted Transaction to TransactionEntity: $transaction -> $entity")
+
+            return entity
+        }
+    }
+
+    fun toTransaction() = Transaction(title, type.name, nominal, creationTime, location, latitude, longitude, id)
+}
diff --git a/app/src/main/java/com/example/bondoman/lib/error/ErrorResponse.kt b/app/src/main/java/com/example/bondoman/lib/error/ErrorResponse.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a262fb36aa5df85db3a9b2a3fd5cb83e772d3db9
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/lib/error/ErrorResponse.kt
@@ -0,0 +1,5 @@
+package com.example.bondoman.lib.error
+
+data class ErrorResponse(
+    val error: String
+)
diff --git a/app/src/main/java/com/example/bondoman/lib/transaction/Enum.kt b/app/src/main/java/com/example/bondoman/lib/transaction/Enum.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3ecdf82375975b5cad4087a89b8d8f3de7b5df33
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/lib/transaction/Enum.kt
@@ -0,0 +1,6 @@
+package com.example.bondoman.lib.transaction
+
+enum class TRANSACTION_TYPE {
+    PEMBELIAN,
+    PEMASUKAN
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/network/ConnectivityObserver.kt b/app/src/main/java/com/example/bondoman/network/ConnectivityObserver.kt
new file mode 100644
index 0000000000000000000000000000000000000000..335e9d1d07aee2f696c82eefc5ac7a200e009563
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/network/ConnectivityObserver.kt
@@ -0,0 +1,14 @@
+package com.example.bondoman.network
+
+import kotlinx.coroutines.flow.Flow
+
+interface ConnectivityObserver {
+
+    fun observe(): Flow<Status>
+
+    fun isConnected(): Boolean
+
+    enum class Status {
+        Available, Unavailable, Losing, Lost
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/network/NetworkConnectivityObserver.kt b/app/src/main/java/com/example/bondoman/network/NetworkConnectivityObserver.kt
new file mode 100644
index 0000000000000000000000000000000000000000..defa69ef6e072f21411b3b6169f1da2efb66c2d6
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/network/NetworkConnectivityObserver.kt
@@ -0,0 +1,66 @@
+package com.example.bondoman.network
+
+import android.content.Context
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.launch
+
+class NetworkConnectivityObserver (
+    private val context: Context
+) : ConnectivityObserver {
+
+    private val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+
+    override fun observe(): Flow<ConnectivityObserver.Status> {
+        return callbackFlow {
+
+            val network = connectivityManager.activeNetwork
+
+            val capabilities = connectivityManager.getNetworkCapabilities(network)
+
+            if (capabilities != null && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+                launch { send(ConnectivityObserver.Status.Available) }
+            } else {
+                launch { send(ConnectivityObserver.Status.Unavailable) }
+            }
+
+            val callback = object : ConnectivityManager.NetworkCallback() {
+                override fun onAvailable(network: Network) {
+                    super.onAvailable(network)
+                    launch { send(ConnectivityObserver.Status.Available) }
+                }
+
+                override fun onLosing(network: Network, maxMsToLive: Int) {
+                    super.onLosing(network, maxMsToLive)
+                    launch { send(ConnectivityObserver.Status.Losing) }
+                }
+
+                override fun onLost(network: Network) {
+                    super.onLost(network)
+                    launch { send(ConnectivityObserver.Status.Lost) }
+                }
+
+                override fun onUnavailable() {
+                    super.onUnavailable()
+                    launch { send(ConnectivityObserver.Status.Unavailable) }
+                }
+            }
+
+            connectivityManager.registerDefaultNetworkCallback(callback)
+            awaitClose{
+                connectivityManager.unregisterNetworkCallback(callback)
+            }
+        }.distinctUntilChanged()
+    }
+    override fun isConnected(): Boolean {
+        val network = connectivityManager.activeNetwork
+        val capabilities = connectivityManager.getNetworkCapabilities(network)
+        return capabilities != null && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/receiver/MyBroadcastListener.kt b/app/src/main/java/com/example/bondoman/receiver/MyBroadcastListener.kt
new file mode 100644
index 0000000000000000000000000000000000000000..44588d5aeb891fc348a4633ca0a92bfc1cc7291c
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/receiver/MyBroadcastListener.kt
@@ -0,0 +1,5 @@
+package com.example.bondoman.receiver
+
+interface MyBroadcastListener {
+    fun onBroadcastReceived(value: String?)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/receiver/MyBroadcastReceiver.kt b/app/src/main/java/com/example/bondoman/receiver/MyBroadcastReceiver.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f72726000d235734e5810840d5f919b2800877f7
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/receiver/MyBroadcastReceiver.kt
@@ -0,0 +1,11 @@
+package com.example.bondoman.receiver
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+
+class MyBroadcastReceiver(private val listener: MyBroadcastListener) : BroadcastReceiver() {
+    override fun onReceive(context: Context, intent: Intent) {
+        listener.onBroadcastReceived(intent.action.toString())
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/service/auth/TokenExpApp.kt b/app/src/main/java/com/example/bondoman/service/auth/TokenExpApp.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1ec12989bc5f0b9c5972a611b8f16f4d2ac766d0
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/service/auth/TokenExpApp.kt
@@ -0,0 +1,25 @@
+package com.example.bondoman.service.auth
+
+import android.app.Application
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.content.Context
+import android.os.Build
+
+class TokenExpApp: Application() {
+
+    private val channelId = "token_check_running_channel"
+
+    override fun onCreate() {
+        super.onCreate()
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            val channel = NotificationChannel(
+                channelId,
+                "Running Token Expiration Checking",
+                NotificationManager.IMPORTANCE_DEFAULT
+            )
+            val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+            notificationManager.createNotificationChannel(channel)
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/service/auth/TokenExpService.kt b/app/src/main/java/com/example/bondoman/service/auth/TokenExpService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..de3d1626548d33c95727d4ac22a53bcdd5715837
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/service/auth/TokenExpService.kt
@@ -0,0 +1,106 @@
+package com.example.bondoman.service.auth
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+import android.util.Log
+import com.example.bondoman.common.response.ResponseContract
+import com.example.bondoman.core.repository.auth.token.TokenRepository
+import com.example.bondoman.network.ConnectivityObserver
+import com.example.bondoman.network.NetworkConnectivityObserver
+import com.example.bondoman.share_preference.PreferenceManager
+import com.example.bondoman.ui.login.LoginActivity
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+class TokenExpService : Service() {
+
+    private val notificationId = 123
+    private val channelId = "token_check_running_channel"
+
+    private lateinit var preferenceManager: PreferenceManager
+
+    private lateinit var tokenRepository: TokenRepository
+    private lateinit var connectivityObserver: ConnectivityObserver
+
+    private val job = Job()
+    private val serviceScope = CoroutineScope(Dispatchers.Default + job)
+    override fun onBind(intent: Intent?): IBinder? {
+        return null
+    }
+
+    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+        when(intent?.action) {
+            Actions.START.toString() -> start()
+            Actions.STOP.toString() -> stopSelf()
+        }
+        return super.onStartCommand(intent, flags, startId)
+    }
+
+    override fun onCreate() {
+        super.onCreate()
+
+        preferenceManager = PreferenceManager(this)
+        tokenRepository = TokenRepository()
+        connectivityObserver = NetworkConnectivityObserver(applicationContext)
+    }
+
+    enum class Actions {
+        START, STOP
+    }
+
+    private fun start() {
+        val token = preferenceManager.getToken()
+
+        Log.d("Token Exp Service", "Start")
+
+        if (!token.isNullOrEmpty()) {
+            serviceScope.launch {
+
+                val isLogin = preferenceManager.isLogin()
+
+                if(isLogin) {
+                    Log.d("Token Exp Service", "Start Timer")
+                    delay(300000)
+                    if (connectivityObserver.isConnected()) {
+                        redirectionChecking(token)
+                    } else {
+                        Log.d("Token Exp Service", "No network")
+                        connectivityObserver.observe().collect { status ->
+                            if (status == ConnectivityObserver.Status.Available) {
+                                redirectionChecking(token)
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+//        val notification = NotificationCompat.Builder(this, channelId)
+//            .setSmallIcon(R.drawable.ic_launcher_foreground)
+//            .setContentTitle("Token Check Service Is Active")
+//            .setContentText("Checking JWT Token Expiration")
+//            .build()
+//
+//        startForeground(notificationId, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC)
+    }
+
+    private suspend fun redirectionChecking(token: String) {
+        val response = tokenRepository.getToken("Bearer $token")
+
+        if (response is ResponseContract.Error) {
+            preferenceManager.removePref()
+            val intent = Intent(applicationContext, LoginActivity::class.java)
+            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+            startActivity(intent)
+        }
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        job.cancel()
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/share_preference/PreferenceManager.kt b/app/src/main/java/com/example/bondoman/share_preference/PreferenceManager.kt
new file mode 100644
index 0000000000000000000000000000000000000000..df7bd0f324cd2a1792baf4712f88920ef1a486f2
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/share_preference/PreferenceManager.kt
@@ -0,0 +1,46 @@
+package com.example.bondoman.share_preference
+
+import android.content.Context
+import android.content.SharedPreferences
+
+class PreferenceManager (var context: Context) {
+    val PRIVATE_MODE = 0
+
+    private val PREF_NAME = "SharedPreferences"
+    private val IS_LOGIN = "is_login"
+
+    var pref:SharedPreferences = context.getSharedPreferences(PREF_NAME, PRIVATE_MODE)
+    var editor:SharedPreferences.Editor = pref.edit()
+
+    fun setLogin() {
+        editor.putBoolean(IS_LOGIN, true)
+        editor.commit()
+    }
+
+    fun setToken(token: String) {
+        editor.putString("token", token)
+        editor.commit()
+    }
+
+    fun isLogin(): Boolean {
+        return pref.getBoolean(IS_LOGIN, false)
+    }
+
+    fun getToken(): String? {
+        return pref.getString("token", "")
+    }
+
+    fun removePref() {
+        editor.clear()
+        editor.commit()
+    }
+
+    fun setEmail(email: String?) {
+        editor.putString("email", email)
+        editor.commit()
+    }
+
+    fun getEmail(): String? {
+        return pref.getString("email", "")
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/graph/GraphFragment.kt b/app/src/main/java/com/example/bondoman/ui/graph/GraphFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..371c343f8fa313ab63564944e36fa356aa05b55c
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/graph/GraphFragment.kt
@@ -0,0 +1,74 @@
+package com.example.bondoman.ui.graph
+
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import com.anychart.AnyChart
+import com.anychart.AnyChartView
+import com.anychart.chart.common.dataentry.DataEntry
+import com.anychart.chart.common.dataentry.ValueDataEntry
+import com.anychart.charts.Pie
+import com.example.bondoman.databinding.FragmentGraphBinding
+import kotlinx.coroutines.launch
+
+class GraphFragment: Fragment() {
+
+    private lateinit var anyChartView: AnyChartView;
+
+    private var _binding: FragmentGraphBinding? = null
+
+    private lateinit var graphViewModel: GraphViewModel
+
+    private var pie: Pie? = null
+
+    private val binding get() = _binding!!
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        graphViewModel = ViewModelProvider(this).get(GraphViewModel::class.java)
+
+        _binding = FragmentGraphBinding.inflate(inflater, container, false)
+        val root: View = binding.root
+
+        anyChartView = binding.graphChartFragment
+        pie= AnyChart.pie()
+
+
+        return root
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        lifecycleScope.launch {
+            val (pemasukan, pembelian) = graphViewModel.getCountTypeData()
+            Log.d("Graph Fragment", "$pemasukan, $pembelian")
+            updateChart(pemasukan, pembelian)
+        }
+
+    }
+
+    private fun updateChart(pemasukanCount: Int, pembelianCount: Int){
+        Log.d("Graph Fragment", "$pemasukanCount and $pembelianCount")
+        val dataEntries: List<DataEntry> = listOf(
+            ValueDataEntry("Pemasukan", pemasukanCount),
+            ValueDataEntry("Pembelian", pembelianCount)
+        )
+
+
+        pie!!.data(dataEntries)
+        anyChartView.setChart(pie)
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/graph/GraphViewModel.kt b/app/src/main/java/com/example/bondoman/ui/graph/GraphViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7782fd7af20537d5c9dbe49e6f403ffa9a6e73b0
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/graph/GraphViewModel.kt
@@ -0,0 +1,36 @@
+package com.example.bondoman.ui.graph
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import com.example.bondoman.core.repository.TransactionRepository
+import com.example.bondoman.core.usecase.AddTransaction
+import com.example.bondoman.core.usecase.GetAllTransaction
+import com.example.bondoman.core.usecase.GetTransaction
+import com.example.bondoman.core.usecase.GetTransactionTypeCount
+import com.example.bondoman.core.usecase.RemoveTransaction
+import com.example.bondoman.framework.RoomTransactionDataSource
+import com.example.bondoman.framework.UseCases
+import com.example.bondoman.lib.transaction.TRANSACTION_TYPE
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+class GraphViewModel(application: Application):AndroidViewModel(application) {
+
+    val repository = TransactionRepository(RoomTransactionDataSource(application))
+
+    val useCases = UseCases(
+        AddTransaction(repository),
+        GetTransaction(repository),
+        GetAllTransaction(repository),
+        RemoveTransaction(repository),
+        GetTransactionTypeCount(repository)
+    )
+
+    suspend fun getCountTypeData(): Pair<Int, Int>{
+        return withContext(Dispatchers.Default) {
+            val pemasukanCount = useCases.getTransactionTypeCount(TRANSACTION_TYPE.PEMASUKAN)
+            val pembelianCount = useCases.getTransactionTypeCount(TRANSACTION_TYPE.PEMBELIAN)
+            Pair(pemasukanCount, pembelianCount)
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/login/LoginActivity.kt b/app/src/main/java/com/example/bondoman/ui/login/LoginActivity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..81814ee994dd8eae2ea3a673091de052cbde10d0
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/login/LoginActivity.kt
@@ -0,0 +1,165 @@
+package com.example.bondoman.ui.login
+
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import com.example.bondoman.MainActivity
+import com.example.bondoman.api.auth.login.dto.LoginRequest
+import com.example.bondoman.databinding.ActivityLoginBinding
+import com.example.bondoman.network.ConnectivityObserver
+import com.example.bondoman.network.NetworkConnectivityObserver
+import com.example.bondoman.service.auth.TokenExpService
+import com.example.bondoman.share_preference.PreferenceManager
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class LoginActivity : AppCompatActivity() {
+
+    private lateinit var binding: ActivityLoginBinding
+    private lateinit var preferenceManager: PreferenceManager
+
+    private lateinit var connectivityObserver: ConnectivityObserver
+    private var alertDialog: AlertDialog? = null
+
+    private val emailPattern = "[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}".toRegex()
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        binding = ActivityLoginBinding.inflate(layoutInflater)
+        setContentView(binding.root)
+
+        val viewModel = ViewModelProvider(this).get(LoginViewModel::class.java)
+
+        preferenceManager = PreferenceManager(this)
+
+        connectivityObserver = NetworkConnectivityObserver(applicationContext)
+
+        binding.button2.setOnClickListener {
+            binding.button2.isEnabled = false
+            val email = binding.editTextTextEmailAddress.text.toString()
+            val password = binding.editTextTextPassword.text.toString()
+
+            if(email.isEmpty() || email == "") {
+                binding.editTextTextEmailAddress.error = "Email is required"
+                binding.editTextTextEmailAddress.requestFocus()
+                binding.button2.isEnabled = true
+                return@setOnClickListener
+            } else if (!email.matches(emailPattern)) {
+                binding.editTextTextEmailAddress.error = "Invalid email format"
+                binding.editTextTextEmailAddress.requestFocus()
+                binding.button2.isEnabled = true
+                return@setOnClickListener
+            }
+
+            if(password.isEmpty() || password == "") {
+                binding.editTextTextPassword.error = "Password is required"
+                binding.editTextTextPassword.requestFocus()
+                binding.button2.isEnabled = true
+                return@setOnClickListener
+            }
+
+            if(password.length < 8) {
+                binding.editTextTextPassword.error = "Password must contain at least 8 character(s)"
+                binding.editTextTextPassword.requestFocus()
+                binding.button2.isEnabled = true
+                return@setOnClickListener
+            }
+
+            if(!connectivityObserver.isConnected()) {
+                Toast.makeText(this@LoginActivity, "Please connect to a network", Toast.LENGTH_SHORT).show()
+                binding.button2.isEnabled = true
+                return@setOnClickListener
+            }
+
+            val loginRequest = LoginRequest(email, password)
+
+            Log.d("Login", loginRequest.email.toString())
+            Log.d("Login", loginRequest.password.toString())
+            viewModel.login(loginRequest)
+
+            preferenceManager.setEmail(loginRequest.email.toString())
+        }
+
+
+        viewModel.loginResponse.observe(this, Observer { res ->
+            Log.d("Login", res.toString())
+            preferenceManager.setToken(res.token)
+            preferenceManager.setLogin()
+
+            Intent(applicationContext, TokenExpService::class.java).also {
+                it.action = TokenExpService.Actions.START.toString()
+                startService(it)
+            }
+
+            Toast.makeText(this@LoginActivity, "Login Successful", Toast.LENGTH_SHORT).show()
+            startActivity(Intent(this@LoginActivity, MainActivity::class.java))
+            finish()
+
+            binding.button2.isEnabled = true
+        })
+
+        viewModel.errorMessage.observe(this, Observer { res ->
+            Log.d("Login", res.toString())
+            binding.button2.isEnabled = true
+            if (res.toString() == "Invalid email") {
+                binding.editTextTextEmailAddress.error = res.toString()
+                binding.editTextTextPassword.setText("")
+                binding.editTextTextEmailAddress.requestFocus()
+                binding.editTextTextPassword.error = null
+            } else if (res.toString() == "Invalid password") {
+                binding.editTextTextPassword.error = res.toString()
+                binding.editTextTextPassword.requestFocus()
+            }
+
+            binding.button2.isEnabled = true
+
+        })
+    }
+
+    override fun onStart() {
+        super.onStart()
+        lifecycleScope.launch {
+            observeConnectivity()
+        }
+    }
+
+    private fun observeConnectivity() {
+        val scope = CoroutineScope(Dispatchers.Main)
+        scope.launch {
+            connectivityObserver.observe().collect { status ->
+                if (status == ConnectivityObserver.Status.Unavailable || status == ConnectivityObserver.Status.Lost) {
+                    showNoInternetPopUp()
+                } else {
+                    hideNoInternetPopup()
+                }
+            }
+        }
+    }
+
+    private fun showNoInternetPopUp() {
+        if (!isFinishing && alertDialog == null) {
+            alertDialog = AlertDialog.Builder(this)
+                .setTitle("No Internet Connection")
+                .setMessage("Please check your internet connection and try again.")
+                .setCancelable(false)
+                .setPositiveButton("OK") { dialog, _ ->
+                    dialog.dismiss()
+                }
+                .show()
+        }
+    }
+
+    private fun hideNoInternetPopup() {
+        alertDialog?.dismiss()
+        alertDialog = null
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/login/LoginViewModel.kt b/app/src/main/java/com/example/bondoman/ui/login/LoginViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..51c8466031e595dc1a718b1f40307fc650c69054
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/login/LoginViewModel.kt
@@ -0,0 +1,40 @@
+package com.example.bondoman.ui.login
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.viewModelScope
+import com.example.bondoman.api.auth.login.dto.LoginRequest
+import com.example.bondoman.api.auth.login.dto.LoginResponse
+import com.example.bondoman.common.response.ResponseContract
+import com.example.bondoman.core.repository.auth.login.LoginRepository
+import kotlinx.coroutines.launch
+
+class LoginViewModel(application: Application):AndroidViewModel(application) {
+    private val _loginResponse = MutableLiveData<LoginResponse>()
+
+    val loginResponse:LiveData<LoginResponse> = _loginResponse
+
+    private val loginRepository = LoginRepository()
+
+    private val _errorMessage = MutableLiveData<String>()
+
+    val errorMessage:LiveData<String> = _errorMessage
+
+
+    fun login(req: LoginRequest) {
+        viewModelScope.launch {
+
+            when (val result = loginRepository.login(req)) {
+                is ResponseContract.Success<*> -> {
+                    _loginResponse.value = (result.response as LoginResponse?)
+                }
+
+                is ResponseContract.Error -> {
+                    _errorMessage.value = result.response
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/network/NetworkOfflineFragment.kt b/app/src/main/java/com/example/bondoman/ui/network/NetworkOfflineFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f0630fa5d2a7fb799dedf2207dd476758483b044
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/network/NetworkOfflineFragment.kt
@@ -0,0 +1,13 @@
+package com.example.bondoman.ui.network
+
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import com.example.bondoman.R
+
+class NetworkOfflineFragment : Fragment(R.layout.fragment_network_offline) {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/notifications/NotificationsFragment.kt b/app/src/main/java/com/example/bondoman/ui/notifications/NotificationsFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..8898f965332b6ba83e70b26f73dd60c728272851
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/notifications/NotificationsFragment.kt
@@ -0,0 +1,42 @@
+package com.example.bondoman.ui.notifications
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.example.bondoman.databinding.FragmentNotificationsBinding
+
+class NotificationsFragment : Fragment() {
+
+    private var _binding: FragmentNotificationsBinding? = null
+
+    // This property is only valid between onCreateView and
+    // onDestroyView.
+    private val binding get() = _binding!!
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        val notificationsViewModel =
+            ViewModelProvider(this).get(NotificationsViewModel::class.java)
+
+        _binding = FragmentNotificationsBinding.inflate(inflater, container, false)
+        val root: View = binding.root
+
+        val textView: TextView = binding.textNotifications
+        notificationsViewModel.text.observe(viewLifecycleOwner) {
+            textView.text = it
+        }
+        return root
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/notifications/NotificationsViewModel.kt b/app/src/main/java/com/example/bondoman/ui/notifications/NotificationsViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7ef4fbfbd21de46bc1f9672e03e250f7b25f1e1c
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/notifications/NotificationsViewModel.kt
@@ -0,0 +1,13 @@
+package com.example.bondoman.ui.notifications
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+
+class NotificationsViewModel : ViewModel() {
+
+    private val _text = MutableLiveData<String>().apply {
+        value = "This is notifications Fragment"
+    }
+    val text: LiveData<String> = _text
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/result/ResultAdapter.kt b/app/src/main/java/com/example/bondoman/ui/result/ResultAdapter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..61afb12128baeba993db935a9b37f2ac7555d4a8
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/result/ResultAdapter.kt
@@ -0,0 +1,45 @@
+package com.example.bondoman.ui.result
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.example.bondoman.core.data.Item
+import com.example.bondoman.databinding.ItemScanBinding
+import com.example.bondoman.databinding.ItemTransactionBinding
+import java.text.NumberFormat
+import java.util.Locale
+
+class ResultAdapter(var items: ArrayList<Item>): RecyclerView.Adapter<ResultAdapter.ResultHolder>() {
+
+    inner class ResultHolder(val binding: ItemScanBinding): RecyclerView.ViewHolder(binding.root) {
+        fun bind(get: Item) {
+            binding.NameText.text = get.name
+            binding.AmountText.text = get.qty.toString()
+
+            val price = get.price.toString().toDouble()
+            val normalized = (price * 1000).toLong()
+            val formatter = NumberFormat.getInstance(Locale.getDefault())
+            val formattedNumber = "Rp " + formatter.format(normalized)
+            binding.NominalText.text = formattedNumber
+        }
+    }
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ResultHolder {
+        val binding = ItemScanBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+        return ResultHolder(binding)
+    }
+
+    override fun getItemCount(): Int {
+        return items.size
+    }
+
+    override fun onBindViewHolder(holder: ResultHolder, position: Int) {
+        holder.bind(items[position])
+    }
+
+    fun updateItems(newItems: ArrayList<Item>) {
+        items.clear()
+        items.addAll(newItems)
+        notifyDataSetChanged()
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/result/ResultFragment.kt b/app/src/main/java/com/example/bondoman/ui/result/ResultFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..041c2a4ee8aef76be1e5c2b5530ec84bab629219
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/result/ResultFragment.kt
@@ -0,0 +1,92 @@
+package com.example.bondoman.ui.result
+
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import androidx.navigation.Navigation
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.example.bondoman.core.data.Item
+import com.example.bondoman.core.data.ParcelableItem
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.databinding.FragmentResultBinding
+
+class ResultFragment : Fragment() {
+
+    private var _binding: FragmentResultBinding? = null
+
+    private val binding get() = _binding!!
+    private val viewModel: ResultViewModel by viewModels()
+
+    private val resultAdapter = ResultAdapter(arrayListOf())
+
+    private var tempTransaction = Transaction("", "", 0L, 0L, "",0.0,0.0)
+
+    private lateinit var items: List<ParcelableItem>
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        binding.uploadRecyclerView.apply {
+            layoutManager = LinearLayoutManager(context)
+            adapter = resultAdapter
+        }
+
+        arguments?.let{
+            items = ResultFragmentArgs.fromBundle(it).items.toList()
+            val temp = ArrayList<Item>()
+            var sum = 0.0
+
+            items.forEach(){
+                temp.add(Item(it))
+                val price = Item(it).price.toString().toDouble()
+                val normalized = (price * 1000).toLong()
+                sum += normalized
+            }
+            val time:Long = System.currentTimeMillis()
+            tempTransaction.location = ""
+            tempTransaction.latitude = 0.0
+            tempTransaction.longitude = 0.0
+            tempTransaction.title = "Transaction Scanned"
+            tempTransaction.type = "PEMBELIAN"
+            tempTransaction.nominal = sum.toLong()
+            tempTransaction.creationTime = time
+
+            Log.d("Result Fragment", items.toString())
+            resultAdapter.updateItems(temp)
+        }
+
+        binding.uploadResultButtonReject.setOnClickListener {
+            viewModel.saveTransaction(tempTransaction)
+            val action = ResultFragmentDirections.actionResultFragmentToNavigationHome()
+            Navigation.findNavController(binding.uploadRecyclerView).navigate(action)
+        }
+
+        binding.uploadResultButtonAccept.setOnClickListener {
+            val action = ResultFragmentDirections.actionResultFragmentToNavigationHome()
+            Navigation.findNavController(binding.uploadRecyclerView).navigate(action)
+        }
+    }
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        _binding = FragmentResultBinding.inflate(inflater, container, false)
+        val root: View = binding.root
+
+        return root
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/result/ResultViewModel.kt b/app/src/main/java/com/example/bondoman/ui/result/ResultViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1828e83a979c97e4ca319d5c79bb3087a248b345
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/result/ResultViewModel.kt
@@ -0,0 +1,57 @@
+package com.example.bondoman.ui.result
+
+import android.app.Application
+import android.util.Log
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.core.repository.TransactionRepository
+import com.example.bondoman.core.usecase.AddTransaction
+import com.example.bondoman.core.usecase.GetAllTransaction
+import com.example.bondoman.core.usecase.GetTransaction
+import com.example.bondoman.core.usecase.GetTransactionTypeCount
+import com.example.bondoman.core.usecase.RemoveTransaction
+import com.example.bondoman.framework.RoomTransactionDataSource
+import com.example.bondoman.framework.UseCases
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class ResultViewModel(application: Application) : AndroidViewModel(application){
+    private val coroutineScope = CoroutineScope(Dispatchers.IO)
+
+    val repository = TransactionRepository(RoomTransactionDataSource(application))
+
+    val useCases = UseCases(
+        AddTransaction(repository),
+        GetTransaction(repository),
+        GetAllTransaction(repository),
+        RemoveTransaction(repository),
+        GetTransactionTypeCount(repository)
+    )
+
+    var saved = MutableLiveData<Boolean>()
+    val currentTransaction = MutableLiveData<Transaction?>()
+
+    fun saveTransaction(transaction: Transaction) {
+        coroutineScope.launch {
+            useCases.addTransaction(transaction)
+            Log.d("chane", "Observer triggered with yippie")
+            saved.postValue(true)
+        }
+    }
+
+    fun getTransaction(id: Long){
+        coroutineScope.launch {
+            val transaction = useCases.getTransaction(id)
+            currentTransaction.postValue(transaction)
+        }
+    }
+
+    fun deleteTransaction(transaction: Transaction){
+        coroutineScope.launch {
+            useCases.removeTransaction(transaction)
+            saved.postValue(true)
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/settings/SettingsFragment.kt b/app/src/main/java/com/example/bondoman/ui/settings/SettingsFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9388976d73b3319855ef43017951ff1766c12582
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/settings/SettingsFragment.kt
@@ -0,0 +1,275 @@
+package com.example.bondoman.ui.settings
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.os.Environment
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.core.content.FileProvider
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.databinding.FragmentSettingsBinding
+import com.example.bondoman.service.auth.TokenExpService
+import com.example.bondoman.share_preference.PreferenceManager
+import com.example.bondoman.ui.login.LoginActivity
+import org.apache.poi.ss.usermodel.BorderStyle
+import org.apache.poi.ss.usermodel.CellStyle
+import org.apache.poi.ss.usermodel.FillPatternType
+import org.apache.poi.ss.usermodel.HorizontalAlignment
+import org.apache.poi.ss.usermodel.IndexedColors
+import org.apache.poi.ss.usermodel.Sheet
+import org.apache.poi.ss.usermodel.Workbook
+import org.apache.poi.xssf.usermodel.XSSFWorkbook
+import java.io.File
+import java.io.FileOutputStream
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+
+
+class SettingsFragment : Fragment() {
+
+    private var _binding: FragmentSettingsBinding? = null
+
+    // This property is only valid between onCreateView and
+    // onDestroyView.
+    private val binding get() = _binding!!
+
+    private lateinit var viewModel: SettingsViewModel
+
+    private lateinit var preferenceManager: PreferenceManager
+
+    private fun createSheetHeader(cellStyle: CellStyle, sheet: Sheet) {
+        val row = sheet.createRow(0)
+
+        val headerList = listOf("Tanggal", "Kategori", "Nominal", "Nama", "Lokasi")
+
+        for ((index, value) in headerList.withIndex()) {
+            val columnWidth = 15 * 500
+
+            sheet.setColumnWidth(index, columnWidth)
+
+            val cell = row.createCell(index)
+
+            cell?.setCellValue(value)
+
+            cell.cellStyle = cellStyle
+        }
+    }
+
+    private fun addData(
+        rowIndex: Int,
+        transaction: Transaction,
+        cellStyle: CellStyle,
+        sheet: Sheet
+    ) {
+        val row = sheet.createRow(rowIndex)
+
+        // Tanggal
+        val dateCell = row.createCell(0)
+        val dateFormat = SimpleDateFormat("HH:mm:ss yyyy-MM-dd", Locale.getDefault())
+        dateCell?.setCellValue(dateFormat.format(Date(transaction.creationTime)))
+        dateCell.cellStyle = cellStyle
+
+        // Kategori
+        val categoryCell = row.createCell(1)
+        categoryCell?.setCellValue(transaction.type)
+        categoryCell.cellStyle = cellStyle
+
+        // Nominal
+        val nominalCell = row.createCell(2)
+        nominalCell?.setCellValue(transaction.nominal.toString())
+        nominalCell.cellStyle = cellStyle
+
+        // Nama
+        val nameCell = row.createCell(3)
+        nameCell?.setCellValue(transaction.title)
+        nameCell.cellStyle = cellStyle
+
+        // Lokasi
+        val locationCell = row.createCell(4)
+        locationCell.setCellValue(transaction.location)
+        locationCell.cellStyle = cellStyle
+    }
+
+    private fun createWorkbook(): Workbook {
+        val workbook = XSSFWorkbook()
+
+        val dateFormat = SimpleDateFormat("HH-mm-ss-dd-MM-yyyy", Locale.getDefault())
+
+        val sheet: Sheet = workbook.createSheet("Transaksi-" + dateFormat.format(Date()))
+
+        val headerCellStyle = workbook.createCellStyle()
+        headerCellStyle.fillForegroundColor = IndexedColors.SKY_BLUE.index
+        headerCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND)
+        headerCellStyle.setAlignment(HorizontalAlignment.CENTER)
+        headerCellStyle.setBorderTop(BorderStyle.MEDIUM)
+        headerCellStyle.setBorderBottom(BorderStyle.MEDIUM)
+        headerCellStyle.setBorderLeft(BorderStyle.MEDIUM)
+        headerCellStyle.setBorderRight(BorderStyle.MEDIUM)
+
+        createSheetHeader(headerCellStyle, sheet)
+
+        val cellStyle = workbook.createCellStyle()
+        cellStyle.setBorderTop(BorderStyle.MEDIUM)
+        cellStyle.setBorderBottom(BorderStyle.MEDIUM)
+        cellStyle.setBorderLeft(BorderStyle.MEDIUM)
+        cellStyle.setBorderRight(BorderStyle.MEDIUM)
+
+        val transactions = viewModel.transactions.value!!
+
+        transactions.forEachIndexed { index, transaction ->
+            addData(index + 1, transaction, cellStyle, sheet)
+        }
+
+        return workbook
+    }
+
+    private fun saveToExcel() {
+        val workbook = createWorkbook()
+
+        val appDirectory =
+            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
+
+        val dateFormat = SimpleDateFormat("HH-mm-ss-dd-MM-yyyy", Locale.getDefault())
+
+        var fileName = "Transaksi-" + dateFormat.format(Date())
+
+        fileName += if (binding.radioButtonOptionXls.isChecked) {
+            ".xls"
+        } else {
+            ".xlsx"
+        }
+
+        val excelFile = File(appDirectory, fileName)
+
+        try {
+            val fileOut = FileOutputStream(excelFile)
+            workbook.write(fileOut)
+            fileOut.close()
+
+            Toast.makeText(
+                requireContext(),
+                "Spreadsheet saved in $appDirectory/$fileName",
+                Toast.LENGTH_LONG
+            ).show()
+
+            Log.d("Settings Fragment", "Saved successfully in $appDirectory/$fileName")
+        } catch (err: Exception) {
+            Log.d("Settings Fragment", err.toString())
+        }
+    }
+
+    private fun sendEmail() {
+        val workbook = createWorkbook()
+
+        val suffix = if (binding.radioButtonOptionXls.isChecked) {
+            ".xls"
+        } else {
+            ".xlsx"
+        }
+
+        val excelFile = File.createTempFile("Transaksi_", suffix, requireContext().cacheDir)
+
+        try {
+            val fileOut = FileOutputStream(excelFile)
+            workbook.write(fileOut)
+            fileOut.close()
+
+            Log.d("Settings Fragment", "Saved successfully")
+        } catch (err: Exception) {
+            Log.d("Settings Fragment", err.toString())
+        }
+
+        val fileUri: Uri =
+            FileProvider.getUriForFile(requireContext(), "com.example.counter", excelFile)
+
+        var intent = Intent(Intent.ACTION_SEND)
+            .setType("application/excel")
+            .putExtra(Intent.EXTRA_EMAIL, arrayOf(preferenceManager.getEmail().toString()))
+            .putExtra(Intent.EXTRA_SUBJECT, "Data Transaksi")
+            .putExtra(Intent.EXTRA_TEXT, "This email is generated automatically")
+            .putExtra(Intent.EXTRA_STREAM, fileUri)
+            .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+        startActivity(Intent.createChooser(intent, "Send Mail"))
+    }
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        _binding = FragmentSettingsBinding.inflate(inflater, container, false)
+
+        binding.radioButtonOptionXls.isChecked = true
+
+        preferenceManager = context?.let { PreferenceManager(it) }!!
+        val root: View = binding.root
+
+        viewModel = ViewModelProvider(this).get(SettingsViewModel::class.java)
+        viewModel.getTransactions()
+
+        return root
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        System.setProperty(
+            "org.apache.poi.javax.xml.stream.XMLInputFactory",
+            "com.fasterxml.aalto.stax.InputFactoryImpl"
+        )
+        System.setProperty(
+            "org.apache.poi.javax.xml.stream.XMLOutputFactory",
+            "com.fasterxml.aalto.stax.OutputFactoryImpl"
+        )
+        System.setProperty(
+            "org.apache.poi.javax.xml.stream.XMLEventFactory",
+            "com.fasterxml.aalto.stax.EventFactoryImpl"
+        )
+        binding.randomizeButton.setOnClickListener {
+            val intent = Intent("com.example.bondoman.action")
+            intent.putExtra("message", "hello")
+            requireContext().sendBroadcast(intent)
+        }
+
+        // Save spreadsheets
+        binding.settingsButtonSaveSpreadsheet.setOnClickListener {
+            Log.d("Settings Fragment", viewModel.transactions.value.toString())
+
+            saveToExcel()
+        }
+
+        // Send email
+        binding.settingsButtonSendEmail.setOnClickListener {
+            Log.d("Settings Fragment", viewModel.transactions.value.toString())
+
+            sendEmail()
+        }
+
+        // Logout
+        binding.logoutButton.setOnClickListener {
+            preferenceManager.removePref()
+            Intent(requireContext(), TokenExpService::class.java).also {
+                it.action = TokenExpService.Actions.STOP.toString()
+                requireContext().startService(it)
+            }
+            Toast.makeText(context, "Logout Successful", Toast.LENGTH_SHORT).show()
+            startActivity(Intent(requireContext(), LoginActivity::class.java))
+            requireActivity().finish()
+        }
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/settings/SettingsViewModel.kt b/app/src/main/java/com/example/bondoman/ui/settings/SettingsViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..af69e4815d882e19fdadfe59adca5e2cc8170a05
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/settings/SettingsViewModel.kt
@@ -0,0 +1,51 @@
+package com.example.bondoman.ui.settings
+
+import android.app.Application
+import android.util.Log
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.core.repository.TransactionRepository
+import com.example.bondoman.core.usecase.AddTransaction
+import com.example.bondoman.core.usecase.GetAllTransaction
+import com.example.bondoman.core.usecase.GetTransaction
+import com.example.bondoman.core.usecase.GetTransactionTypeCount
+import com.example.bondoman.core.usecase.RemoveTransaction
+import com.example.bondoman.framework.RoomTransactionDataSource
+import com.example.bondoman.framework.UseCases
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+class SettingsViewModel(application: Application) : AndroidViewModel(application) {
+
+    private val coroutineScope = CoroutineScope(Dispatchers.IO)
+
+    val repository = TransactionRepository(RoomTransactionDataSource(application))
+
+    val useCases = UseCases(
+        AddTransaction(repository),
+        GetTransaction(repository),
+        GetAllTransaction(repository),
+        RemoveTransaction(repository),
+        GetTransactionTypeCount(repository),
+    )
+
+    val transactions = MutableLiveData<List<Transaction>>()
+
+    fun getTransactions() {
+        coroutineScope.launch {
+            val transactionList = useCases.getAllTransaction()
+            Log.d("Settings View Model", transactionList.toString())
+            transactions.postValue(transactionList)
+            Log.d("Settings View Model", transactions.value.toString())
+        }
+    }
+
+    fun setTransactions(transactionList: List<Transaction>) {
+        transactions.value = transactionList
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/transaction/TransactionFragment.kt b/app/src/main/java/com/example/bondoman/ui/transaction/TransactionFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f5cdface919a1395ab00909d267df3692b6cfd1e
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/transaction/TransactionFragment.kt
@@ -0,0 +1,314 @@
+package com.example.bondoman.ui.transaction
+
+import android.Manifest
+import android.app.AlertDialog
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.location.Address
+import android.location.Geocoder
+import android.location.Geocoder.GeocodeListener
+import android.location.Location
+import android.location.LocationListener
+import android.location.LocationManager
+import android.net.Uri
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import androidx.core.view.MenuHost
+import androidx.core.view.MenuProvider
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.Observer
+import androidx.navigation.Navigation
+import com.example.bondoman.R
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.databinding.FragmentTransactionBinding
+import com.example.bondoman.lib.transaction.TRANSACTION_TYPE
+
+
+class TransactionFragment : Fragment(), LocationListener, GeocodeListener {
+    private var transactionId = 0L
+    private val viewModel: TransactionViewModel by viewModels()
+    private var currentTransaction = Transaction("", "", 0L, 0L, "",0.0,0.0)
+
+    private var _binding: FragmentTransactionBinding? = null
+    private var isAvailable = false;
+    // This property is only valid between onCreateView and
+    // onDestroyView.
+    private val binding get() = _binding!!
+    private lateinit var curLocation : Location
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        this.isAvailable = false
+    }
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        this.isAvailable = true
+        // Inflate the layout for this fragment
+        _binding = FragmentTransactionBinding.inflate(inflater, container, false)
+        val view = binding.root
+        observeViewModel()
+//        getLocation()
+        getRequest()
+        geocoder = Geocoder(requireContext())
+
+        return view
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        arguments?.let {
+            transactionId = TransactionFragmentArgs.fromBundle(it).transactionID
+            binding.titleView.setText(TransactionFragmentArgs.fromBundle(it).randomTitle)
+        }
+        if(transactionId != 0L) {
+            val menuHost: MenuHost = requireActivity()
+            menuHost.addMenuProvider(object : MenuProvider {
+                override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
+                    // Add menu items here
+                    menuInflater.inflate(R.menu.transaction_menu, menu)
+                }
+
+                override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
+                    // Handle the menu selection
+                    when (menuItem.itemId) {
+                        R.id.deleteTransaction -> {
+                            if (context != null && transactionId != 0L) {
+                                AlertDialog.Builder(context!!)
+                                    .setTitle("Delete Transaction")
+                                    .setMessage("Are you sure you want to delete this transaction?")
+                                    .setPositiveButton("Yes") { dialogInterface, i ->
+                                        viewModel.deleteTransaction(currentTransaction)
+                                    }
+                                    .setNegativeButton("Cancel") { dialogInterface, i -> }
+                                    .create()
+                                    .show()
+                            }
+
+                        }
+                    }
+                    return true
+                }
+            }, viewLifecycleOwner, Lifecycle.State.RESUMED)
+        }
+//        viewModel = ViewModelProvider(this)[TransactionViewModel::class.java]
+
+
+        if(transactionId != 0L){
+            viewModel.getTransaction(transactionId)
+        }
+        binding.updateLocationButton.setOnClickListener{
+            getLocation()
+        }
+        binding.pemasukanButton.setChecked(true)
+        currentTransaction.type = TRANSACTION_TYPE.PEMASUKAN.toString()
+
+        binding.pemasukanButton.setOnClickListener{
+            currentTransaction.type = TRANSACTION_TYPE.PEMASUKAN.toString()
+        }
+        binding.pengeluaranButton.setOnClickListener {
+            currentTransaction.type = TRANSACTION_TYPE.PEMBELIAN.toString()
+        }
+
+
+
+        binding.saveButton.setOnClickListener{
+            if(binding.titleView.text.toString().trim() == ""){
+                binding.titleView.error = "Title is required"
+                binding.titleView.requestFocus()
+                return@setOnClickListener
+            }
+            if(!binding.titleView.text.toString().matches(Regex("[a-zA-Z0-9 _-]*"))){
+                binding.titleView.error = "Title can only be alphanumeric with spaces, -, and _"
+                binding.titleView.requestFocus()
+                return@setOnClickListener
+            }
+            if(binding.titleView.text.toString().length > 255){
+                binding.titleView.error = "Title is maxed at 255 characters"
+                binding.titleView.requestFocus()
+                return@setOnClickListener
+            }
+            if(binding.nominalView.text.toString() ==""){
+                binding.nominalView.error = "Nominal is required"
+                binding.nominalView.requestFocus()
+                return@setOnClickListener
+            }
+            if(binding.nominalView.text.toString().length > 12){
+                binding.nominalView.error = "Nominal is too big"
+                binding.nominalView.requestFocus()
+                return@setOnClickListener
+            }
+            if(!binding.nominalView.text.toString().matches(Regex("[0-9]*"))){
+                binding.nominalView.error = "Nominal must be integer"
+                binding.nominalView.requestFocus()
+                return@setOnClickListener
+            }
+
+            if(binding.titleView.text.toString() != "" && binding.nominalView.text.toString() != "") {
+                val time:Long = System.currentTimeMillis()
+                currentTransaction.location = binding.locationView.text.toString()
+                if(this::curLocation.isInitialized) {
+                    currentTransaction.latitude = curLocation.latitude
+                    currentTransaction.longitude = curLocation.longitude
+                }
+                else{
+                    currentTransaction.latitude = 0.0
+                    currentTransaction.longitude = 0.0
+                }
+                currentTransaction.title =binding.titleView.text.toString().trim()
+                currentTransaction.nominal = binding.nominalView.text.toString().toLong()
+                if(currentTransaction.id == 0L){
+                    currentTransaction.creationTime = time
+                }
+                viewModel.saveTransaction(currentTransaction)
+
+            }
+            Navigation.findNavController(it).popBackStack()
+        }
+        binding.mapsButton.setOnClickListener{
+            if(this::curLocation.isInitialized && binding.locationView.text.toString() != "")
+                openMapsIntent(curLocation.latitude, curLocation.longitude)
+            else{
+                Toast.makeText(context, "No location selected", Toast.LENGTH_SHORT).show()
+            }
+        }
+
+    }
+
+    // on below line creating an open maps intent method.
+    private fun openMapsIntent(lat: Double, lng: Double) {
+        val gmmIntentUri = Uri.parse("http://www.google.com/maps/place/${lat.toString()},${lng.toString()}")
+        val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri)
+//        mapIntent.setPackage("com.google.android.apps.maps")
+//        mapIntent.resolveActivity(requireActivity().packageManager)?.let {
+//            Log.d("aa", " triggered")
+            startActivity(mapIntent)
+//        }
+    }
+    private fun observeViewModel(){
+        viewModel.saved.observe(viewLifecycleOwner, Observer<Boolean> {it->
+            Log.d("Observer", "Observer triggered with yippie")
+            if(it) {
+                Navigation.findNavController(binding.titleView).popBackStack()
+            } else{
+            }
+        }
+        )
+
+        viewModel.currentTransaction.observe(viewLifecycleOwner, Observer{transaction->
+            transaction?.let {
+                currentTransaction = it
+                binding.titleView.setText(it.title, TextView.BufferType.EDITABLE)
+                if(it.type == TRANSACTION_TYPE.PEMASUKAN.toString()){
+                    binding.pemasukanButton.setChecked(true)
+                }
+                if(it.type == TRANSACTION_TYPE.PEMBELIAN.toString()){
+                    binding.pengeluaranButton.setChecked(true)
+                }
+                binding.locationView.setText(it.location, TextView.BufferType.NORMAL)
+                curLocation = Location(it.location)
+                curLocation.latitude = it.latitude
+                curLocation.longitude = it.longitude
+                binding.nominalView.setText(it.nominal.toString(), TextView.BufferType.EDITABLE)
+            }
+
+        })
+    }
+
+    // location stuff
+    private lateinit var locationManager: LocationManager
+    private lateinit var tvGpsLocation: TextView
+    private val locationPermissionCode = 2
+
+    private fun getRequest(){
+        locationManager = context?.getSystemService(Context.LOCATION_SERVICE) as LocationManager
+        if (ContextCompat.checkSelfPermission(requireContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) ==
+            PackageManager.PERMISSION_GRANTED ||
+            ContextCompat.checkSelfPermission(requireContext(), android.Manifest.permission.ACCESS_COARSE_LOCATION) ==
+            PackageManager.PERMISSION_GRANTED) {
+//            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 5f, this)
+        } else {
+            Log.d("ples]aes","request pleasesaesee")
+            ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), locationPermissionCode)
+            Log.d("where","why not here")
+
+            val locationPermissionRequest = registerForActivityResult(
+                ActivityResultContracts.RequestMultiplePermissions()
+            ) { permissions ->
+                when {
+                    permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) -> {
+                        // Precise location access granted.
+                    }
+                    permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) -> {
+                        // Only approximate location access granted.
+                    } else -> {
+                    // No location access granted.
+                    Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT).show()
+                }
+                }
+            }
+        }
+    }
+    private fun getLocation() {
+//        locationManager = context?.getSystemService(Context.LOCATION_SERVICE) as LocationManager
+        if (ContextCompat.checkSelfPermission(requireContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) ==
+            PackageManager.PERMISSION_GRANTED ||
+            ContextCompat.checkSelfPermission(requireContext(), android.Manifest.permission.ACCESS_COARSE_LOCATION) ==
+            PackageManager.PERMISSION_GRANTED) {
+            Toast.makeText(context, "Fetching location...", Toast.LENGTH_SHORT).show()
+            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 5f, this)
+        } else {
+            Toast.makeText(context, "Location not permitted", Toast.LENGTH_SHORT).show()
+        }
+
+    }
+
+
+    override fun onLocationChanged(location: Location) {
+        curLocation = location
+        tvGpsLocation = binding.locationView
+        geocoder.getFromLocation(location.latitude,location.longitude,1, this)
+    }
+
+    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
+        if (requestCode == locationPermissionCode) {
+            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+                Toast.makeText(context, "Permission Granted", Toast.LENGTH_SHORT).show()
+            }
+            else {
+                Toast.makeText(context, "Permission Denied", Toast.LENGTH_SHORT).show()
+            }
+        }
+    }
+
+    // geocode stuff
+
+    private lateinit var geocoder: Geocoder
+    override fun onGeocode(p0: MutableList<Address>) {
+        if(this.isAvailable)
+        tvGpsLocation.text = p0[0].getAddressLine(0).toString()
+    }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/transaction/TransactionViewModel.kt b/app/src/main/java/com/example/bondoman/ui/transaction/TransactionViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..51f5d5aa37e95c387991bdc1b9b9c76db1321822
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/transaction/TransactionViewModel.kt
@@ -0,0 +1,57 @@
+package com.example.bondoman.ui.transaction
+
+import android.app.Application
+import android.util.Log
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.core.repository.TransactionRepository
+import com.example.bondoman.core.usecase.AddTransaction
+import com.example.bondoman.core.usecase.GetAllTransaction
+import com.example.bondoman.core.usecase.GetTransaction
+import com.example.bondoman.core.usecase.GetTransactionTypeCount
+import com.example.bondoman.core.usecase.RemoveTransaction
+import com.example.bondoman.framework.RoomTransactionDataSource
+import com.example.bondoman.framework.UseCases
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class TransactionViewModel(application: Application) : AndroidViewModel(application){
+    private val coroutineScope = CoroutineScope(Dispatchers.IO)
+
+    val repository = TransactionRepository(RoomTransactionDataSource(application))
+
+    val useCases = UseCases(
+        AddTransaction(repository),
+        GetTransaction(repository),
+        GetAllTransaction(repository),
+        RemoveTransaction(repository),
+        GetTransactionTypeCount(repository)
+    )
+
+    var saved = MutableLiveData<Boolean>()
+    val currentTransaction = MutableLiveData<Transaction?>()
+
+    fun saveTransaction(transaction: Transaction) {
+        coroutineScope.launch {
+            useCases.addTransaction(transaction)
+            Log.d("chane", "Observer triggered with yippie")
+            saved.postValue(true)
+        }
+    }
+
+    fun getTransaction(id: Long){
+        coroutineScope.launch {
+            val transaction = useCases.getTransaction(id)
+            currentTransaction.postValue(transaction)
+        }
+    }
+
+    fun deleteTransaction(transaction: Transaction){
+        coroutineScope.launch {
+            useCases.removeTransaction(transaction)
+            saved.postValue(true)
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/transactionlists/ListAction.kt b/app/src/main/java/com/example/bondoman/ui/transactionlists/ListAction.kt
new file mode 100644
index 0000000000000000000000000000000000000000..812e9ef4db34ffb7b954b6c88ac5666d6b7d9758
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/transactionlists/ListAction.kt
@@ -0,0 +1,5 @@
+package com.example.bondoman.ui.transactionlists
+
+interface ListAction {
+    fun onClick(id: Long)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/transactionlists/TransactionMenuAdapter.kt b/app/src/main/java/com/example/bondoman/ui/transactionlists/TransactionMenuAdapter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..52bfe8497e6745c527728ddc58f487acc56d695f
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/transactionlists/TransactionMenuAdapter.kt
@@ -0,0 +1,53 @@
+package com.example.bondoman.ui.transactionlists
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.databinding.ItemTransactionBinding
+import java.text.NumberFormat
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+
+class TransactionMenuAdapter(var transactions : ArrayList<Transaction>, val action: ListAction) : RecyclerView.Adapter<TransactionMenuAdapter.TransactionViewHolder>(){
+
+    inner class TransactionViewHolder(val binding: ItemTransactionBinding):RecyclerView.ViewHolder(binding.root){
+        fun bind(get: Transaction){
+            binding.title.text = get.title
+            binding.content.text = get.type
+            val num = get.nominal.toString().toLong()
+            val formatter = NumberFormat.getInstance(Locale.getDefault())
+            val formattedNumber = "Rp " + formatter.format(num)
+            binding.nominal.text = formattedNumber
+
+            val sdf = SimpleDateFormat("MMM dd, HH:mm:ss")
+            val resultDate = Date(get.creationTime)
+            binding.date.text = "Created:       ${sdf.format(resultDate)}"
+            binding.transactionLayout.setOnClickListener{action.onClick(get.id)}
+            binding.locationText.text = get.location
+        }
+
+    }
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionViewHolder {
+        val binding = ItemTransactionBinding
+            .inflate(LayoutInflater.from(parent.context), parent, false)
+        return TransactionViewHolder(binding)
+    }
+
+    override fun getItemCount(): Int {
+        return transactions.size
+    }
+
+    override fun onBindViewHolder(holder: TransactionViewHolder, position: Int) {
+        holder.bind(transactions[position])
+    }
+
+    fun updateTransactions(newTransactions: List<Transaction>){
+        transactions.clear()
+        transactions.addAll(newTransactions)
+        notifyDataSetChanged()
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/transactionlists/TransactionMenuFragment.kt b/app/src/main/java/com/example/bondoman/ui/transactionlists/TransactionMenuFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c8a5a5b5cf78ba14afe17ad7327386b933f945af
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/transactionlists/TransactionMenuFragment.kt
@@ -0,0 +1,121 @@
+package com.example.bondoman.ui.transactionlists
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.IntentFilter
+import android.os.Build
+import android.os.Bundle
+import android.os.Handler
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Observer
+import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.Navigation
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.example.bondoman.databinding.FragmentListBinding
+import com.example.bondoman.receiver.MyBroadcastListener
+import com.example.bondoman.receiver.MyBroadcastReceiver
+import kotlin.random.Random
+
+
+class TransactionMenuFragment : Fragment(), ListAction, MyBroadcastListener {
+
+    private var _binding: FragmentListBinding? = null
+    private val transactionMenuAdapter = TransactionMenuAdapter(arrayListOf(), this)
+    private lateinit var viewModel: TransactionMenuViewModel
+    private var toggle: Boolean = false
+
+    // This property is only valid between onCreateView and
+    // onDestroyView.
+    private val binding get() = _binding!!
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        _binding = FragmentListBinding.inflate(inflater, container, false)
+        val view = binding.root
+        return view
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        binding.transactionListView.apply {
+            layoutManager = LinearLayoutManager(context)
+            adapter = transactionMenuAdapter
+        }
+
+        binding.addTransaction.setOnClickListener{
+            if(toggle) {
+                val randomNumber = Random.nextInt(1, 101)
+                goToTransactionDetails(0L, "Random transaction $randomNumber")
+                toggle = false
+            }
+                else
+            goToTransactionDetails()}
+
+        viewModel = ViewModelProvider(this).get(TransactionMenuViewModel::class.java)
+
+        observeViewModel()
+    }
+
+    fun observeViewModel() {
+        viewModel.transactions.observe(viewLifecycleOwner, Observer {transactionsList->
+            binding.loadingView.visibility = View.GONE
+            binding.transactionListView.visibility = View.VISIBLE
+            transactionMenuAdapter.updateTransactions(transactionsList.sortedBy { -it.creationTime })
+            if(transactionsList.isEmpty()) {
+                binding.textView2.visibility = View.VISIBLE
+            } else{
+                binding.textView2.visibility = View.INVISIBLE
+            }
+        })
+    }
+
+    override fun onResume() {
+        super.onResume()
+
+        viewModel.getTransactions()
+    }
+
+    private fun goToTransactionDetails(id:Long = 0L, rand:String = ""){
+        val action = TransactionMenuFragmentDirections.actionGoToTransaction(id,rand)
+        Navigation.findNavController(binding.transactionListView).navigate(action)
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+
+    override fun onClick(id: Long) {
+        goToTransactionDetails(id)
+    }
+
+    private lateinit var receiver: BroadcastReceiver
+
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        receiver = MyBroadcastReceiver(this)
+        val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+            ContextCompat.RECEIVER_NOT_EXPORTED
+        } else {
+            0 // For versions below Android 13, there's no export flag
+        }
+        val intentFilter = IntentFilter("com.example.bondoman.action")
+        
+        requireContext().registerReceiver(receiver, intentFilter, Context.RECEIVER_EXPORTED)
+
+    }
+    override fun onBroadcastReceived(value: String?) {
+        Log.d("adsadas", "asdasd")
+        toggle=true
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/transactionlists/TransactionMenuViewModel.kt b/app/src/main/java/com/example/bondoman/ui/transactionlists/TransactionMenuViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a56cbd9aa65733b5aa165e8f07358c8c1059327f
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/transactionlists/TransactionMenuViewModel.kt
@@ -0,0 +1,41 @@
+package com.example.bondoman.ui.transactionlists
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import com.example.bondoman.core.data.Transaction
+import com.example.bondoman.core.repository.TransactionRepository
+import com.example.bondoman.core.usecase.AddTransaction
+import com.example.bondoman.core.usecase.GetAllTransaction
+import com.example.bondoman.core.usecase.GetTransaction
+import com.example.bondoman.core.usecase.RemoveTransaction
+import com.example.bondoman.core.usecase.GetTransactionTypeCount
+import com.example.bondoman.framework.RoomTransactionDataSource
+import com.example.bondoman.framework.UseCases
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class TransactionMenuViewModel(application: Application) : AndroidViewModel(application) {
+
+    private val coroutineScope = CoroutineScope(Dispatchers.IO)
+
+    val repository = TransactionRepository(RoomTransactionDataSource(application))
+
+    val useCases = UseCases(
+        AddTransaction(repository),
+        GetTransaction(repository),
+        GetAllTransaction(repository),
+        RemoveTransaction(repository),
+        GetTransactionTypeCount(repository),
+    )
+
+    val transactions = MutableLiveData<List<Transaction>>()
+
+    fun getTransactions(){
+        coroutineScope.launch {
+            val transactionList = useCases.getAllTransaction()
+            transactions.postValue(transactionList)
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/twibbon/TwibbonFragment.kt b/app/src/main/java/com/example/bondoman/ui/twibbon/TwibbonFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ca167542f1748ff671fba4e97b77b814081015f3
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/twibbon/TwibbonFragment.kt
@@ -0,0 +1,196 @@
+package com.example.bondoman.ui.twibbon
+
+import android.Manifest
+import android.content.ContentValues
+import android.content.pm.PackageManager
+import android.graphics.BitmapFactory
+import android.net.Uri
+import android.os.Bundle
+import android.provider.MediaStore
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCaptureException
+import androidx.camera.core.Preview
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import com.example.bondoman.R
+import com.example.bondoman.databinding.FragmentTwibbonBinding
+import java.text.SimpleDateFormat
+import java.util.Locale
+
+class TwibbonFragment : Fragment() {
+
+    private lateinit var viewModel: TwibbonViewModel
+
+    private var _binding: FragmentTwibbonBinding? = null
+    private val binding get() = _binding!!
+
+    private var imageCapture: ImageCapture? = null
+
+    private var isCapture = false
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        viewModel = ViewModelProvider(this).get(TwibbonViewModel::class.java)
+
+        _binding = FragmentTwibbonBinding.inflate(inflater, container, false)
+
+        return binding.root
+    }
+    private fun allPermisionsGranted() = TwibbonFragment.REQUIRED_PERMISSIONS.all {
+        ContextCompat.checkSelfPermission(
+            requireContext(), it
+        ) == PackageManager.PERMISSION_GRANTED
+    }
+
+    companion object {
+        private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
+        private val REQUIRED_PERMISSIONS = mutableListOf(
+            Manifest.permission.CAMERA
+        ).toTypedArray()
+    }
+
+    private val activityResultLauncher = registerForActivityResult(
+        ActivityResultContracts.RequestMultiplePermissions()
+    ) { permissions ->
+        // Handle Permission granted/rejected
+        var permissionGranted = true
+        permissions.entries.forEach {
+            if (it.key in TwibbonFragment.REQUIRED_PERMISSIONS && !it.value) {
+                permissionGranted = false
+            }
+        }
+        if (!permissionGranted) {
+            Toast.makeText(
+                requireContext(),
+                "Permission request denied",
+                Toast.LENGTH_SHORT
+            ).show()
+        } else {
+            startCamera()
+        }
+    }
+
+
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        if (allPermisionsGranted()) {
+            startCamera()
+        } else {
+            requestPermissions()
+        }
+
+
+        binding.captureButton.setOnClickListener {
+            Log.d("Twibbon Fragment", isCapture.toString())
+            if (isCapture) {
+                binding.imageOverview.visibility = View.GONE
+                startCamera()
+                isCapture = false
+            } else {
+                takePhoto()
+                isCapture = true
+            }
+        }
+    }
+
+    private fun takePhoto() {
+        // Get a stable reference of the modifiable image capture use cases
+        val imageCapture = imageCapture ?: return
+
+        // Create time stamped name and MediaStory entry
+        val name = SimpleDateFormat(TwibbonFragment.FILENAME_FORMAT, Locale.US)
+            .format(System.currentTimeMillis())
+        val contentValues = ContentValues().apply {
+            put(MediaStore.MediaColumns.DISPLAY_NAME, name)
+            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
+        }
+
+        // Create output options object which contains file + metadata
+        val outputOptions = ImageCapture.OutputFileOptions
+            .Builder(
+                requireContext().contentResolver,
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+                contentValues
+            )
+            .build()
+
+        // Set up image capture listener, which is triggered after photo has been taken
+        imageCapture.takePicture(
+            outputOptions,
+            ContextCompat.getMainExecutor(requireContext()),
+            object : ImageCapture.OnImageSavedCallback {
+                override fun onError(exception: ImageCaptureException) {
+                    Log.e("Twibbon Fragment", "Photo capture failed: ${exception.message}", exception)
+                }
+
+                override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
+                    val msg = "Photo captured successfully: ${outputFileResults.savedUri}"
+                    Log.d("Twibbon Fragment", msg)
+                    displayCapturedImage(outputFileResults.savedUri!!)
+                }
+            }
+        )
+    }
+
+    private fun displayCapturedImage(imageUri: Uri) {
+        // Show captured image in imageOverview with twibbon overlay
+        binding.imageOverview.setImageURI(imageUri)
+        binding.imageOverview.visibility = View.VISIBLE
+    }
+
+    private fun requestPermissions() {
+        activityResultLauncher.launch(TwibbonFragment.REQUIRED_PERMISSIONS)
+    }
+    private fun startCamera() {
+        val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
+
+        cameraProviderFuture.addListener({
+            // Bind the lifecycle of cameras to the lifecycle owner
+            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
+
+            // Preview
+            val preview = Preview.Builder()
+                .build()
+                .also {
+                    it.setSurfaceProvider(binding.cameraView.surfaceProvider)
+                }
+
+            imageCapture = ImageCapture.Builder()
+                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
+                .build()
+
+            val twibbonBitmap = BitmapFactory.decodeResource(resources, R.drawable.twibon_pbd)
+
+            binding.twibbonOverlay.setImageBitmap(twibbonBitmap)
+            binding.twibbonOverlay.visibility = View.VISIBLE
+
+            // Select back camera as default
+            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
+
+            try {
+                // Unbind use cases before rebinding
+                cameraProvider.unbindAll()
+
+                // Bind use cases to camera
+                cameraProvider.bindToLifecycle(
+                    this, cameraSelector, preview, imageCapture
+                )
+            } catch (exception: Exception) {
+                Log.e("Twibbon Fragment", "Use case binding failed", exception)
+            }
+        }, ContextCompat.getMainExecutor(requireContext()))
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/twibbon/TwibbonViewModel.kt b/app/src/main/java/com/example/bondoman/ui/twibbon/TwibbonViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d4a015e5d538d7df6e4f0aeb7c3c0b1658934833
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/twibbon/TwibbonViewModel.kt
@@ -0,0 +1,7 @@
+package com.example.bondoman.ui.twibbon
+
+import androidx.lifecycle.ViewModel
+
+class TwibbonViewModel : ViewModel() {
+    // TODO: Implement the ViewModel
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/upload/UploadFragment.kt b/app/src/main/java/com/example/bondoman/ui/upload/UploadFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..415ac6ba395678a6e52ae97f1a5d535c7a0e7e5c
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/upload/UploadFragment.kt
@@ -0,0 +1,276 @@
+package com.example.bondoman.ui.upload
+
+import android.Manifest
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.activity.result.PickVisualMediaRequest
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCaptureException
+import androidx.camera.core.Preview
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.Navigation
+import com.example.bondoman.core.data.Item
+import com.example.bondoman.core.data.ParcelableItem
+import com.example.bondoman.databinding.FragmentHomeBinding
+import com.example.bondoman.share_preference.PreferenceManager
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.MultipartBody
+import java.io.File
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+import okhttp3.RequestBody.Companion.asRequestBody
+import java.io.FileOutputStream
+
+class UploadFragment : Fragment() {
+
+    private var _binding: FragmentHomeBinding? = null
+
+    // This property is only valid between onCreateView and
+    // onDestroyView.
+    private val binding get() = _binding!!
+
+    private lateinit var preferenceManager: PreferenceManager
+
+    private lateinit var viewModel: UploadViewModel
+
+    private lateinit var file: File
+
+    private var imageCapture: ImageCapture? = null
+
+    private lateinit var cameraExecutor: ExecutorService
+
+    private val activityResultLauncher = registerForActivityResult(
+        ActivityResultContracts.RequestMultiplePermissions()
+    ) { permissions ->
+        // Handle Permission granted/rejected
+        var permissionGranted = true
+        permissions.entries.forEach {
+            if (it.key in REQUIRED_PERMISSIONS && !it.value) {
+                permissionGranted = false
+            }
+        }
+        if (!permissionGranted) {
+            Toast.makeText(
+                requireContext(), "Permission request denied", Toast.LENGTH_SHORT
+            ).show()
+        } else {
+            startCamera()
+        }
+    }
+
+    private val pickMedia = registerForActivityResult(
+        ActivityResultContracts.PickVisualMedia()
+    ) { uri ->
+        if (uri != null) {
+            Log.d("Upload Fragment", "Selected uri: $uri")
+
+            val inputStream = requireContext().contentResolver.openInputStream(uri)
+
+            file = File.createTempFile("TEMP_FILE_", ".jpg", requireContext().cacheDir)
+            val outputStream = FileOutputStream(file)
+
+            inputStream!!.use { input ->
+                outputStream.use { output ->
+                    input.copyTo(output)
+                }
+            }
+
+            val mediaType = "image/jpeg"
+
+            val part = MultipartBody.Part.createFormData(
+                "file",
+                file.name,
+                file.asRequestBody(mediaType.toMediaType())
+            )
+
+            val token = preferenceManager.getToken()
+
+            viewModel.upload(token, part)
+        } else {
+            Log.d("Upload Fragment", "No media selected")
+        }
+    }
+
+    private fun goToUploadResultFragment() {
+        val items: Array<Item> = viewModel.items.value!!.items.toTypedArray()
+        val parcelableItem: Array<ParcelableItem> = items.map {
+            ParcelableItem(it.name, it.qty, it.price)
+        }.toTypedArray()
+        val action = UploadFragmentDirections.actionNavigationHomeToResultFragment(parcelableItem)
+        Navigation.findNavController(binding.cameraView).navigate(action)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        // Request camera permissions
+        if (allPermisionsGranted()) {
+            startCamera()
+        } else {
+            requestPermissions()
+        }
+
+        // Set up the listeners to pick image
+        binding.scanImagePickerButton.setOnClickListener {
+            pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
+        }
+
+        // Set up the listeners to take photo
+        binding.imageCaptureButton.setOnClickListener {
+            takePhoto()
+
+            val mediaType = "image/jpeg"
+
+            val part = MultipartBody.Part.createFormData(
+                "file",
+                file.name,
+                file.asRequestBody(mediaType.toMediaType())
+            )
+
+            val token = preferenceManager.getToken()
+
+            viewModel.upload(token, part)
+        }
+
+        viewModel.uploadResponse.observe(viewLifecycleOwner) { res ->
+            Log.d("Upload Fragment", res.toString())
+            viewModel.setItems(res)
+
+            goToUploadResultFragment()
+        }
+
+        viewModel.errorMessage.observe(viewLifecycleOwner) { res ->
+            Log.d("Upload Fragment", res.toString())
+
+            if (res.toString() == "Unauthorized") {
+                Toast.makeText(
+                    requireContext(), "Token has expired, please log in again", Toast.LENGTH_LONG
+                ).show()
+            } else {
+                Toast.makeText(
+                    requireContext(), "Server unreachable, please try again", Toast.LENGTH_LONG
+                ).show()
+            }
+        }
+
+        cameraExecutor = Executors.newSingleThreadExecutor()
+    }
+
+    private fun takePhoto() {
+        // Get a stable reference of the modifiable image capture use cases
+        val imageCapture = imageCapture ?: return
+
+        // Create output options object which contains file + metadata
+        file = File.createTempFile("TEMP_FILE_", ".jpg", requireContext().cacheDir)
+        val outputOptions = ImageCapture.OutputFileOptions.Builder(file).build()
+
+        // Set up image capture listener, which is triggered after photo has been taken
+        imageCapture.takePicture(outputOptions,
+            ContextCompat.getMainExecutor(requireContext()),
+            object : ImageCapture.OnImageSavedCallback {
+                override fun onError(exception: ImageCaptureException) {
+                    Log.e(
+                        "Upload Fragment",
+                        "Photo capture failed: ${exception.message}",
+                        exception
+                    )
+                }
+
+                override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
+                    Log.d("Upload Fragment", file.name)
+                }
+            })
+    }
+
+    private fun startCamera() {
+        val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
+
+        cameraProviderFuture.addListener({
+            // Bind the lifecycle of cameras to the lifecycle owner
+            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
+
+            // Preview
+            val preview = Preview.Builder().build().also {
+                it.setSurfaceProvider(binding.cameraView.surfaceProvider)
+            }
+
+            imageCapture =
+                ImageCapture.Builder().setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
+                    .build()
+
+            // Select back camera as default
+            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
+
+            try {
+                // Unbind use cases before rebinding
+                cameraProvider.unbindAll()
+
+                // Bind use cases to camera
+                cameraProvider.bindToLifecycle(
+                    this, cameraSelector, preview, imageCapture
+                )
+            } catch (exception: Exception) {
+                Log.e("Upload Fragment", "Use case binding failed", exception)
+            }
+        }, ContextCompat.getMainExecutor(requireContext()))
+    }
+
+    private fun requestPermissions() {
+        activityResultLauncher.launch(REQUIRED_PERMISSIONS)
+    }
+
+    private fun allPermisionsGranted() = REQUIRED_PERMISSIONS.all {
+        ContextCompat.checkSelfPermission(
+            requireContext(), it
+        ) == PackageManager.PERMISSION_GRANTED
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        if(::cameraExecutor.isInitialized)
+        cameraExecutor.shutdown()
+    }
+
+    companion object {
+        private val REQUIRED_PERMISSIONS = mutableListOf(
+            Manifest.permission.CAMERA
+        ).apply {
+            add(
+                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+                    Manifest.permission.READ_EXTERNAL_STORAGE
+                } else {
+                    Manifest.permission.READ_MEDIA_IMAGES
+                }
+            )
+        }.toTypedArray()
+    }
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+    ): View {
+        _binding = FragmentHomeBinding.inflate(inflater, container, false)
+        val root: View = binding.root
+
+        preferenceManager = PreferenceManager(requireContext())
+
+        viewModel = ViewModelProvider(this).get(UploadViewModel::class.java)
+
+        return root
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        _binding = null
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoman/ui/upload/UploadViewModel.kt b/app/src/main/java/com/example/bondoman/ui/upload/UploadViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6a7c4bac4962d7a4f88a200ac4ea8f4855229578
--- /dev/null
+++ b/app/src/main/java/com/example/bondoman/ui/upload/UploadViewModel.kt
@@ -0,0 +1,51 @@
+package com.example.bondoman.ui.upload
+
+import android.util.Log
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.bondoman.api.scan.dto.UploadResponse
+import com.example.bondoman.common.response.ResponseContract
+import com.example.bondoman.core.data.Items
+import com.example.bondoman.core.repository.scan.UploadRepository
+import kotlinx.coroutines.launch
+import okhttp3.MultipartBody
+
+class UploadViewModel : ViewModel() {
+
+    private val uploadRepository = UploadRepository()
+
+    private val _uploadResponse = MutableLiveData<UploadResponse>()
+
+    val uploadResponse: LiveData<UploadResponse> = _uploadResponse
+
+    private val _errorMessage = MutableLiveData<String>()
+
+    val errorMessage: LiveData<String> = _errorMessage
+
+    private val _items = MutableLiveData<Items>()
+
+    val items: LiveData<Items> = _items
+
+    fun upload(token: String?, part: MultipartBody.Part) {
+        viewModelScope.launch {
+            when (val result = uploadRepository.upload(token, part)) {
+                is ResponseContract.Success<*> -> {
+                    _uploadResponse.value = (result.response as UploadResponse)
+                    _items.value = _uploadResponse.value!!.items
+                    Log.d("Upload View Model", items.value.toString())
+                }
+
+                is ResponseContract.Error -> {
+                    _errorMessage.value = result.response
+                    Log.d("Upload View Model", _errorMessage.value.toString())
+                }
+            }
+        }
+    }
+
+    fun setItems(res: UploadResponse) {
+        _items.value = res.items
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/baseline_photo_24.xml b/app/src/main/res/drawable/baseline_photo_24.xml
new file mode 100644
index 0000000000000000000000000000000000000000..35960a0bdfe1e4a1a302b1c48a2456af1412bf8f
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_photo_24.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z"/>
+</vector>
diff --git a/app/src/main/res/drawable/baseline_photo_48.xml b/app/src/main/res/drawable/baseline_photo_48.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3ffb603ae5648cde8bf2819ceaaac89e25b20278
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_photo_48.xml
@@ -0,0 +1,5 @@
+<vector android:height="48dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_baseline_auto_graph_24.xml b/app/src/main/res/drawable/ic_baseline_auto_graph_24.xml
new file mode 100644
index 0000000000000000000000000000000000000000..668eef2dc6df57a7c6b3f144f18ac68ff2465d8a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_auto_graph_24.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M14.06,9.94L12,9l2.06,-0.94L15,6l0.94,2.06L18,9l-2.06,0.94L15,12L14.06,9.94zM4,14l0.94,-2.06L7,11l-2.06,-0.94L4,8l-0.94,2.06L1,11l2.06,0.94L4,14zM8.5,9l1.09,-2.41L12,5.5L9.59,4.41L8.5,2L7.41,4.41L5,5.5l2.41,1.09L8.5,9zM4.5,20.5l6,-6.01l4,4L23,8.93l-1.41,-1.41l-7.09,7.97l-4,-4L3,19L4.5,20.5z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_baseline_photo_camera_24.xml b/app/src/main/res/drawable/ic_baseline_photo_camera_24.xml
new file mode 100644
index 0000000000000000000000000000000000000000..43a4fd5fd807687459db4eb1b1783f1064d7162f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_photo_camera_24.xml
@@ -0,0 +1,6 @@
+<vector android:height="24dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
+    <path android:fillColor="@android:color/white" android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_baseline_photo_camera_48.xml b/app/src/main/res/drawable/ic_baseline_photo_camera_48.xml
new file mode 100644
index 0000000000000000000000000000000000000000..48a8a0197aa608129d48ee7a28bcd1eecea7c84d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_photo_camera_48.xml
@@ -0,0 +1,6 @@
+<vector android:height="48dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
+    <path android:fillColor="@android:color/white" android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_baseline_wifi_off_24.xml b/app/src/main/res/drawable/ic_baseline_wifi_off_24.xml
new file mode 100644
index 0000000000000000000000000000000000000000..82c4265238028b57420cfb089d0dd73c270dfb05
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_wifi_off_24.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M22.99,9C19.15,5.16 13.8,3.76 8.84,4.78l2.52,2.52c3.47,-0.17 6.99,1.05 9.63,3.7l2,-2zM18.99,13c-1.29,-1.29 -2.84,-2.13 -4.49,-2.56l3.53,3.53 0.96,-0.97zM2,3.05L5.07,6.1C3.6,6.82 2.22,7.78 1,9l1.99,2c1.24,-1.24 2.67,-2.16 4.2,-2.77l2.24,2.24C7.81,10.89 6.27,11.73 5,13v0.01L6.99,15c1.36,-1.36 3.14,-2.04 4.92,-2.06L18.98,20l1.27,-1.26L3.29,1.79 2,3.05zM9,17l3,3 3,-3c-1.65,-1.66 -4.34,-1.66 -6,0z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cf143d4d5293542cbd9e66f4206bbed06138fdb6
--- /dev/null
+++ b/app/src/main/res/drawable/ic_check.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_create.xml b/app/src/main/res/drawable/ic_create.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1c9bd3e6bda2e7ee0e8fb5151b4b09c4ae0daac4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_create.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_dashboard_black_24dp.xml b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml
new file mode 100644
index 0000000000000000000000000000000000000000..46fc8deec32bb06fedfe594815e568e3a6bf48b9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M3,13h8L11,3L3,3v10zM3,21h8v-6L3,15v6zM13,21h8L21,11h-8v10zM13,3v6h8L21,3h-8z" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml
new file mode 100644
index 0000000000000000000000000000000000000000..de011dd993d89ca80cee876d12cffda825c49a33
--- /dev/null
+++ b/app/src/main/res/drawable/ic_delete.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_home_black_24dp.xml b/app/src/main/res/drawable/ic_home_black_24dp.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f8bb0b55633d3e41228e9e285149af5f1d839d08
--- /dev/null
+++ b/app/src/main/res/drawable/ic_home_black_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000000000000000000000000000000000000..07d5da9cbf141911847041df5d7b87f0dd5ef9d4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillColor="#3DDC84"
+        android:pathData="M0,0h108v108h-108z" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M9,0L9,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,0L19,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,0L29,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,0L39,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,0L49,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,0L59,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,0L69,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,0L79,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M89,0L89,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M99,0L99,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,9L108,9"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,19L108,19"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,29L108,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,39L108,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,49L108,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,59L108,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,69L108,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,79L108,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,89L108,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,99L108,99"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,29L89,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,39L89,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,49L89,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,59L89,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,69L89,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,79L89,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,19L29,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,19L39,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,19L49,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,19L59,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,19L69,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,19L79,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2b068d11462a4b96669193de13a711a3a36220a0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="85.84757"
+                android:endY="92.4963"
+                android:startX="42.9492"
+                android:startY="49.59793"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0" />
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0" />
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000" />
+</vector>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_notifications_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_black_24dp.xml
new file mode 100644
index 0000000000000000000000000000000000000000..78b75c39b55bc3cbbc18bfe7d9165fb3da7d03ff
--- /dev/null
+++ b/app/src/main/res/drawable/ic_notifications_black_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_outline_filter_frames_24.xml b/app/src/main/res/drawable/ic_outline_filter_frames_24.xml
new file mode 100644
index 0000000000000000000000000000000000000000..14e89057b7ca763cc56218c44c067e4552690677
--- /dev/null
+++ b/app/src/main/res/drawable/ic_outline_filter_frames_24.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M20,4h-4l-4,-4 -4,4L4,4c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,20L4,20L4,6h4.52l3.52,-3.5L15.52,6L20,6v14zM6,18h12L18,8L6,8v10zM8,10h8v6L8,16v-6z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..298a5a1ff28c4ce6a5591285f569dc6c827e1b15
--- /dev/null
+++ b/app/src/main/res/drawable/ic_settings.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
+</vector>
diff --git a/app/src/main/res/drawable/twibon_pbd.png b/app/src/main/res/drawable/twibon_pbd.png
new file mode 100644
index 0000000000000000000000000000000000000000..5b08ea07272bc8a7745377226e49c9f49b10e08b
Binary files /dev/null and b/app/src/main/res/drawable/twibon_pbd.png differ
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
new file mode 100644
index 0000000000000000000000000000000000000000..80f541c59644b5fd6af20d683234d84dd907c135
--- /dev/null
+++ b/app/src/main/res/layout/activity_login.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ui.login.LoginActivity">
+
+    <LinearLayout
+        android:layout_width="294dp"
+        android:layout_height="430dp"
+        android:gravity="center"
+        android:orientation="vertical"
+        android:padding="20dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
+
+        <TextView
+            android:id="@+id/textView"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="50dp"
+            android:text="@string/login"
+            android:textSize="30sp"
+            tools:layout_editor_absoluteX="176dp"
+            tools:layout_editor_absoluteY="222dp" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <TextView
+                android:id="@+id/loginEmailLabel"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="5dp"
+                android:text="@string/login_email_label"
+                android:textSize="15sp"
+                tools:layout_editor_absoluteX="176dp"
+                tools:layout_editor_absoluteY="222dp" />
+
+            <EditText
+                android:id="@+id/editTextTextEmailAddress"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="20dp"
+                android:ems="10"
+                android:inputType="textEmailAddress"
+                tools:layout_editor_absoluteX="100dp"
+                tools:layout_editor_absoluteY="279dp" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <TextView
+                android:id="@+id/loginPasswordLabel"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="5dp"
+                android:text="@string/login_password_label"
+                android:textSize="15sp"
+                tools:layout_editor_absoluteX="176dp"
+                tools:layout_editor_absoluteY="222dp" />
+
+            <EditText
+                android:id="@+id/editTextTextPassword"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="8dp"
+                android:ems="10"
+                android:inputType="textPassword"
+                tools:layout_editor_absoluteX="100dp"
+                tools:layout_editor_absoluteY="365dp" />
+        </LinearLayout>
+
+
+        <Button
+            android:id="@+id/button2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/login"
+            tools:layout_editor_absoluteX="160dp"
+            tools:layout_editor_absoluteY="450dp" />
+
+    </LinearLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3b61f05d5c73f5a2748a0dcbfcb6f2496163b5e2
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.google.android.material.bottomnavigation.BottomNavigationView
+        android:id="@+id/nav_view"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/windowBackground"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:menu="@menu/bottom_nav_menu" />
+
+    <fragment
+        android:id="@+id/nav_host_fragment_activity_main"
+        android:name="androidx.navigation.fragment.NavHostFragment"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        app:defaultNavHost="true"
+        app:layout_constraintBottom_toTopOf="@+id/nav_view"
+        app:layout_constraintHorizontal_bias="0.0"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="0.0"
+        app:navGraph="@navigation/mobile_navigation" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_graph.xml b/app/src/main/res/layout/fragment_graph.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fa89eeedc71c13a08dab4e72f7b7c6a4b3934467
--- /dev/null
+++ b/app/src/main/res/layout/fragment_graph.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ui.graph.GraphFragment">
+
+    <com.anychart.AnyChartView
+        android:id="@+id/graph_chart_fragment"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
new file mode 100644
index 0000000000000000000000000000000000000000..784d023c0191f440333652a88625fa18b2ef2a8a
--- /dev/null
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ui.upload.UploadFragment">
+
+    <androidx.camera.view.PreviewView
+        android:id="@+id/camera_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginLeft="50dp"
+        android:layout_marginRight="50dp"
+        android:layout_marginTop="50dp"
+        android:layout_marginBottom="100dp"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <ImageButton
+        android:id="@+id/image_capture_button"
+        android:src="@drawable/ic_baseline_photo_camera_48"
+        android:text="@string/take_photo"
+        android:contentDescription="@string/take_photo"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/camera_view"
+        app:layout_constraintVertical_bias="0.454" />
+
+    <ImageButton
+        android:id="@+id/scan_image_picker_button"
+        android:src="@drawable/baseline_photo_48"
+        android:text="@string/scan_image_picker_button"
+        android:contentDescription="@string/scan_image_picker_button"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginBottom="28dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/image_capture_button"
+        app:layout_constraintHorizontal_bias="0.362"
+        app:layout_constraintStart_toStartOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_list.xml b/app/src/main/res/layout/fragment_list.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d8633213c9f9f0c652f5816a87f595e177080185
--- /dev/null
+++ b/app/src/main/res/layout/fragment_list.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ui.transactionlists.TransactionMenuFragment">
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/transactionListView"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:layout_marginStart="1dp"
+        android:layout_marginTop="1dp"
+        android:layout_marginEnd="1dp"
+        android:layout_marginBottom="1dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <ProgressBar
+        android:id="@+id/loadingView"
+        style="?android:attr/progressBarStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="@+id/transactionListView"
+        app:layout_constraintHorizontal_bias="0.498"
+        app:layout_constraintStart_toStartOf="@+id/transactionListView"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="0.48" />
+
+    <com.google.android.material.floatingactionbutton.FloatingActionButton
+        android:id="@+id/addTransaction"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:clickable="true"
+        android:layout_margin="@dimen/standard_margin"
+        android:src="@drawable/ic_create"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent" />
+
+    <TextView
+        android:id="@+id/textView2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="No transactions yet."
+        android:visibility="invisible"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="@+id/transactionListView" />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_network_offline.xml b/app/src/main/res/layout/fragment_network_offline.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6c1d11f66bac6074d5a9dda490bb7c4ac81b39a2
--- /dev/null
+++ b/app/src/main/res/layout/fragment_network_offline.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center">
+
+        <ImageView
+            android:id="@+id/image_wifi_connection"
+            android:layout_width="54dp"
+            android:layout_height="53dp"
+            android:contentDescription="@string/network_offline_image_description"
+            app:srcCompat="@drawable/ic_baseline_wifi_off_24" />
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:paddingStart="16dp"
+            android:paddingEnd="16dp"
+            android:layout_toEndOf="@+id/image_wifi_connection">
+
+            <TextView
+                android:id="@+id/network_offline_title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/network_offline_title"
+                android:textColor="@color/black"
+                android:textSize="24sp" />
+
+            <TextView
+                android:id="@+id/network_offline_subtitle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/network_offline_subtitle"
+                android:textColor="@color/dark_gray"
+                android:textSize="14sp" />
+
+        </LinearLayout>
+</RelativeLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_notifications.xml b/app/src/main/res/layout/fragment_notifications.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0691d7dc54eb88e4080ca534c07ff907f03aed9c
--- /dev/null
+++ b/app/src/main/res/layout/fragment_notifications.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ui.notifications.NotificationsFragment">
+
+    <TextView
+        android:id="@+id/text_notifications"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="8dp"
+        android:textAlignment="center"
+        android:textSize="20sp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_result.xml b/app/src/main/res/layout/fragment_result.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3eb0527c0371de1bbb493e8fab7ea8aa090baeb8
--- /dev/null
+++ b/app/src/main/res/layout/fragment_result.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/frameLayout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ui.result.ResultFragment">
+
+    <!-- TODO: Update blank fragment layout -->
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/upload_recycler_view"
+        android:layout_width="0dp"
+        android:layout_height="400dp"
+        android:layout_margin="12dp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/upload_result_confirmation_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="65dp"
+        android:text="@string/upload_result_text_view_retake_note"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/upload_recycler_view" />
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="100dp"
+        android:layout_marginTop="44dp"
+        android:orientation="horizontal"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/upload_result_confirmation_text">
+
+        <Button
+            android:id="@+id/upload_result_button_accept"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="50dp"
+            android:text="@string/upload_result_button_yes" />
+
+        <Button
+            android:id="@+id/upload_result_button_reject"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/upload_result_button_no" />
+
+    </LinearLayout>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6fcba9ec68c13ac5f79f6d69a6ed34874da1c7fc
--- /dev/null
+++ b/app/src/main/res/layout/fragment_settings.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ui.settings.SettingsFragment">
+
+    <RadioGroup
+        android:id="@+id/radio_group"
+        android:layout_width="211dp"
+        android:layout_height="94dp"
+        android:layout_marginTop="40dp"
+        android:orientation="vertical"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.11"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
+
+        <RadioButton
+            android:id="@+id/radio_button_option_xls"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/settings_radio_button_xls" />
+
+        <RadioButton
+            android:id="@+id/radio_button_option_xlsx"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/settings_radio_button_xlsx" />
+
+    </RadioGroup>
+
+    <Button
+        android:id="@+id/logout_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/signout"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.072"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/randomizeButton" />
+
+    <Button
+        android:id="@+id/settings_button_send_email"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/settings_button_send_email"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.084"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/settings_button_save_spreadsheet" />
+
+    <Button
+        android:id="@+id/settings_button_save_spreadsheet"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/standard_margin"
+        android:text="@string/settings_button_save_spreadsheets"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.084"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="0.237" />
+
+    <Button
+        android:id="@+id/randomizeButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="RANDOMIZE TRANSACTION"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.132"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/settings_button_send_email" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_transaction.xml b/app/src/main/res/layout/fragment_transaction.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3b779485e3bd5b9594628ce7a700d4e21ffe27a1
--- /dev/null
+++ b/app/src/main/res/layout/fragment_transaction.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ui.transaction.TransactionFragment">
+
+    <EditText
+        android:id="@+id/titleView"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:ems="10"
+        android:hint="Title"
+        android:inputType="text"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <EditText
+        android:id="@+id/locationView"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:ems="10"
+        android:gravity="top|left"
+        android:hint="Location"
+        android:inputType="none"
+        android:focusable="false"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.0"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/nominalView" />
+
+    <com.google.android.material.floatingactionbutton.FloatingActionButton
+        android:id="@+id/saveButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:clickable="true"
+        android:src="@drawable/ic_check"
+        android:layout_margin="@dimen/standard_margin"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent" />
+
+    <EditText
+        android:id="@+id/nominalView"
+        android:layout_width="0dp"
+        android:layout_height="49dp"
+        android:ems="10"
+        android:hint="Nominal"
+        android:inputType="numberDecimal"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.0"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/radioGroup2" />
+
+    <Button
+        android:id="@+id/mapsButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="10dp"
+        android:text="Open In Map"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/locationView" />
+
+    <RadioGroup
+        android:id="@+id/radioGroup2"
+        android:layout_width="0dp"
+        android:layout_height="109dp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.0"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/titleView">
+
+        <RadioButton
+            android:id="@+id/pemasukanButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="Pemasukan" />
+
+        <RadioButton
+            android:id="@+id/pengeluaranButton"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="Pengeluaran" />
+    </RadioGroup>
+
+    <Button
+        android:id="@+id/updateLocationButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="10dp"
+        android:text="Update Location"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/locationView" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_twibbon.xml b/app/src/main/res/layout/fragment_twibbon.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3bec03da119fbc48def8820e9aa0aa7f8eb69eb5
--- /dev/null
+++ b/app/src/main/res/layout/fragment_twibbon.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ui.twibbon.TwibbonFragment">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+    <androidx.camera.view.PreviewView
+        android:id="@+id/camera_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginLeft="50dp"
+        android:layout_marginTop="50dp"
+        android:layout_marginRight="50dp"
+        android:layout_marginBottom="100dp" />
+
+    <ImageView
+        android:id="@+id/image_overview"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone"
+        android:contentDescription="@string/image_overview" />
+
+    <ImageView
+        android:id="@+id/twibbon_overlay"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="fitXY"
+        android:visibility="gone"
+        android:contentDescription="@string/twibbon_overlay" />
+
+    </RelativeLayout>
+
+
+    <ImageButton
+        android:id="@+id/capture_button"
+        android:layout_width="wrap_content"
+        android:layout_gravity="bottom|center_horizontal"
+        android:layout_marginBottom="20dp"
+        android:src="@drawable/ic_baseline_photo_camera_48"
+        android:layout_height="wrap_content"
+        android:contentDescription="@string/camera_image_description"
+        />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_scan.xml b/app/src/main/res/layout/item_scan.xml
new file mode 100644
index 0000000000000000000000000000000000000000..60659a1ca3897d9bb12830a1625588970f83c9b0
--- /dev/null
+++ b/app/src/main/res/layout/item_scan.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/scanLayout"
+    android:layout_width="match_parent"
+    android:layout_height="120dp"
+    android:orientation="vertical"
+    app:cardCornerRadius="5dp"
+    app:cardElevation="2dp"
+    app:cardUseCompatPadding="true">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:padding="@dimen/standard_margin">
+
+        <TextView
+            android:id="@+id/NameText"
+            style="@style/Title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:maxLines="1"
+            android:text="Name"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <TextView
+            android:id="@+id/AmountText"
+            style="@style/Text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="12dp"
+            android:ellipsize="end"
+            android:maxLines="1"
+            android:text="Amount"
+            app:layout_constraintTop_toBottomOf="@+id/NameText"
+            tools:layout_editor_absoluteX="8dp" />
+
+        <TextView
+            android:id="@+id/NominalText"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="4dp"
+            android:text="Nominal"
+            android:textSize="16sp"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.0"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/AmountText" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_transaction.xml b/app/src/main/res/layout/item_transaction.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4b6310b3030aa6868a3953405b4ea19ad299f7ae
--- /dev/null
+++ b/app/src/main/res/layout/item_transaction.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/transactionLayout"
+    android:layout_width="match_parent"
+    android:layout_height="130dp"
+    android:orientation="vertical"
+    app:cardCornerRadius="5dp"
+    app:cardElevation="2dp"
+    app:cardUseCompatPadding="true">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:padding="@dimen/standard_margin">
+
+        <TextView
+            android:id="@+id/title"
+            style="@style/Title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:maxLines="1"
+            android:text="Title"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <TextView
+            android:id="@+id/content"
+            style="@style/Text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:maxLines="1"
+            android:text="Content"
+            app:layout_constraintTop_toBottomOf="@id/title" />
+
+        <TextView
+            android:id="@+id/date"
+            style="@style/Detail"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="Last updated"
+            app:layout_constraintBottom_toBottomOf="parent" />
+
+        <TextView
+            android:id="@+id/nominal"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:text="Nominal"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/content" />
+
+        <TextView
+            android:id="@+id/locationText"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:maxLines="1"
+            android:text="Location"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/nominal" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</androidx.cardview.widget.CardView>
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml
new file mode 100644
index 0000000000000000000000000000000000000000..699818523da27f9d19a932df9055e613c70fef2e
--- /dev/null
+++ b/app/src/main/res/menu/bottom_nav_menu.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:id="@+id/navigation_transactions"
+        android:icon="@drawable/ic_dashboard_black_24dp"
+        android:title="Transactions" />
+
+    <item
+        android:id="@+id/navigation_home"
+        android:icon="@drawable/ic_baseline_photo_camera_24"
+        android:title="@string/title_home" />
+
+    <item
+        android:id="@+id/navigation_twibbon"
+        android:icon="@drawable/ic_outline_filter_frames_24"
+        android:title="Twibbon" />
+
+    <item
+        android:id="@+id/navigation_graph"
+        android:icon="@drawable/ic_baseline_auto_graph_24"
+        android:title="@string/title_graph" />
+
+    <item
+        android:id="@+id/navigation_settings"
+        android:icon="@drawable/ic_settings"
+        android:title="Settings" />
+
+</menu>
\ No newline at end of file
diff --git a/app/src/main/res/menu/transaction_menu.xml b/app/src/main/res/menu/transaction_menu.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7adb9b5a8b42a04415d5f762442bf49e14f3c856
--- /dev/null
+++ b/app/src/main/res/menu/transaction_menu.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+    <item
+        android:id="@+id/deleteTransaction"
+        android:icon="@drawable/ic_delete"
+        app:showAsAction="always"
+        android:title="Delete Transaction"
+        />
+</menu>
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/app/src/main/res/mipmap-anydpi/ic_launcher.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6f3b755bf50c6b03d8714a9c6184705e6a08389f
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi/ic_launcher.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+    <monochrome android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6f3b755bf50c6b03d8714a9c6184705e6a08389f
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+    <monochrome android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000000000000000000000000000000000000..c209e78ecd372343283f4157dcfd918ec5165bb3
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000000000000000000000000000000000000..b2dfe3d1ba5cf3ee31b3ecc1ced89044a1f3b7a9
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000000000000000000000000000000000000..4f0f1d64e58ba64d180ce43ee13bf9a17835fbca
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000000000000000000000000000000000000..62b611da081676d42f6c3f78a2c91e7bcedddedb
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000000000000000000000000000000000000..948a3070fe34c611c42c0d3ad3013a0dce358be0
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000000000000000000000000000000000000..1b9a6956b3acdc11f40ce2bb3f6efbd845cc243f
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000000000000000000000000000000000000..28d4b77f9f036a47549d47db79c16788749dca10
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000000000000000000000000000000000000..9287f5083623b375139afb391af71cc533a7dd37
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000000000000000000000000000000000000..aa7d6427e6fa1074b79ccd52ef67ac15c5637e85
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000000000000000000000000000000000000..9126ae37cbc3587421d6889eadd1d91fbf1994d4
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d5cf940c9a618f8d36917e410b1c5aade198ab8f
--- /dev/null
+++ b/app/src/main/res/navigation/mobile_navigation.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<navigation xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/mobile_navigation"
+    app:startDestination="@+id/navigation_transactions">
+
+    <fragment
+        android:id="@+id/navigation_home"
+        android:name="com.example.bondoman.ui.upload.UploadFragment"
+        android:label="@string/title_home"
+        tools:layout="@layout/fragment_home" >
+        <action
+            android:id="@+id/action_navigation_home_to_resultFragment"
+            app:destination="@id/resultFragment" />
+    </fragment>
+
+    <fragment
+        android:id="@+id/navigation_transactions"
+        android:name="com.example.bondoman.ui.transactionlists.TransactionMenuFragment"
+        android:label="Transactions"
+        tools:layout="@layout/fragment_list" >
+        <action
+            android:id="@+id/actionGoToTransaction"
+
+            app:destination="@id/transactionFragment" />
+    </fragment>
+
+    <fragment
+        android:id="@+id/navigation_graph"
+        android:name="com.example.bondoman.ui.graph.GraphFragment"
+        android:label="@string/title_graph"
+        tools:layout="@layout/fragment_graph" />
+
+    <fragment
+        android:id="@+id/navigation_twibbon"
+        android:name="com.example.bondoman.ui.twibbon.TwibbonFragment"
+        android:label="@string/title_twibbon"
+        tools:layout="@layout/fragment_twibbon" />
+
+    <fragment
+        android:id="@+id/transactionFragment"
+        android:name="com.example.bondoman.ui.transaction.TransactionFragment"
+        android:label="Transaction"
+        tools:layout="@layout/fragment_transaction" >
+        <argument
+            android:name="transactionID"
+            app:argType="long"
+            android:defaultValue="0L" />
+        <argument
+            android:name="randomTitle"
+            app:argType="string"
+            android:defaultValue="" />
+    </fragment>
+    <fragment
+        android:id="@+id/navigation_settings"
+        android:name="com.example.bondoman.ui.settings.SettingsFragment"
+        android:label="Settings"
+        tools:layout="@layout/fragment_settings" />
+    <fragment
+        android:id="@+id/resultFragment"
+        android:name="com.example.bondoman.ui.result.ResultFragment"
+        android:label="Scan Result"
+        tools:layout="@layout/fragment_result" >
+        <argument
+            android:name="items"
+            app:argType="com.example.bondoman.core.data.ParcelableItem[]" />
+        <action
+            android:id="@+id/action_resultFragment_to_navigation_home"
+            app:destination="@id/navigation_home" />
+    </fragment>
+
+</navigation>
\ No newline at end of file
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a1c01f4a6eea8189e2f65ff7e3c4de8750814fca
--- /dev/null
+++ b/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,16 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Base application theme. -->
+    <style name="Theme.BondoMan" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+        <!-- Primary brand color. -->
+        <item name="colorPrimary">@color/purple_200</item>
+        <item name="colorPrimaryVariant">@color/purple_700</item>
+        <item name="colorOnPrimary">@color/black</item>
+        <!-- Secondary brand color. -->
+        <item name="colorSecondary">@color/teal_200</item>
+        <item name="colorSecondaryVariant">@color/teal_200</item>
+        <item name="colorOnSecondary">@color/black</item>
+        <!-- Status bar color. -->
+        <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
+        <!-- Customize your theme here. -->
+    </style>
+</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000000000000000000000000000000000000..49aaaa000cb3c06f02bf388787cac453001699f4
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,11 @@
+<?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="dark_gray">#3b3b3b</color>
+</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000000000000000000000000000000000000..77f5997a0dd20ec319107cc97bd59ce5f7b6b023
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+    <dimen name="standard_margin">8dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6abf047b5ca4fdf8ecdd0a43e5614b0d128d09bb
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,31 @@
+<resources>
+    <string name="app_name">BondoMan</string>
+    <string name="title_home">Home</string>
+    <string name="title_dashboard">Dashboard</string>
+    <string name="title_notifications">Notifications</string>
+    <string name="take_photo">Take a picture</string>
+    <string name="title_graph">Graph</string>
+    <!-- TODO: Remove or change this placeholder text -->
+    <string name="hello_blank_fragment">Hello blank fragment</string>
+    <string name="network_offline_title">No Internet Connection</string>
+    <string name="network_offline_subtitle">Please Reconnect to Internet</string>
+    <string name="network_offline_image_description">Network Offline Image</string>
+    <string name="network_retry_button">Retry</string>
+    <string name="login">Login</string>
+    <string name="login_email_label">Email</string>
+    <string name="signout">Logout</string>
+    <string name="login_password_label">Password</string>
+    <string name="upload_result_text_view_retake_note">Retake Note?</string>
+    <string name="upload_result_button_yes">Yes</string>
+    <string name="upload_result_button_no">No</string>
+    <string name="settings_radio_button_xls">xls</string>
+    <string name="settings_radio_button_xlsx">xlsx</string>
+    <string name="settings_button_save_spreadsheets">Save as Spreadsheets</string>
+    <string name="settings_button_send_email">Send as Email</string>
+    <string name="title_twibbon">Twibbon</string>
+    <string name="camera_image_description">Capture picture</string>
+    <string name="image_overview">Image Overview</string>
+    <string name="twibbon_overlay">twibbon overlay</string>
+    <string name="scan_image_picker_button">Pick Image</string>
+
+</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e6ca302655ca89b3c584bcebdefa3b5a52644477
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="Title">
+        <item name="android:textSize">20sp</item>
+        <item name="android:textStyle">bold</item>
+    </style>
+
+    <style name="Text">
+        <item name="android:textSize">16sp</item>
+    </style>
+
+    <style name="Detail">
+        <item name="android:textSize">10sp</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f1776cdc99f8db6413d29e9bc32f6ba427cc688a
--- /dev/null
+++ b/app/src/main/res/values/themes.xml
@@ -0,0 +1,16 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Base application theme. -->
+    <style name="Theme.BondoMan" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+        <!-- Primary brand color. -->
+        <item name="colorPrimary">@color/purple_500</item>
+        <item name="colorPrimaryVariant">@color/purple_700</item>
+        <item name="colorOnPrimary">@color/white</item>
+        <!-- Secondary brand color. -->
+        <item name="colorSecondary">@color/teal_200</item>
+        <item name="colorSecondaryVariant">@color/teal_700</item>
+        <item name="colorOnSecondary">@color/black</item>
+        <!-- Status bar color. -->
+        <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
+        <!-- Customize your theme here. -->
+    </style>
+</resources>
\ No newline at end of file
diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fa0f996d2c2a6bdd11f5371de4268c8389d6c720
--- /dev/null
+++ b/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+   Sample backup rules file; uncomment and customize as necessary.
+   See https://developer.android.com/guide/topics/data/autobackup
+   for details.
+   Note: This file is ignored for devices older that API 31
+   See https://developer.android.com/about/versions/12/backup-restore
+-->
+<full-backup-content>
+    <!--
+   <include domain="sharedpref" path="."/>
+   <exclude domain="sharedpref" path="device.xml"/>
+-->
+</full-backup-content>
\ No newline at end of file
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9ee9997b0b4726e57c27b2f7b21462b604ff8a88
--- /dev/null
+++ b/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+   Sample data extraction rules file; uncomment and customize as necessary.
+   See https://developer.android.com/about/versions/12/backup-restore#xml-changes
+   for details.
+-->
+<data-extraction-rules>
+    <cloud-backup>
+        <!-- TODO: Use <include> and <exclude> to control what is backed up.
+        <include .../>
+        <exclude .../>
+        -->
+    </cloud-backup>
+    <!--
+    <device-transfer>
+        <include .../>
+        <exclude .../>
+    </device-transfer>
+    -->
+</data-extraction-rules>
\ No newline at end of file
diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7581796d236252598cc3b49b2d0e38d0b5ceb7b8
--- /dev/null
+++ b/app/src/main/res/xml/provider_paths.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <cache-path
+        name="cache_path"
+        path="." />
+</paths>
\ No newline at end of file
diff --git a/app/src/test/java/com/example/bondoman/ExampleUnitTest.kt b/app/src/test/java/com/example/bondoman/ExampleUnitTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a6f826f1f5e9fc7d6a7db3ca07ce4af0ff53e201
--- /dev/null
+++ b/app/src/test/java/com/example/bondoman/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.example.bondoman
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+    @Test
+    fun addition_isCorrect() {
+        assertEquals(4, 2 + 2)
+    }
+}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000000000000000000000000000000000000..2513688c1cab24b573468b879c1e8c6ed1c8ac1c
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,17 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+    repositories {
+        google()
+    }
+    dependencies {
+        val nav_version = "2.7.7"
+        classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version")
+    }
+}
+
+plugins {
+    id("com.android.application") version "8.2.2" apply false
+    id("org.jetbrains.kotlin.android") version "1.9.0" apply false
+    id("com.android.library") version "8.1.2" apply false
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000000000000000000000000000000000000..3c5031eb7d63f785752b1914cc8692a453d1cc63
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,23 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000000000000000000000000000000..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000000000000000000000000000000000..e62a2ff80f5fdcbbf79ba5b81b7604edd3716dae
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Mar 12 16:28:48 WIB 2024
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000000000000000000000000000000000000..4f906e0c811fc9e230eb44819f509cd0627f2600
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=`expr $i + 1`
+    done
+    case $i in
+        0) set -- ;;
+        1) set -- "$args0" ;;
+        2) set -- "$args0" "$args1" ;;
+        3) set -- "$args0" "$args1" "$args2" ;;
+        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000000000000000000000000000000000000..107acd32c4e687021ef32db511e8a206129b88ec
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000000000000000000000000000000000000..43a027c2d2a7288761174c07174cbae0d752a968
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,20 @@
+pluginManagement {
+    repositories {
+        google()
+        mavenCentral()
+        gradlePluginPortal()
+    }
+
+}
+dependencyResolutionManagement {
+    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+    repositories {
+        google()
+        mavenCentral()
+        maven { url = uri("https://jitpack.io") }
+    }
+
+}
+
+rootProject.name = "BondoMan"
+include(":app")