From 94e7b5c825c8e8bd6c3c590f172ca4d8c775d525 Mon Sep 17 00:00:00 2001 From: RyanSC06 <cadanganryansc@gmail.com> Date: Sat, 30 Mar 2024 23:28:33 +0700 Subject: [PATCH] feat: transactions --- .idea/gradle.xml | 1 + .idea/vcs.xml | 6 + app/.idea/.gitignore | 3 + app/.idea/gradle.xml | 12 ++ app/.idea/migrations.xml | 10 ++ app/.idea/misc.xml | 10 ++ app/.idea/vcs.xml | 6 + app/build.gradle.kts | 5 + app/src/.idea/.gitignore | 3 + app/src/.idea/misc.xml | 6 + app/src/.idea/modules.xml | 11 ++ app/src/.idea/vcs.xml | 6 + .../myapplication/AddTransactionActivity.kt | 111 ++++++++++++++++++ .../com/example/myapplication/MainActivity.kt | 2 +- .../myapplication/dao/TransactionDao.kt | 22 ++++ .../database/TransactionDatabase.kt | 19 +++ .../entities/TransactionEntities.kt | 27 +++++ .../repository/TransactionRepository.kt | 12 ++ .../ui/transaction/TransactionsFragment.kt | 45 +++++++ .../res/layout/activity_transaction_list.xml | 11 ++ app/src/main/res/layout/item_transaction.xml | 38 ++++++ .../main/res/navigation/mobile_navigation.xml | 7 ++ gradle/wrapper/gradle-wrapper.properties | 4 +- 23 files changed, 374 insertions(+), 3 deletions(-) create mode 100644 .idea/vcs.xml create mode 100644 app/.idea/.gitignore create mode 100644 app/.idea/gradle.xml create mode 100644 app/.idea/migrations.xml create mode 100644 app/.idea/misc.xml create mode 100644 app/.idea/vcs.xml create mode 100644 app/src/.idea/.gitignore create mode 100644 app/src/.idea/misc.xml create mode 100644 app/src/.idea/modules.xml create mode 100644 app/src/.idea/vcs.xml create mode 100644 app/src/main/java/com/example/myapplication/AddTransactionActivity.kt create mode 100644 app/src/main/java/com/example/myapplication/dao/TransactionDao.kt create mode 100644 app/src/main/java/com/example/myapplication/database/TransactionDatabase.kt create mode 100644 app/src/main/java/com/example/myapplication/entities/TransactionEntities.kt create mode 100644 app/src/main/java/com/example/myapplication/repository/TransactionRepository.kt create mode 100644 app/src/main/java/com/example/myapplication/ui/transaction/TransactionsFragment.kt create mode 100644 app/src/main/res/layout/activity_transaction_list.xml create mode 100644 app/src/main/res/layout/item_transaction.xml diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 0897082..d12ae9e 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -15,5 +15,6 @@ <option name="resolveExternalAnnotations" value="false" /> </GradleProjectSettings> </option> + <option name="offlineMode" value="true" /> </component> </project> \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="" vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/app/.idea/.gitignore b/app/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/app/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/app/.idea/gradle.xml b/app/.idea/gradle.xml new file mode 100644 index 0000000..89935b5 --- /dev/null +++ b/app/.idea/gradle.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="GradleSettings"> + <option name="linkedExternalProjectsSettings"> + <GradleProjectSettings> + <option name="externalProjectPath" value="$PROJECT_DIR$" /> + <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" /> + <option name="resolveExternalAnnotations" value="false" /> + </GradleProjectSettings> + </option> + </component> +</project> \ No newline at end of file diff --git a/app/.idea/migrations.xml b/app/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/app/.idea/migrations.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectMigrations"> + <option name="MigrateToGradleLocalJavaHome"> + <set> + <option value="$PROJECT_DIR$" /> + </set> + </option> + </component> +</project> \ No newline at end of file diff --git a/app/.idea/misc.xml b/app/.idea/misc.xml new file mode 100644 index 0000000..3040d03 --- /dev/null +++ b/app/.idea/misc.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ExternalStorageConfigurationManager" enabled="true" /> + <component name="ProjectRootManager"> + <output url="file://$PROJECT_DIR$/build/classes" /> + </component> + <component name="ProjectType"> + <option name="id" value="Android" /> + </component> +</project> \ No newline at end of file diff --git a/app/.idea/vcs.xml b/app/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/app/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="$PROJECT_DIR$/.." vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 019d126..bfffbf2 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -54,4 +54,9 @@ dependencies { testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) + + implementation "androidx.room:room-runtime:2.4.0" + kapt "androidx.room:room-compiler:2.4.0" + implementation "androidx.room:room-ktx:2.4.0" + testImplementation "androidx.room:room-testing:2.4.0" } \ No newline at end of file diff --git a/app/src/.idea/.gitignore b/app/src/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/app/src/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/app/src/.idea/misc.xml b/app/src/.idea/misc.xml new file mode 100644 index 0000000..639900d --- /dev/null +++ b/app/src/.idea/misc.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectRootManager"> + <output url="file://$PROJECT_DIR$/out" /> + </component> +</project> \ No newline at end of file diff --git a/app/src/.idea/modules.xml b/app/src/.idea/modules.xml new file mode 100644 index 0000000..403a512 --- /dev/null +++ b/app/src/.idea/modules.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/androidTest/androidTest.iml" filepath="$PROJECT_DIR$/androidTest/androidTest.iml" /> + <module fileurl="file://$PROJECT_DIR$/main/main.iml" filepath="$PROJECT_DIR$/main/main.iml" /> + <module fileurl="file://$PROJECT_DIR$/.idea/src.iml" filepath="$PROJECT_DIR$/.idea/src.iml" /> + <module fileurl="file://$PROJECT_DIR$/test/test.iml" filepath="$PROJECT_DIR$/test/test.iml" /> + </modules> + </component> +</project> \ No newline at end of file diff --git a/app/src/.idea/vcs.xml b/app/src/.idea/vcs.xml new file mode 100644 index 0000000..b2bdec2 --- /dev/null +++ b/app/src/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="$PROJECT_DIR$/../.." vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/AddTransactionActivity.kt b/app/src/main/java/com/example/myapplication/AddTransactionActivity.kt new file mode 100644 index 0000000..293d674 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/AddTransactionActivity.kt @@ -0,0 +1,111 @@ +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.widget.Toast +import androidx.lifecycle.ViewModelProvider +import java.util.Date + + +class AddTransactionActivity : AppCompatActivity() { + private lateinit var titleEditText: EditText + private lateinit var nominalEditText: EditText + private lateinit var kategoriEditText: EditText + private lateinit var lokasiEditText: EditText + private lateinit var saveButton: Button + + private lateinit var transactionViewModel: TransactionViewModel + private lateinit var transactionRepository: TransactionRepository + + private var currentLocation: Location? = null + + companion object { + private const val LOCATION_PERMISSION_REQUEST_CODE = 123 + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_add_transaction) + + titleEditText = findViewById(R.id.editTextJudul) + nominalEditText = findViewById(R.id.editTextNominal) + kategoriEditText = findViewById(R.id.editTextKategori) + lokasiEditText = findViewById(R.id.editTextLokasi) + saveButton = findViewById(R.id.buttonSimpan) + + val transactionDao = TransactionDatabase.getInstance(this).transactionDao() + transactionRepository = TransactionRepository(transactionDao) + transactionViewModel = ViewModelProvider(this).get(TransactionViewModel::class.java) + transactionViewModel.initialize(transactionRepository) + + saveButton.setOnClickListener { saveTransaction() } + getLocation() + } + + private fun saveTransaction() { + val title = titleEditText.text.toString().trim() + val nominal = nominalEditText.text.toString().trim() + val kategori = kategoriEditText.text.toString().trim() + val lokasi = lokasiEditText.text.toString().trim() + val tanggal = Date() + + if (title.isEmpty() || nominal.isEmpty() || kategori.isEmpty() || lokasi.isEmpty()) { + Toast.makeText(this, "Isi semua atribut transaksi", Toast.LENGTH_SHORT).show() + return + } + + val transaction = TransactionEntity(title, nominal, kategori, lokasi, tanggal) + transactionViewModel.addTransaction(transaction) + Toast.makeText(this, "Transaksi berhasil ditambahkan", Toast.LENGTH_SHORT).show() + finish() + } + + + private fun saveTransaction() { + val title = titleEditText.text.toString().trim() + val nominal = nominalEditText.text.toString().trim() + val kategori = kategoriEditText.text.toString().trim() + val lokasi = lokasiEditText.text.toString().trim() + val tanggal = Date() + + if (title.isEmpty() || nominal.isEmpty() || kategori.isEmpty() || lokasi.isEmpty()) { + Toast.makeText(this, "Isi semua atribut transaksi", Toast.LENGTH_SHORT).show() + return + } + + val transaction = TransactionEntity(title = title, nominal = nominal, kategori = kategori, lokasi = lokasi, tanggal = tanggal) + val insertedTransactionId = transactionViewModel.addTransaction(transaction) + Toast.makeText(this, "Transaksi berhasil ditambahkan dengan ID $insertedTransactionId", Toast.LENGTH_SHORT).show() + finish() + } + + + @SuppressLint("MissingPermission") + private fun getLocation() { + if (LocationUtils.isLocationPermissionGranted(this)) { + LocationUtils.requestLocationUpdates(this) { location -> + currentLocation = location + lokasiEditText.setText("${location.latitude}, ${location.longitude}") + } + } else { + ActivityCompat.requestPermissions( + this, + arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), + LOCATION_PERMISSION_REQUEST_CODE + ) + } + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array<out String>, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + getLocation() + } else { + Toast.makeText(this, "Izin akses lokasi ditolak", Toast.LENGTH_SHORT).show() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/MainActivity.kt b/app/src/main/java/com/example/myapplication/MainActivity.kt index 4d6ef5d..d3fe50c 100644 --- a/app/src/main/java/com/example/myapplication/MainActivity.kt +++ b/app/src/main/java/com/example/myapplication/MainActivity.kt @@ -32,7 +32,7 @@ class MainActivity : AppCompatActivity() { // menu should be considered as top level destinations. val appBarConfiguration = AppBarConfiguration( setOf( - R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications + R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications, R.id.navigation_transactions ) ) setupActionBarWithNavController(navController, appBarConfiguration) diff --git a/app/src/main/java/com/example/myapplication/dao/TransactionDao.kt b/app/src/main/java/com/example/myapplication/dao/TransactionDao.kt new file mode 100644 index 0000000..2decc8c --- /dev/null +++ b/app/src/main/java/com/example/myapplication/dao/TransactionDao.kt @@ -0,0 +1,22 @@ +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import androidx.room.Delete + + +@Dao +interface TransactionDao { + @Insert + suspend fun insertTransaction(transaction: TransactionEntity): Long + + @Query("SELECT * FROM transactionentity") + fun getAllTransactions(): LiveData<List<TransactionEntity>> + + @Update + fun update(transaction: TransactionEntity) + + @Delete + fun delete(transaction: TransactionEntity) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/TransactionDatabase.kt b/app/src/main/java/com/example/myapplication/database/TransactionDatabase.kt new file mode 100644 index 0000000..7785998 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/database/TransactionDatabase.kt @@ -0,0 +1,19 @@ +@Database (entities = [TransactionEntity::class], version = 1) +abstract class TransactionDatabase : RoomDatabase() { + abstract fun transactionDao(): TransactionDao + + companion object { + @Volatile + private var instance: TransactionDatabase? = null + + fun getInstance (context: Context): TransactionDatabase { + return instance ?: synchronized(this) { + instance ?: Room.databaseBuilder( + context.applicationContext, + TransactionDatabase::class.java, + "transaction_database" + ).build().also { instance = it } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/entities/TransactionEntities.kt b/app/src/main/java/com/example/myapplication/entities/TransactionEntities.kt new file mode 100644 index 0000000..9455a4e --- /dev/null +++ b/app/src/main/java/com/example/myapplication/entities/TransactionEntities.kt @@ -0,0 +1,27 @@ +import java.util.Date +import androidx.room.Entity +import androidx.room.PrimaryKey +import androidx.room.ColumnInfo + + +@Entity(tableName = "transactionentity") +data class TransactionEntity( + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = "id") + val id: Int = 0, + + @ColumnInfo(name = "title") + val title: String, + + @ColumnInfo(name = "nominal") + val nominal: String, + + @ColumnInfo(name = "kategori") + val kategori: String, + + @ColumnInfo(name = "lokasi") + val lokasi: String, + + @ColumnInfo(name = "tanggal") + val tanggal: Date +) \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/repository/TransactionRepository.kt b/app/src/main/java/com/example/myapplication/repository/TransactionRepository.kt new file mode 100644 index 0000000..e8d6cd2 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/repository/TransactionRepository.kt @@ -0,0 +1,12 @@ +import androidx.lifecycle.LiveData +import androidx.room.Update +import androidx.room.Delete + + +class TransactionRepository(private val transactionDao: TransactionDao) { + val allTransactions: LiveData<List<TransactionEntity>> = transactionDao.getAllTransactions() + + suspend fun insertTransaction(transaction: TransactionEntity): Long { + return transactionDao.insertTransaction(transaction) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/ui/transaction/TransactionsFragment.kt b/app/src/main/java/com/example/myapplication/ui/transaction/TransactionsFragment.kt new file mode 100644 index 0000000..f3cd330 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/ui/transaction/TransactionsFragment.kt @@ -0,0 +1,45 @@ +package com.example.myapplication.ui.transactions + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.example.myapplication.R +import com.example.myapplication.data.Transaction +import com.example.myapplication.data.TransactionAdapter + +class TransactionsFragment : Fragment() { + + private lateinit var recyclerView: RecyclerView + private lateinit var transactionAdapter: TransactionAdapter + private val transactionList = mutableListOf<Transaction>() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val root = inflater.inflate(R.layout.fragment_transactions, container, false) + + recyclerView = root.findViewById(R.id.recyclerViewTransactions) + recyclerView.layoutManager = LinearLayoutManager(requireContext()) + transactionAdapter = TransactionAdapter(transactionList) + recyclerView.adapter = transactionAdapter + + return root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + // Simulate loading transactions from a data source + loadTransactions() + } + + private fun loadTransactions() { + transactionViewModel.allTransactions.observe(viewLifecycleOwner, { transactions -> + transactionList.clear() + transactionList.addAll(transactions.map { Transaction(it.title, it.nominal) }) + transactionAdapter.notifyDataSetChanged() + }) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_transaction_list.xml b/app/src/main/res/layout/activity_transaction_list.xml new file mode 100644 index 0000000..58a86db --- /dev/null +++ b/app/src/main/res/layout/activity_transaction_list.xml @@ -0,0 +1,11 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/recyclerViewTransactions" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + +</LinearLayout> \ 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 0000000..324f70a --- /dev/null +++ b/app/src/main/res/layout/item_transaction.xml @@ -0,0 +1,38 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="16dp"> + + <TextView + android:id="@+id/textViewDate" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16sp" + android:textStyle="bold" /> + + <TextView + android:id="@+id/textViewTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16sp" /> + + <TextView + android:id="@+id/textViewCategory" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" /> + + <TextView + android:id="@+id/textViewPrice" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" /> + + <TextView + android:id="@+id/textViewLocation" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" /> + +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index 9439eda..f34e15b 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -22,4 +22,11 @@ android:name="com.example.myapplication.ui.notifications.NotificationsFragment" android:label="@string/title_notifications" tools:layout="@layout/fragment_notifications" /> + + <fragment + android:id="@+id/navigation_transactions" + android:name="com.example.myapplication.ui.transactions.TransactionsFragment" + android:label="@string/title_transactions" + tools:layout="@layout/fragment_transactions" /> + </navigation> \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7c90f5c..0991321 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Mar 16 13:51:19 WIB 2024 +#Thu Mar 21 16:32:17 WIB 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -- GitLab