diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d714532975888e4121fa1752cdccf45b004eab91..4dd5ff7aea82efe33a729eefc3636fb98bb6e934 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,6 +38,10 @@ android:name=".AddTransactionActivity" android:exported="false" /> + <activity + android:name=".EditTransactionActivity" + android:exported="false" /> + <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" diff --git a/app/src/main/java/com/onionsquad/bondoman/EditTransactionActivity.kt b/app/src/main/java/com/onionsquad/bondoman/EditTransactionActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..5606ede65b8da631bc51b5024b1e7c5ff9ef8537 --- /dev/null +++ b/app/src/main/java/com/onionsquad/bondoman/EditTransactionActivity.kt @@ -0,0 +1,79 @@ +package com.onionsquad.bondoman + +import android.content.Intent +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.ViewModelProvider +import com.onionsquad.bondoman.databinding.ActivityEditTransactionBinding +import com.onionsquad.bondoman.repository.TransactionRepository +import com.onionsquad.bondoman.room.TransactionCategory +import com.onionsquad.bondoman.room.TransactionDatabase +import com.onionsquad.bondoman.room.TransactionEntity +import com.onionsquad.bondoman.ui.transaction.TransactionViewModel +import com.onionsquad.bondoman.ui.transaction.TransactionViewModelFactory +import java.util.Date + +class EditTransactionActivity : AppCompatActivity() { + private lateinit var binding: ActivityEditTransactionBinding + private val database by lazy { TransactionDatabase.getInstance(this) } + private val repository by lazy { TransactionRepository(database.transactionDao()) } + private lateinit var viewModel: TransactionViewModel + + private var transactionId: Int = -1 + private var transactionDate: Date = Date() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityEditTransactionBinding.inflate(layoutInflater) + setContentView(binding.root) + + val factory = TransactionViewModelFactory(repository) + viewModel = ViewModelProvider(this, factory)[TransactionViewModel::class.java] + + transactionId = intent.getIntExtra("transactionId", -1) + if (transactionId != -1) { + viewModel.getTransactionById(transactionId).observe(this) { transaction -> + if (transaction != null) { + binding.titleEditText.setText(transaction.title) + binding.amountEditText.setText(transaction.amount.toString()) + when (transaction.category) { + TransactionCategory.INCOME -> binding.incomeRadioButton.isChecked = true + TransactionCategory.OUTCOME -> binding.outcomeRadioButton.isChecked = true + else -> { + + } + } + binding.locationEditText.setText(transaction.location) + transactionDate = transaction.date + } + } + } + + binding.saveButton.setOnClickListener { + val title = binding.titleEditText.text.toString() + val amount = binding.amountEditText.text.toString().toDoubleOrNull() ?: 0.0 + val selectedCategoryId = binding.categoryRadioGroup.checkedRadioButtonId + val category = when (selectedCategoryId) { + R.id.incomeRadioButton -> TransactionCategory.INCOME + R.id.outcomeRadioButton -> TransactionCategory.OUTCOME + else -> TransactionCategory.OUTCOME + } + val location = binding.locationEditText.text.toString() + + val updatedTransaction = TransactionEntity( + id = transactionId, + title = title, + amount = amount, + category = category, + date = transactionDate, + location = location + ) + + viewModel.updateTransaction(updatedTransaction) + + Intent(this@EditTransactionActivity, MainActivity::class.java).also { + startActivity(it) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/onionsquad/bondoman/repository/TransactionRepository.kt b/app/src/main/java/com/onionsquad/bondoman/repository/TransactionRepository.kt index 6d31c4ab7d591d2cb2a82a8c5af4fcd690fbeee8..f284dfb547caa702a574fab60db157775cb6c4f9 100644 --- a/app/src/main/java/com/onionsquad/bondoman/repository/TransactionRepository.kt +++ b/app/src/main/java/com/onionsquad/bondoman/repository/TransactionRepository.kt @@ -17,4 +17,8 @@ class TransactionRepository(private val transactionDao: TransactionDao) { suspend fun deleteTransaction(transaction: TransactionEntity) { transactionDao.deleteTransaction(transaction) } + + fun getTransactionById(id: Int): LiveData<TransactionEntity> { + return transactionDao.getTransactionById(id) + } } \ No newline at end of file diff --git a/app/src/main/java/com/onionsquad/bondoman/room/TransactionDao.kt b/app/src/main/java/com/onionsquad/bondoman/room/TransactionDao.kt index 35e64cc4e012610fb9739a15fc9e6a5132680f45..5eeeedb3bfe998598bd1cf3d29b2171e661ee551 100644 --- a/app/src/main/java/com/onionsquad/bondoman/room/TransactionDao.kt +++ b/app/src/main/java/com/onionsquad/bondoman/room/TransactionDao.kt @@ -16,4 +16,7 @@ interface TransactionDao { @Delete suspend fun deleteTransaction(transaction: TransactionEntity) + + @Query("SELECT * FROM transactions WHERE id = :id") + fun getTransactionById(id: Int): LiveData<TransactionEntity> } \ No newline at end of file diff --git a/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionAdapter.kt b/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..b39a926ac4c347ae5a3e08f8d1763d99622c9af9 --- /dev/null +++ b/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionAdapter.kt @@ -0,0 +1,53 @@ +package com.onionsquad.bondoman.ui.transaction + +import android.content.Intent +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.onionsquad.bondoman.EditTransactionActivity +import com.onionsquad.bondoman.databinding.TransactionCardBinding +import com.onionsquad.bondoman.room.TransactionEntity + +class TransactionAdapter( + private val viewModel: TransactionViewModel, + private var transactionList: List<TransactionEntity> = emptyList() +) : RecyclerView.Adapter<TransactionAdapter.ViewHolder>() { + + inner class ViewHolder(private val binding: TransactionCardBinding) : RecyclerView.ViewHolder(binding.root) { + fun bind(transaction: TransactionEntity) { + binding.titleTextView.text = transaction.title + binding.amountTextView.text = "IDR ".plus(transaction.amount) + binding.categoryTextView.text = transaction.category.toString() + binding.dateTextView.text = transaction.date.toString() + binding.locationTextView.text = transaction.location + + binding.deleteButton.setOnClickListener { + viewModel.deleteTransaction(transaction) + } + binding.editButton.setOnClickListener { + val intent = Intent(binding.root.context, EditTransactionActivity::class.java) + intent.putExtra("transactionId", transaction.id) + binding.root.context.startActivity(intent) + } + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + val binding = TransactionCardBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val transaction = transactionList[position] + holder.bind(transaction) + } + + override fun getItemCount(): Int { + return transactionList.size + } + + fun setTransactionList(transactionList: List<TransactionEntity>) { + this.transactionList = transactionList + notifyDataSetChanged() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionFragment.kt b/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionFragment.kt index 4ff1ccc32f50abe95a0e0e74e85e2595bf8997e6..7af3c31b9b13576aaee461b52885ff04ae8710f7 100644 --- a/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionFragment.kt +++ b/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionFragment.kt @@ -7,38 +7,60 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.LinearLayoutManager import com.onionsquad.bondoman.AddTransactionActivity import com.onionsquad.bondoman.databinding.FragmentTransactionBinding import com.onionsquad.bondoman.repository.TransactionRepository import com.onionsquad.bondoman.room.TransactionDatabase class TransactionFragment : Fragment() { - private var _binding: FragmentTransactionBinding? = null - - // This property is only valid between onCreateView and - // onDestroyView. private val binding get() = _binding!! private val database by lazy { TransactionDatabase.getInstance(requireContext().applicationContext) } private val repository by lazy { TransactionRepository(database.transactionDao()) } + private lateinit var transactionViewModel: TransactionViewModel + private lateinit var transactionAdapter: TransactionAdapter override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? ): View { + _binding = FragmentTransactionBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setupViewModel() + setupRecyclerView() + setupClickListeners() + } + + private fun setupViewModel() { val factory = TransactionViewModelFactory(repository) - val transactionViewModel = ViewModelProvider(this, factory)[TransactionViewModel::class.java] + transactionViewModel = ViewModelProvider(this, factory)[TransactionViewModel::class.java] - _binding = FragmentTransactionBinding.inflate(inflater, container, false) + transactionViewModel.listTransactions.observe(viewLifecycleOwner) { transactionList -> + transactionAdapter.setTransactionList(transactionList) + } + } + + private fun setupRecyclerView() { + transactionAdapter = TransactionAdapter(transactionViewModel) + binding.transactionList.apply { + layoutManager = LinearLayoutManager(context) + adapter = transactionAdapter + } + } - binding.button.setOnClickListener { + private fun setupClickListeners() { + binding.addTransactionButton.setOnClickListener { val intent = Intent(activity, AddTransactionActivity::class.java) startActivity(intent) } - - return binding.root } override fun onDestroyView() { diff --git a/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionViewModel.kt b/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionViewModel.kt index cf96283f3289be47bfd3205f7e6faa0ac4467748..e34a11eb51d9dcf434b68e8089586dab0911a7a2 100644 --- a/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionViewModel.kt +++ b/app/src/main/java/com/onionsquad/bondoman/ui/transaction/TransactionViewModel.kt @@ -21,4 +21,8 @@ class TransactionViewModel(private val repository : TransactionRepository) : Vie fun deleteTransaction(transaction: TransactionEntity) = viewModelScope.launch { repository.deleteTransaction(transaction) } + + fun getTransactionById(id: Int): LiveData<TransactionEntity> { + return repository.getTransactionById(id) + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/card_background.xml b/app/src/main/res/drawable/card_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..9687bcb49124a23fdc528e7bcfc09da50ff742f0 --- /dev/null +++ b/app/src/main/res/drawable/card_background.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="#FFBB86FC" /> + <corners android:radius="8dp" /> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add.xml b/app/src/main/res/drawable/ic_add.xml new file mode 100644 index 0000000000000000000000000000000000000000..8140012280ccf471ae3e11e44058ebfb0a4fa6e4 --- /dev/null +++ b/app/src/main/res/drawable/ic_add.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="@android:color/white" + android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/> +</vector> \ No newline at end of file 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..618a75853cf62efae9734d66d4e3cdd2396fd080 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <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> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_edit.xml b/app/src/main/res/drawable/ic_edit.xml new file mode 100644 index 0000000000000000000000000000000000000000..3ea930d89592aa614ceb09cefe6ee449dc55f1da --- /dev/null +++ b/app/src/main/res/drawable/ic_edit.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <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> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_edit_transaction.xml b/app/src/main/res/layout/activity_edit_transaction.xml new file mode 100644 index 0000000000000000000000000000000000000000..8b23b5075a31acd86cc49cdd54a73576f5b219d7 --- /dev/null +++ b/app/src/main/res/layout/activity_edit_transaction.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:padding="16dp"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Edit Transaksi" + android:textSize="24sp" + android:textStyle="bold" /> + + <EditText + android:id="@+id/titleEditText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:hint="Judul" + android:inputType="text" /> + + <EditText + android:id="@+id/amountEditText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:hint="Nominal" + android:inputType="numberDecimal" /> + + <RadioGroup + android:id="@+id/categoryRadioGroup" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:orientation="horizontal"> + + <RadioButton + android:id="@+id/incomeRadioButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Pemasukan" /> + + <RadioButton + android:id="@+id/outcomeRadioButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Pengeluaran" /> + </RadioGroup> + + <EditText + android:id="@+id/locationEditText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:hint="Lokasi" + android:inputType="text" /> + + <Button + android:id="@+id/saveButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:text="Simpan" /> + +</LinearLayout> \ 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 index 26af3dd3316b3d39d8d4a93547724bcb95a87311..f6bdd20ec3dd92fcc5f68be9c57f83d2e5c47bb5 100644 --- a/app/src/main/res/layout/fragment_transaction.xml +++ b/app/src/main/res/layout/fragment_transaction.xml @@ -6,15 +6,25 @@ android:layout_height="match_parent" tools:context=".ui.transaction.TransactionFragment"> - <Button - android:id="@+id/button" + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/transactionList" + android:layout_width="0dp" + android:layout_height="0dp" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:listitem="@layout/transaction_card" /> + + <com.google.android.material.floatingactionbutton.FloatingActionButton + android:id="@+id/addTransactionButton" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="Button" - android:visibility="visible" + android:layout_margin="16dp" + android:src="@drawable/ic_add" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:backgroundTint="#FF6200EE" /> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/transaction_card.xml b/app/src/main/res/layout/transaction_card.xml new file mode 100644 index 0000000000000000000000000000000000000000..0460ea905c63c1d90b81d1d5b48e56429e263623 --- /dev/null +++ b/app/src/main/res/layout/transaction_card.xml @@ -0,0 +1,96 @@ +<?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:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="10dp" + app:cardCornerRadius="8dp" + app:cardElevation="4dp"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@drawable/card_background" + android:padding="16dp"> + + <TextView + android:id="@+id/dateTextView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16sp" + android:textStyle="bold" + android:textColor="#FFFFFF" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="29/02/2024" /> + + <TextView + android:id="@+id/categoryTextView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:textSize="14sp" + android:textColor="#FFFFFF" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/dateTextView" + tools:text="Pembelian" /> + + <TextView + android:id="@+id/titleTextView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="18sp" + android:textStyle="bold" + android:textColor="#FFFFFF" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/categoryTextView" + tools:text="Transaction Name" /> + + <TextView + android:id="@+id/amountTextView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16sp" + android:textColor="#FFFFFF" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="IDR 15.000" /> + + <TextView + android:id="@+id/locationTextView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="14sp" + android:textColor="#FFFFFF" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/amountTextView" + tools:text="Location" /> + + <ImageButton + android:id="@+id/editButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:layout_marginEnd="10dp" + android:background="?attr/selectableItemBackgroundBorderless" + android:src="@drawable/ic_edit" + app:layout_constraintEnd_toStartOf="@+id/deleteButton" + app:layout_constraintTop_toBottomOf="@id/titleTextView" + app:tint="#FFFFFF" /> + + <ImageButton + android:id="@+id/deleteButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp" + android:background="?attr/selectableItemBackgroundBorderless" + android:src="@drawable/ic_delete" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/titleTextView" + app:tint="#FFFFFF" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + +</androidx.cardview.widget.CardView> \ No newline at end of file