diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f76e101450e4b114b58e9cd4cc0d705bba06bd2f..97df0d454b9b034529bdf75b0b9226d26f70b721 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,7 +8,6 @@ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/> - xmlns:tools="http://schemas.android.com/tools"> <uses-feature android:name="android.hardware.camera.any" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" @@ -27,7 +26,7 @@ android:theme="@style/Theme.Tubespbd" tools:targetApi="31"> <activity - android:name=".LoginActivity" + android:name=".SplashActivity" android:exported="true" android:label="@string/app_name"> <intent-filter> @@ -36,8 +35,11 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> - <activity android:name=".MainActivity"/> <activity android:name=".ui.NoConnectionActivity"/> + <activity + android:name=".LoginActivity" /> + <activity + android:name=".MainActivity" /> <service android:name=".auth.TokenExpirationService" android:foregroundServiceType="dataSync" @@ -51,7 +53,6 @@ <meta-data android:name="preloaded_fonts" android:resource="@array/preloaded_fonts" /> - </application> </manifest> \ No newline at end of file diff --git a/app/src/main/java/com/example/tubespbd/App.kt b/app/src/main/java/com/example/tubespbd/App.kt index 47818e63c958bfae80eda19bed54b66c82ffebd2..af33f0faf4e1e47b2e97e4df32fd52df4dc9fee0 100644 --- a/app/src/main/java/com/example/tubespbd/App.kt +++ b/app/src/main/java/com/example/tubespbd/App.kt @@ -1,10 +1,16 @@ package com.example.tubespbd + import android.app.Application import androidx.room.Room import com.example.tubespbd.database.AppDatabase +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import com.example.tubespbd.database.* class App : Application() { lateinit var appDatabase: AppDatabase + private val transactionRepository by lazy { TransactionRepository(appDatabase.transactionDao()) } override fun onCreate() { super.onCreate() @@ -15,5 +21,39 @@ class App : Application() { ) .fallbackToDestructiveMigration() .build() + + // Test database operations + performDatabaseOperations() + } + + private fun performDatabaseOperations() = CoroutineScope(Dispatchers.IO).launch { + val locationString = "testing" + + // Insert a transaction + val transaction = Transaction(title = "Mi Ayam", category = "Pembelian", amount = 15000f, location = locationString, tanggal = "2023-02-01 12:00:00") + val transactionId = transactionRepository.insertTransaction(transaction) + println("Inserted transaction with ID: $transactionId") + + // Retrieve all transactions + val transactions = transactionRepository.getAllTransactions() + transactions.forEach { transaction -> + println("Transaction ID: ${transaction.id}, Title: ${transaction.title}, Category: ${transaction.category}, Amount: ${transaction.amount}, Location: ${transaction.location}, Date: ${transaction.tanggal}") + } + + // Update last transaction + val lastTransaction = transactions.last() + val updatedTransaction = lastTransaction.copy(title = "Nasi Goreng") + transactionRepository.updateTransaction(updatedTransaction) + println("Updated transaction with ID: ${updatedTransaction.id}") + + // Retrieve all transactions after update + val afterUpdateTransactions = transactionRepository.getAllTransactions() + afterUpdateTransactions.forEach { transaction -> + println("Transaction ID: ${transaction.id}, Title: ${transaction.title}, Category: ${transaction.category}, Amount: ${transaction.amount}, Location: ${transaction.location}, Date: ${transaction.tanggal}") + } + + // Delete the last transaction + transactionRepository.deleteTransaction(lastTransaction) + println("Deleted transaction with ID: ${lastTransaction.id}") } } \ No newline at end of file diff --git a/app/src/main/java/com/example/tubespbd/HistoryActivity.kt b/app/src/main/java/com/example/tubespbd/HistoryActivity.kt index 5b84e8b1e3f324cccb4c798db2591121379d4efa..842357298cae09560bf74c3176cb2a4b15ee3330 100644 --- a/app/src/main/java/com/example/tubespbd/HistoryActivity.kt +++ b/app/src/main/java/com/example/tubespbd/HistoryActivity.kt @@ -7,6 +7,6 @@ class HistoryActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.fragment_history) - // Initialize your UI here if needed + } } diff --git a/app/src/main/java/com/example/tubespbd/MainActivity.kt b/app/src/main/java/com/example/tubespbd/MainActivity.kt index 31e6f5ff994751171ebdcf5379a46f40c0de52ff..3f5aa48be05e09334b52e246513cefb1a4d88b3e 100644 --- a/app/src/main/java/com/example/tubespbd/MainActivity.kt +++ b/app/src/main/java/com/example/tubespbd/MainActivity.kt @@ -30,20 +30,10 @@ class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding private lateinit var locationManager: LocationManager private lateinit var transactionManager: TransactionManager -// private lateinit var appDatabase: AppDatabase -// private val transactionRepository by lazy { TransactionRepository(appDatabase.transactionDao()) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - // Room Database -// appDatabase = Room.databaseBuilder( -// applicationContext, -// AppDatabase::class.java, "transaction.db" -// ) -// .fallbackToDestructiveMigration() -// .build() - // Routing binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) @@ -85,57 +75,22 @@ class MainActivity : AppCompatActivity() { val serviceIntent = Intent(applicationContext, TokenExpirationService::class.java) applicationContext.startService(serviceIntent) - val backButton = findViewById<Button>(R.id.back_login) - backButton.setOnClickListener { +// val backButton = findViewById<Button>(R.id.back_login) +// backButton.setOnClickListener { +// +// } - } } private fun initializeAfterPermissionsGranted() { // Initialize TransactionManager after permissions are granted transactionManager = TransactionManager(this, locationManager) - -// performDatabaseOperations() } private fun getLocationString(): String { return transactionManager.getLocationString() } -// private fun performDatabaseOperations() = CoroutineScope(Dispatchers.IO).launch { -// val locationString = if (hasLocationPermissions() && isLocationEnabled()) { -// getLocationString() -// } else { -// "none" -// } -// -// // Insert a transaction -// val transaction = Transaction(title = "Mi Ayam", category = "Pembelian", amount = 15000f, location = locationString, tanggal = "2023-02-01 12:00:00") -// val transactionId = transactionRepository.insertTransaction(transaction) -// println("Inserted transaction with ID: $transactionId") -// -// // Retrieve all transactions -// val transactions = transactionRepository.getAllTransactions() -// transactions.forEach { transaction -> -// println("Transaction ID: ${transaction.id}, Title: ${transaction.title}, Category: ${transaction.category}, Amount: ${transaction.amount}, Location: ${transaction.location}, Date: ${transaction.tanggal}") -// } -// -// // Update last transaction -// val lastTransaction = transactions.last() -// val updatedTransaction = lastTransaction.copy(title = "Nasi Goreng") -// transactionRepository.updateTransaction(updatedTransaction) -// println("Updated transaction with ID: ${updatedTransaction.id}") -// -// // Retrieve all transactions after update -// val afterUpdateTransactions = transactionRepository.getAllTransactions() -// afterUpdateTransactions.forEach { transaction -> -// println("Transaction ID: ${transaction.id}, Title: ${transaction.title}, Category: ${transaction.category}, Amount: ${transaction.amount}, Location: ${transaction.location}, Date: ${transaction.tanggal}") -// } -// -// // Delete the last transaction -// transactionRepository.deleteTransaction(lastTransaction) -// println("Deleted transaction with ID: ${lastTransaction.id}") -// } private fun isLocationEnabled(): Boolean { return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) diff --git a/app/src/main/java/com/example/tubespbd/TransactionManager.kt b/app/src/main/java/com/example/tubespbd/TransactionManager.kt index a277a87eb1574333cd9c99b8803ab4e186bd29f8..18626a0de15f79914d7f7caa602dd8ef3f261036 100644 --- a/app/src/main/java/com/example/tubespbd/TransactionManager.kt +++ b/app/src/main/java/com/example/tubespbd/TransactionManager.kt @@ -10,7 +10,6 @@ class TransactionManager(private val context: Context, private val locationManag fun getLocationString(): String { if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - // Permission is not granted return "Location Permissions not granted" } val location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER) diff --git a/app/src/main/java/com/example/tubespbd/database/TransactionAdapter.kt b/app/src/main/java/com/example/tubespbd/database/TransactionAdapter.kt index fa9e2d4b14e56cd3209c604697a65f8686f091ff..bb2344efd94e1696a635e51b4acb3746c875b4f5 100644 --- a/app/src/main/java/com/example/tubespbd/database/TransactionAdapter.kt +++ b/app/src/main/java/com/example/tubespbd/database/TransactionAdapter.kt @@ -4,11 +4,12 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView +import androidx.navigation.findNavController import androidx.recyclerview.widget.RecyclerView import com.example.tubespbd.R import com.example.tubespbd.database.Transaction -class TransactionAdapter(private val transactions: List<Transaction>) : +class TransactionAdapter(private val transactions: List<Transaction>, private val itemClickListener: (Transaction) -> Unit) : RecyclerView.Adapter<TransactionAdapter.TransactionViewHolder>() { inner class TransactionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { @@ -32,7 +33,10 @@ class TransactionAdapter(private val transactions: List<Transaction>) : holder.amountTextView.text = currentItem.amount.toString() holder.dateTextView.text = currentItem.tanggal holder.locationTextView.text = currentItem.location + holder.itemView.setOnClickListener { + itemClickListener(currentItem) + } } override fun getItemCount() = transactions.size -} +} \ No newline at end of file diff --git a/app/src/main/java/com/example/tubespbd/database/TransactionDAO.kt b/app/src/main/java/com/example/tubespbd/database/TransactionDAO.kt index cdf159e3fdebc7e88e6b2a45d83cca0558407818..6588d7b879951a68d4c47da0aa4e26ddd1a48c09 100644 --- a/app/src/main/java/com/example/tubespbd/database/TransactionDAO.kt +++ b/app/src/main/java/com/example/tubespbd/database/TransactionDAO.kt @@ -12,6 +12,9 @@ interface TransactionDao { @Query("SELECT * FROM transactions") fun getAllTransactions(): List<Transaction> + @Query("SELECT * FROM transactions WHERE id = :transactionId") + fun getTransactionById(transactionId: Int): Transaction + @Insert fun insertTransaction(transaction: Transaction): Long @@ -20,6 +23,7 @@ interface TransactionDao { @Update fun updateTransaction(transaction: Transaction): Int - @Query("SELECT * FROM transactions") - fun getAllTransactionsLiveData(): LiveData<List<Transaction>> + + @Query("DELETE FROM transactions WHERE id = :transactionId") + fun deleteTransactionById(transactionId: Int): Int } \ No newline at end of file diff --git a/app/src/main/java/com/example/tubespbd/database/TransactionRepository.kt b/app/src/main/java/com/example/tubespbd/database/TransactionRepository.kt index 63c664837a9bdb5f784fc5a6567e3e899c578674..9e8e23dd0237d7b8b200357a917398394a8b11a7 100644 --- a/app/src/main/java/com/example/tubespbd/database/TransactionRepository.kt +++ b/app/src/main/java/com/example/tubespbd/database/TransactionRepository.kt @@ -20,11 +20,11 @@ class TransactionRepository(private val transactionDao: TransactionDao) { return transactionDao.updateTransaction(transaction) } - fun getAllTransactionsLiveData(): LiveData<List<Transaction>> { - return transactionDao.getAllTransactionsLiveData() + suspend fun getTransactionById(transactionId: Int): Transaction? { + return transactionDao.getTransactionById(transactionId) } - suspend fun refreshTransactions() { - // Perform data refresh operations if needed + suspend fun deleteTransactionById(transactionId: Int) { + transactionDao.deleteTransactionById(transactionId) } } \ No newline at end of file diff --git a/app/src/main/java/com/example/tubespbd/ui/home/AddTransactionFragment.kt b/app/src/main/java/com/example/tubespbd/ui/home/AddTransactionFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..401076c326e58fd20b8bdc73b862d2a5a30b2903 --- /dev/null +++ b/app/src/main/java/com/example/tubespbd/ui/home/AddTransactionFragment.kt @@ -0,0 +1,141 @@ +// AddTransactionFragment.kt +package com.example.tubespbd.ui.home + +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.tubespbd.R +import com.example.tubespbd.database.Transaction +import com.example.tubespbd.database.TransactionAdapter +import com.example.tubespbd.databinding.FragmentAddTransactionBinding // Updated import +import com.example.tubespbd.databinding.FragmentHomeBinding +import java.util.Date +import android.Manifest +import android.content.Context +import android.content.pm.PackageManager +import androidx.core.content.ContextCompat +import com.example.tubespbd.TransactionManager +import android.location.LocationManager +import androidx.core.location.LocationManagerCompat.isLocationEnabled +import com.example.tubespbd.App +import com.example.tubespbd.database.TransactionRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import androidx.navigation.fragment.findNavController +class AddTransactionFragment : Fragment() { + + private var _binding: FragmentAddTransactionBinding? = null // Updated binding class + private val binding get() = _binding!! + private lateinit var transactionAdapter: TransactionAdapter + private val transactions = mutableListOf<Transaction>() + private lateinit var locationManager: LocationManager + private lateinit var transactionRepository: TransactionRepository + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentAddTransactionBinding.inflate(inflater, container, false) // Updated layout inflation + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + locationManager = requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager + transactionAdapter = TransactionAdapter(transactions) { transaction -> + } + + val appDatabase = (requireActivity().application as App).appDatabase + val transactionDao = appDatabase.transactionDao() + transactionRepository = TransactionRepository(transactionDao) + + binding.addTransactionButton.setOnClickListener { + addTransaction() + navigateBack() + } + + binding.backButton.setOnClickListener { + navigateBack() + } + + CoroutineScope(Dispatchers.IO).launch { + getAllTransactions() + } + } + private fun navigateBack() { + findNavController().navigateUp() + } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + private fun addTransaction() { + val title = binding.titleEditText.text.toString() + val category = binding.categoryEditText.text.toString() + val amountStr = binding.amountEditText.text.toString() + val amount = if (amountStr.isNotEmpty()) amountStr.toFloat() else 0f + + val locationString = getLocationString() + val currentDate = Date() + + val newTransaction = Transaction( + title = title, + category = category, + amount = amount, + location = locationString, + tanggal = currentDate.toString() + ) + + CoroutineScope(Dispatchers.IO).launch { + transactionRepository.insertTransaction(newTransaction) + getAllTransactions() + } + + binding.titleEditText.text.clear() + binding.categoryEditText.text.clear() + binding.amountEditText.text.clear() + } + + private suspend fun getAllTransactions() { + transactions.clear() + transactions.addAll(transactionRepository.getAllTransactions()) + withContext(Dispatchers.Main) { + transactionAdapter.notifyDataSetChanged() + } + } + + private fun getLocationString(): String { + return when { + hasLocationPermissions() && isLocationEnabled() -> { + val transactionManager = TransactionManager(requireContext(), locationManager) + transactionManager.getLocationString() + } + !hasLocationPermissions() -> { + "Location denied" + } + else -> { + "Location unavailable" + } + } + } + + private fun hasLocationPermissions(): Boolean { + return ContextCompat.checkSelfPermission( + requireContext(), + Manifest.permission.ACCESS_FINE_LOCATION + ) == PackageManager.PERMISSION_GRANTED + } + + private fun isLocationEnabled(): Boolean { + return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled( + LocationManager.NETWORK_PROVIDER + ) + } +} diff --git a/app/src/main/java/com/example/tubespbd/ui/home/EditTransactionFragment.kt b/app/src/main/java/com/example/tubespbd/ui/home/EditTransactionFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..acfbc154280d815c473bd4c2e13dcaedf23bbc09 --- /dev/null +++ b/app/src/main/java/com/example/tubespbd/ui/home/EditTransactionFragment.kt @@ -0,0 +1,133 @@ +package com.example.tubespbd.ui.home + +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.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import com.example.tubespbd.App +import com.example.tubespbd.R +import com.example.tubespbd.database.TransactionRepository +import com.example.tubespbd.databinding.FragmentAddTransactionBinding +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import com.example.tubespbd.database.Transaction +import java.util.Date + + +class EditTransactionFragment : Fragment() { + + private lateinit var transactionRepository: TransactionRepository + private var _binding: FragmentAddTransactionBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentAddTransactionBinding.inflate(inflater, container, false) + + val appDatabase = (requireActivity().application as App).appDatabase + val transactionDao = appDatabase.transactionDao() + transactionRepository = TransactionRepository(transactionDao) + + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val transactionId = arguments?.getInt("transactionId") + + if (transactionId != null) { + CoroutineScope(Dispatchers.IO).launch { + val transaction = transactionRepository.getTransactionById(transactionId) + withContext(Dispatchers.Main) { + binding.titleEditText.setText(transaction?.title) + binding.categoryEditText.setText(transaction?.category) + binding.amountEditText.setText(transaction?.amount.toString()) + } + } + } + + // Buat Delete button visible, karena pake fragment yang sama dengan addTransaction + binding.deleteTransactionButton.visibility = View.VISIBLE + + // Delete Button + binding.deleteTransactionButton.setOnClickListener { + val transactionId = arguments?.getInt("transactionId") + if (transactionId != null) { + CoroutineScope(Dispatchers.IO).launch { + transactionRepository.deleteTransactionById(transactionId) + withContext(Dispatchers.Main) { + navigateBack() + } + } + } + } + + // Reuse button addTransaction untuk Update + binding.addTransactionButton.setOnClickListener { + val transactionId = arguments?.getInt("transactionId") + Log.d("EditTransactionFragment", "Transaction ID: $transactionId") + if (transactionId != null) { + CoroutineScope(Dispatchers.IO).launch { + updateTransaction(transactionId) + withContext(Dispatchers.Main) { + Toast.makeText(context, "Transaksi Berhasil Di-update", Toast.LENGTH_SHORT).show() + navigateBack() + } + } + } + } + + binding.backButton.setOnClickListener { + navigateBack() + } + + val appDatabase = (requireActivity().application as App).appDatabase + val transactionDao = appDatabase.transactionDao() + transactionRepository = TransactionRepository(transactionDao) + } + + private fun navigateBack() { + findNavController().navigateUp() + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + private fun updateTransaction(transactionId: Int) { + val title = binding.titleEditText.text.toString() + val category = binding.categoryEditText.text.toString() + val amount = binding.amountEditText.text.toString().toFloat() + val locationString = "Location unavailable" // HARDCODE TEMP + val currentDate = Date() + + val updatedTransaction = Transaction( + id = transactionId, + title = title, + category = category, + amount = amount, + location = locationString, + tanggal = currentDate.toString() + ) + + CoroutineScope(Dispatchers.IO).launch { + transactionRepository.updateTransaction(updatedTransaction) + withContext(Dispatchers.Main) { + binding.titleEditText.text.clear() + binding.categoryEditText.text.clear() + binding.amountEditText.text.clear() + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/tubespbd/ui/home/HomeFragment.kt b/app/src/main/java/com/example/tubespbd/ui/home/HomeFragment.kt index b7f0860f83ec582e542d1db96fe7d1eadc43a83c..473c45034a4d532b5f6be171b3a7b607f56f2ce8 100644 --- a/app/src/main/java/com/example/tubespbd/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/example/tubespbd/ui/home/HomeFragment.kt @@ -19,6 +19,9 @@ import android.content.pm.PackageManager import androidx.core.content.ContextCompat import com.example.tubespbd.TransactionManager import android.location.LocationManager +import android.util.Log +import android.widget.Toast +import androidx.navigation.fragment.findNavController import com.example.tubespbd.App import com.example.tubespbd.database.TransactionRepository import kotlinx.coroutines.CoroutineScope @@ -28,6 +31,8 @@ import kotlinx.coroutines.withContext class HomeFragment : Fragment() { + private var isEditButtonClicked = false + private var _binding: FragmentHistoryBinding? = null private val binding get() = _binding!! private lateinit var transactionAdapter: TransactionAdapter @@ -46,18 +51,26 @@ class HomeFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) locationManager = requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager - transactionAdapter = TransactionAdapter(transactions) + transactionAdapter = TransactionAdapter(transactions) { transaction -> + if (isEditButtonClicked) { + Log.d("HomeFragment", "Selected Transaction ID: ${transaction.id}") + navigateToEditTransactionFragment(transaction.id) + isEditButtonClicked = false + } + } binding.transactionRecyclerView.adapter = transactionAdapter - // Get the AppDatabase instance from the App class val appDatabase = (requireActivity().application as App).appDatabase - // Get the TransactionDao from the AppDatabase val transactionDao = appDatabase.transactionDao() - // Create the TransactionRepository transactionRepository = TransactionRepository(transactionDao) binding.addTransactionButton.setOnClickListener { - addTransaction() + navigateToAddTransactionFragment() + } + + binding.editTransactionButton.setOnClickListener { + isEditButtonClicked = true + Toast.makeText(context, "Please select a transaction to edit.", Toast.LENGTH_SHORT).show() } CoroutineScope(Dispatchers.IO).launch { @@ -70,34 +83,19 @@ class HomeFragment : Fragment() { _binding = null } - private fun addTransaction() { - val title = binding.titleEditText.text.toString() - val category = binding.categoryEditText.text.toString() - val amountStr = binding.amountEditText.text.toString() - val amount = if (amountStr.isNotEmpty()) amountStr.toFloat() else 0f - - // Get location and date - val locationString = getLocationString() - val currentDate = Date() - - val newTransaction = Transaction( - title = title, - category = category, - amount = amount, - location = locationString, - tanggal = currentDate.toString() // Assign current datetime to tanggal - ) - - // Insert the new transaction into the database - CoroutineScope(Dispatchers.IO).launch { - transactionRepository.insertTransaction(newTransaction) - getAllTransactions() + private fun navigateToAddTransactionFragment() { + findNavController().navigate(R.id.action_homeFragment_to_addTransactionFragment) + } +// private fun navigateToEditTransactionFragment() { +// // Use Navigation Component to navigate to EditTransactionFragment +// findNavController().navigate(R.id.action_homeFragment_to_editTransactionFragment) +// } + + private fun navigateToEditTransactionFragment(transactionId: Int) { + val bundle = Bundle().apply { + putInt("transactionId", transactionId) } - - // Clear input fields - binding.titleEditText.text.clear() - binding.categoryEditText.text.clear() - binding.amountEditText.text.clear() + findNavController().navigate(R.id.action_homeFragment_to_editTransactionFragment, bundle) } private suspend fun getAllTransactions() { @@ -111,23 +109,19 @@ class HomeFragment : Fragment() { private fun getLocationString(): String { return when { hasLocationPermissions() && isLocationEnabled() -> { - // Get location if permission is granted and location is enabled val transactionManager = TransactionManager(requireContext(), locationManager) transactionManager.getLocationString() } !hasLocationPermissions() -> { - // Location permissions not granted "Location denied" } else -> { - // Location not available "Location unavailable" } } } - private fun hasLocationPermissions(): Boolean { return ContextCompat.checkSelfPermission( requireContext(), diff --git a/app/src/main/java/com/example/tubespbd/ui/home/HomeViewModel.kt b/app/src/main/java/com/example/tubespbd/ui/home/HomeViewModel.kt index c64f075bb804332d7bf43b0c6a299bb293b42748..56d522a5f309e918b49965d2fefb69314e7abfea 100644 --- a/app/src/main/java/com/example/tubespbd/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/example/tubespbd/ui/home/HomeViewModel.kt @@ -12,9 +12,4 @@ class HomeViewModel(private val transactionRepository: TransactionRepository) : val transactions: List<Transaction> = transactionRepository.getAllTransactions() - init { - viewModelScope.launch { - transactionRepository.refreshTransactions() - } - } } diff --git a/app/src/main/java/com/example/tubespbd/ui/settings/SettingsFragment.kt b/app/src/main/java/com/example/tubespbd/ui/settings/SettingsFragment.kt index 40c87f424a070daf9ee41745433b0b7c64f87f8d..976e3230bae5548024a1ae20521abd663cb0c1b6 100644 --- a/app/src/main/java/com/example/tubespbd/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/example/tubespbd/ui/settings/SettingsFragment.kt @@ -1,12 +1,17 @@ package com.example.tubespbd.ui.settings +import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Button import android.widget.TextView import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider +import com.example.tubespbd.LoginActivity +import com.example.tubespbd.R +import com.example.tubespbd.auth.LoginService import com.example.tubespbd.databinding.FragmentSettingsBinding import com.example.tubespbd.email.MailService @@ -41,6 +46,18 @@ class SettingsFragment : Fragment() { return root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val logoutButton = view.findViewById<Button>(R.id.logout_button) + logoutButton.setOnClickListener { + val loginService = LoginService() + loginService.logout() + val intent = Intent(activity, LoginActivity::class.java) + startActivity(intent) + } + } + override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index e64cb62d7973e20a65d5e92fb8812ffca7743f69..1bd67ec2a0be48fb5b675108ea87e0ccab4339aa 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -26,17 +26,11 @@ android:layout_height="match_parent" 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="1.0" app:navGraph="@navigation/mobile_navigation" /> - <Button - android:id="@+id/back_login" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="Button" - tools:layout_editor_absoluteX="159dp" - tools:layout_editor_absoluteY="167dp" /> - </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_add_transaction.xml b/app/src/main/res/layout/fragment_add_transaction.xml new file mode 100644 index 0000000000000000000000000000000000000000..a4254a8992687cd4c7a7f7d758027daf7161393d --- /dev/null +++ b/app/src/main/res/layout/fragment_add_transaction.xml @@ -0,0 +1,78 @@ +<?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"> + + <Button + android:id="@+id/backButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="44dp" + android:text="Back" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <EditText + android:id="@+id/titleEditText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="132dp" + android:hint="Title" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <EditText + android:id="@+id/categoryEditText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:hint="Category" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/titleEditText" /> + + <EditText + android:id="@+id/amountEditText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:hint="Amount" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/categoryEditText" /> + + <Button + android:id="@+id/addTransactionButton" + android:layout_width="350dp" + android:layout_height="wrap_content" + android:layout_marginTop="316dp" + android:text="Simpan" + android:backgroundTint="@color/subtle_green" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.491" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/amountEditText" /> + + <Button + android:id="@+id/deleteTransactionButton" + android:layout_width="350dp" + android:layout_height="wrap_content" + android:layout_marginTop="10dp" + android:text="Hapus" + android:backgroundTint="@color/red" + android:visibility="gone" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.491" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/addTransactionButton" /> + + +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/app/src/main/res/layout/fragment_history.xml b/app/src/main/res/layout/fragment_history.xml index 263d7f393fa5418e7dfa22118b1d4fb0ba64cb2b..331096fe4b8d7f8c52af37bb13ad851fb6c91564 100644 --- a/app/src/main/res/layout/fragment_history.xml +++ b/app/src/main/res/layout/fragment_history.xml @@ -6,48 +6,57 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - <EditText - android:id="@+id/titleEditText" - android:layout_width="match_parent" + <!-- Title TextView --> + <TextView + android:id="@+id/titleTextView" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:hint="Title" + android:text="TRANSAKSI" + android:textSize="24sp" + android:textStyle="bold" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintEnd_toEndOf="parent" + android:padding="16dp"/> - <EditText - android:id="@+id/categoryEditText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:hint="Category" - app:layout_constraintTop_toBottomOf="@id/titleEditText" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + <!-- Button to go to add transaction page --> - <EditText - android:id="@+id/amountEditText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:hint="Amount" - app:layout_constraintTop_toBottomOf="@id/categoryEditText" + <!-- RecyclerView for displaying transactions --> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/transactionRecyclerView" + android:layout_width="393dp" + android:layout_height="525dp" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintTop_toBottomOf="@id/titleTextView" + app:layout_constraintVertical_bias="0.04" + tools:ignore="MissingConstraints" + tools:listitem="@layout/transaction_item" /> <Button android:id="@+id/addTransactionButton" + android:layout_width="43dp" + android:layout_height="44dp" + android:layout_marginTop="12dp" + android:text="+" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.888" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/transactionRecyclerView" /> + + <Button + android:id="@+id/editTransactionButton" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="Add Transaction" - app:layout_constraintTop_toBottomOf="@id/amountEditText" + android:layout_height="44dp" + android:layout_marginTop="12dp" + android:text="Edit" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.122" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" /> + app:layout_constraintTop_toBottomOf="@id/transactionRecyclerView" /> - <androidx.recyclerview.widget.RecyclerView - android:id="@+id/transactionRecyclerView" - android:layout_width="match_parent" - android:layout_height="0dp" - app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:layout_constraintTop_toBottomOf="@id/addTransactionButton" - app:layout_constraintBottom_toBottomOf="parent" - tools:listitem="@layout/transaction_item" /> -</androidx.constraintlayout.widget.ConstraintLayout> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/transaction_item.xml b/app/src/main/res/layout/transaction_item.xml index 20a501a190130b2f7643fd5f0a2f7dfaa6e8dcb1..a87afdfb2b59490eeb091832507bceeec9a450c9 100644 --- a/app/src/main/res/layout/transaction_item.xml +++ b/app/src/main/res/layout/transaction_item.xml @@ -2,35 +2,66 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical"> + android:orientation="horizontal" + android:paddingLeft="40dp" + android:paddingRight="40dp"> - <TextView - android:id="@+id/titleTextView" - android:layout_width="wrap_content" + <!-- Left side container --> + <LinearLayout + android:layout_width="0dp" android:layout_height="wrap_content" - android:text="Title" /> + android:layout_weight="1" + android:orientation="vertical"> - <TextView - android:id="@+id/categoryTextView" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="Category" /> + <TextView + android:id="@+id/titleTextView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Title" + android:textColor="#000000" + android:textSize="20sp" + android:textStyle="bold" /> - <TextView - android:id="@+id/amountTextView" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="Amount" /> + <TextView + android:id="@+id/categoryTextView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Category" /> - <TextView - android:id="@+id/dateTextView" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="Date" /> - <TextView - android:id="@+id/locationTextView" - android:layout_width="wrap_content" + </LinearLayout> + + <!-- Right side container --> + <LinearLayout + android:layout_width="0dp" android:layout_height="wrap_content" - android:text="Location" /> + android:layout_weight="1" + android:gravity="end" + android:orientation="vertical"> + + <TextView + android:id="@+id/amountTextView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="end" + android:text="Amount" + android:textColor="#1E1B1B" /> + + <TextView + android:id="@+id/dateTextView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="end" + android:text="Date" + android:textColor="#8F8D8D" /> + + <TextView + android:id="@+id/locationTextView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="end" + android:text="Location" + android:textColor="#8F8D8D" /> + + </LinearLayout> </LinearLayout> diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index 6bb0f455a8c6ccb19e5752e000e55b0a3afb0987..02d89e9fb9318de38bca82b92e57eb47f46f181b 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -3,7 +3,7 @@ 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_dashboard"> + app:startDestination="@id/navigation_dashboard"> <fragment android:id="@+id/navigation_home" @@ -28,4 +28,27 @@ android:name="com.example.tubespbd.ui.settings.SettingsFragment" android:label="@string/title_settings" tools:layout="@layout/fragment_settings" /> -</navigation> \ No newline at end of file + + <action + android:id="@+id/action_homeFragment_to_addTransactionFragment" + app:destination="@id/addTransactionFragment" /> + + <fragment + android:id="@+id/addTransactionFragment" + android:name="com.example.tubespbd.ui.home.AddTransactionFragment" + android:label="Add Transaction" + tools:layout="@layout/fragment_add_transaction" /> + + <action + android:id="@+id/action_homeFragment_to_editTransactionFragment" + app:destination="@id/editTransactionFragment"> + <argument + android:name="transactionId" + app:argType="integer" /> + </action> + <fragment + android:id="@+id/editTransactionFragment" + android:name="com.example.tubespbd.ui.home.EditTransactionFragment" + android:label="EditTransactionFragment" /> + +</navigation> diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index bfc3a369266ce8ff9d07c26b018fb822dd501365..ca61dbaecad7d2feca38847cc4630c1cabfeccf2 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -10,4 +10,5 @@ <color name="border">#D9D9D9</color> <color name="primary">#3F6D5C</color> <color name="red">#B70000</color> + <color name="subtle_green">#4CAF50</color> </resources> \ No newline at end of file